mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-06-27 10:11:12 +08:00
Mouse transition support
This commit is contained in:
parent
7f26b823ff
commit
4bf4c36519
20
CHANGELOG.md
20
CHANGELOG.md
@ -7,6 +7,26 @@ current (development)
|
||||
### Component
|
||||
- Feature: Add support for `Input`'s insert mode. Add `InputOption::insert`
|
||||
option. Added by @mingsheng13.
|
||||
- Feature/Bugfix/Breaking change: `Mouse transition`:
|
||||
This fixes: https://github.com/ArthurSonzogni/FTXUI/issues/773
|
||||
Dragging the mouse with the left button pressed now avoids activating multiple
|
||||
checkboxes.
|
||||
|
||||
Add support for detecting mouse press transition. Added:
|
||||
```cpp
|
||||
// The previous mouse event.
|
||||
Mouse Mouse::previous;
|
||||
|
||||
// Return whether the mouse transitionned from:
|
||||
// released to pressed => IsPressed()
|
||||
// pressed to pressed => IsHeld()
|
||||
// pressed to released => IsReleased()
|
||||
bool Mouse::IsPressed(Button button) const;
|
||||
bool Mouse::IsHeld(Button button) const;
|
||||
bool Mouse::IsReleased(Button button) const;
|
||||
```
|
||||
A couple of components are now activated when the mouse is pressed,
|
||||
as opposed to released.
|
||||
- Bugfix: `Input` `onchange` was not called on backspace or delete key.
|
||||
Fixed by @chrysante in chrysante in PR #776.
|
||||
|
||||
|
@ -123,6 +123,7 @@ add_library(component
|
||||
src/ftxui/component/maybe.cpp
|
||||
src/ftxui/component/menu.cpp
|
||||
src/ftxui/component/modal.cpp
|
||||
src/ftxui/component/mouse.cpp
|
||||
src/ftxui/component/radiobox.cpp
|
||||
src/ftxui/component/radiobox.cpp
|
||||
src/ftxui/component/renderer.cpp
|
||||
|
@ -23,6 +23,11 @@ struct Mouse {
|
||||
Pressed = 1,
|
||||
};
|
||||
|
||||
// Utility function to check the variations of the mouse state.
|
||||
bool IsPressed(Button button = Left) const;
|
||||
bool IsHeld(Button button = Left) const;
|
||||
bool IsReleased(Button button = Left) const;
|
||||
|
||||
// Button
|
||||
Button button = Button::None;
|
||||
|
||||
@ -37,6 +42,9 @@ struct Mouse {
|
||||
// Coordinates:
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
// Previous mouse event, if any.
|
||||
Mouse* previous = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
@ -112,6 +112,7 @@ class ScreenInteractive : public Screen {
|
||||
|
||||
bool frame_valid_ = false;
|
||||
|
||||
Mouse latest_mouse_event_;
|
||||
friend class Loop;
|
||||
|
||||
public:
|
||||
|
@ -124,8 +124,7 @@ class ButtonBase : public ComponentBase, public ButtonOption {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse().button == Mouse::Left &&
|
||||
event.mouse().motion == Mouse::Pressed) {
|
||||
if (event.mouse().IsPressed()) {
|
||||
TakeFocus();
|
||||
OnClick();
|
||||
return true;
|
||||
|
@ -69,8 +69,7 @@ class CheckboxBase : public ComponentBase, public CheckboxOption {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse().button == Mouse::Left &&
|
||||
event.mouse().motion == Mouse::Pressed) {
|
||||
if (event.mouse().IsPressed()) {
|
||||
*checked = !*checked;
|
||||
on_change();
|
||||
return true;
|
||||
|
@ -466,8 +466,7 @@ class InputBase : public ComponentBase, public InputOption {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse().button != Mouse::Left ||
|
||||
event.mouse().motion != Mouse::Pressed) {
|
||||
if (!event.mouse().IsPressed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -318,8 +318,7 @@ class MenuBase : public ComponentBase, public MenuOption {
|
||||
|
||||
TakeFocus();
|
||||
focused_entry() = i;
|
||||
if (event.mouse().button == Mouse::Left &&
|
||||
event.mouse().motion == Mouse::Released) {
|
||||
if (event.mouse().IsPressed()) {
|
||||
if (selected() != i) {
|
||||
selected() = i;
|
||||
selected_previous_ = selected();
|
||||
@ -683,8 +682,7 @@ Component MenuEntry(MenuEntryOption option) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse().button == Mouse::Left &&
|
||||
event.mouse().motion == Mouse::Released) {
|
||||
if (event.mouse().IsPressed()) {
|
||||
TakeFocus();
|
||||
return true;
|
||||
}
|
||||
|
39
src/ftxui/component/mouse.cpp
Normal file
39
src/ftxui/component/mouse.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2023 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
|
||||
#include "ftxui/component/mouse.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
namespace {
|
||||
bool IsDown(const Mouse& mouse, Mouse::Button button) {
|
||||
return mouse.button == button && mouse.motion == Mouse::Pressed;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
/// Return whether the mouse transitionned from released to pressed.
|
||||
/// This is useful to detect a click.
|
||||
/// @arg button The button to check.
|
||||
bool Mouse::IsPressed(Button button) const {
|
||||
return IsDown(*this, button) &&
|
||||
(!previous || !IsDown(*previous, button));
|
||||
}
|
||||
|
||||
/// Return whether the mouse is currently held.
|
||||
/// This is useful to detect a drag.
|
||||
/// @arg button The button to check.
|
||||
bool Mouse::IsHeld(Button button) const {
|
||||
return IsDown(*this, button) && previous && IsDown(*previous, button);
|
||||
}
|
||||
|
||||
/// Return whether the mouse transitionned from pressed to released.
|
||||
/// This is useful to detect a click.
|
||||
/// @arg button The button to check.
|
||||
bool Mouse::IsReleased(Button button) const {
|
||||
return !IsDown(*this, button) &&
|
||||
(previous && IsDown(*previous, button));
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
@ -123,8 +123,7 @@ class RadioboxBase : public ComponentBase, public RadioboxOption {
|
||||
|
||||
TakeFocus();
|
||||
focused_entry() = i;
|
||||
if (event.mouse().button == Mouse::Left &&
|
||||
event.mouse().motion == Mouse::Released) {
|
||||
if (event.mouse().IsPressed()) {
|
||||
if (selected() != i) {
|
||||
selected() = i;
|
||||
on_change();
|
||||
|
@ -42,8 +42,7 @@ class ResizableSplitBase : public ComponentBase {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.mouse().button == Mouse::Left &&
|
||||
event.mouse().motion == Mouse::Pressed &&
|
||||
if (event.mouse().IsPressed() &&
|
||||
separator_box_.Contain(event.mouse().x, event.mouse().y) &&
|
||||
!captured_mouse_) {
|
||||
captured_mouse_ = CaptureMouse(event);
|
||||
|
@ -689,11 +689,17 @@ void ScreenInteractive::HandleTask(Component component, Task& task) {
|
||||
if (arg.is_mouse()) {
|
||||
arg.mouse().x -= cursor_x_;
|
||||
arg.mouse().y -= cursor_y_;
|
||||
arg.mouse().previous = &latest_mouse_event_;
|
||||
}
|
||||
|
||||
arg.screen_ = this;
|
||||
component->OnEvent(arg);
|
||||
frame_valid_ = false;
|
||||
|
||||
if (arg.is_mouse()) {
|
||||
latest_mouse_event_ = arg.mouse();
|
||||
latest_mouse_event_.previous = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -174,8 +174,7 @@ class SliderBase : public ComponentBase {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.mouse().button != Mouse::Left ||
|
||||
event.mouse().motion != Mouse::Pressed) {
|
||||
if (!event.mouse().IsPressed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -225,8 +225,7 @@ class WindowImpl : public ComponentBase, public WindowOptions {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.mouse().button != Mouse::Left ||
|
||||
event.mouse().motion != Mouse::Pressed) {
|
||||
if (!event.mouse().IsPressed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user