mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-22 18:59:59 +08:00
Checkbox button debounce (#774)
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. Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
This commit is contained in:
parent
e8589dd533
commit
c31aecf2ed
20
CHANGELOG.md
20
CHANGELOG.md
@ -7,6 +7,26 @@ current (development)
|
|||||||
### Component
|
### Component
|
||||||
- Feature: Add support for `Input`'s insert mode. Add `InputOption::insert`
|
- Feature: Add support for `Input`'s insert mode. Add `InputOption::insert`
|
||||||
option. Added by @mingsheng13.
|
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.
|
- Bugfix: `Input` `onchange` was not called on backspace or delete key.
|
||||||
Fixed by @chrysante in chrysante in PR #776.
|
Fixed by @chrysante in chrysante in PR #776.
|
||||||
|
|
||||||
|
@ -123,6 +123,7 @@ add_library(component
|
|||||||
src/ftxui/component/maybe.cpp
|
src/ftxui/component/maybe.cpp
|
||||||
src/ftxui/component/menu.cpp
|
src/ftxui/component/menu.cpp
|
||||||
src/ftxui/component/modal.cpp
|
src/ftxui/component/modal.cpp
|
||||||
|
src/ftxui/component/mouse.cpp
|
||||||
src/ftxui/component/radiobox.cpp
|
src/ftxui/component/radiobox.cpp
|
||||||
src/ftxui/component/radiobox.cpp
|
src/ftxui/component/radiobox.cpp
|
||||||
src/ftxui/component/renderer.cpp
|
src/ftxui/component/renderer.cpp
|
||||||
|
@ -23,6 +23,11 @@ struct Mouse {
|
|||||||
Pressed = 1,
|
Pressed = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Utility function to check the variations of the mouse state.
|
||||||
|
bool IsPressed(Button btn = Left) const; // Released => Pressed.
|
||||||
|
bool IsHeld(Button btn = Left) const; // Pressed => Pressed.
|
||||||
|
bool IsReleased(Button btn = Left) const; // Pressed => Released.
|
||||||
|
|
||||||
// Button
|
// Button
|
||||||
Button button = Button::None;
|
Button button = Button::None;
|
||||||
|
|
||||||
@ -37,6 +42,9 @@ struct Mouse {
|
|||||||
// Coordinates:
|
// Coordinates:
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
|
|
||||||
|
// Previous mouse event, if any.
|
||||||
|
Mouse* previous = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
@ -112,6 +112,7 @@ class ScreenInteractive : public Screen {
|
|||||||
|
|
||||||
bool frame_valid_ = false;
|
bool frame_valid_ = false;
|
||||||
|
|
||||||
|
Mouse latest_mouse_event_;
|
||||||
friend class Loop;
|
friend class Loop;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -124,8 +124,7 @@ class ButtonBase : public ComponentBase, public ButtonOption {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.mouse().button == Mouse::Left &&
|
if (event.mouse().IsPressed()) {
|
||||||
event.mouse().motion == Mouse::Pressed) {
|
|
||||||
TakeFocus();
|
TakeFocus();
|
||||||
OnClick();
|
OnClick();
|
||||||
return true;
|
return true;
|
||||||
|
@ -69,8 +69,7 @@ class CheckboxBase : public ComponentBase, public CheckboxOption {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.mouse().button == Mouse::Left &&
|
if (event.mouse().IsPressed()) {
|
||||||
event.mouse().motion == Mouse::Pressed) {
|
|
||||||
*checked = !*checked;
|
*checked = !*checked;
|
||||||
on_change();
|
on_change();
|
||||||
return true;
|
return true;
|
||||||
|
@ -466,8 +466,7 @@ class InputBase : public ComponentBase, public InputOption {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.mouse().button != Mouse::Left ||
|
if (!event.mouse().IsPressed()) {
|
||||||
event.mouse().motion != Mouse::Pressed) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,8 +318,7 @@ class MenuBase : public ComponentBase, public MenuOption {
|
|||||||
|
|
||||||
TakeFocus();
|
TakeFocus();
|
||||||
focused_entry() = i;
|
focused_entry() = i;
|
||||||
if (event.mouse().button == Mouse::Left &&
|
if (event.mouse().IsPressed()) {
|
||||||
event.mouse().motion == Mouse::Released) {
|
|
||||||
if (selected() != i) {
|
if (selected() != i) {
|
||||||
selected() = i;
|
selected() = i;
|
||||||
selected_previous_ = selected();
|
selected_previous_ = selected();
|
||||||
@ -683,8 +682,7 @@ Component MenuEntry(MenuEntryOption option) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.mouse().button == Mouse::Left &&
|
if (event.mouse().IsPressed()) {
|
||||||
event.mouse().motion == Mouse::Released) {
|
|
||||||
TakeFocus();
|
TakeFocus();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
36
src/ftxui/component/mouse.cpp
Normal file
36
src/ftxui/component/mouse.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 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 btn) {
|
||||||
|
return mouse->button == btn && mouse->motion == Mouse::Pressed;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
/// Return whether the mouse transitionned from released to pressed.
|
||||||
|
/// This is useful to detect a click.
|
||||||
|
/// @arg btn The button to check.
|
||||||
|
bool Mouse::IsPressed(Button btn) const {
|
||||||
|
return IsDown(this, btn) && (!previous || !IsDown(previous, btn));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return whether the mouse is currently held.
|
||||||
|
/// This is useful to detect a drag.
|
||||||
|
/// @arg btn The button to check.
|
||||||
|
bool Mouse::IsHeld(Button btn) const {
|
||||||
|
return IsDown(this, btn) && previous && IsDown(previous, btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return whether the mouse transitionned from pressed to released.
|
||||||
|
/// This is useful to detect a click.
|
||||||
|
/// @arg btn The button to check.
|
||||||
|
bool Mouse::IsReleased(Button btn) const {
|
||||||
|
return !IsDown(this, btn) && (previous && IsDown(previous, btn));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ftxui
|
@ -123,8 +123,7 @@ class RadioboxBase : public ComponentBase, public RadioboxOption {
|
|||||||
|
|
||||||
TakeFocus();
|
TakeFocus();
|
||||||
focused_entry() = i;
|
focused_entry() = i;
|
||||||
if (event.mouse().button == Mouse::Left &&
|
if (event.mouse().IsPressed()) {
|
||||||
event.mouse().motion == Mouse::Released) {
|
|
||||||
if (selected() != i) {
|
if (selected() != i) {
|
||||||
selected() = i;
|
selected() = i;
|
||||||
on_change();
|
on_change();
|
||||||
|
@ -42,8 +42,7 @@ class ResizableSplitBase : public ComponentBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.mouse().button == Mouse::Left &&
|
if (event.mouse().IsPressed() &&
|
||||||
event.mouse().motion == Mouse::Pressed &&
|
|
||||||
separator_box_.Contain(event.mouse().x, event.mouse().y) &&
|
separator_box_.Contain(event.mouse().x, event.mouse().y) &&
|
||||||
!captured_mouse_) {
|
!captured_mouse_) {
|
||||||
captured_mouse_ = CaptureMouse(event);
|
captured_mouse_ = CaptureMouse(event);
|
||||||
|
@ -689,11 +689,17 @@ void ScreenInteractive::HandleTask(Component component, Task& task) {
|
|||||||
if (arg.is_mouse()) {
|
if (arg.is_mouse()) {
|
||||||
arg.mouse().x -= cursor_x_;
|
arg.mouse().x -= cursor_x_;
|
||||||
arg.mouse().y -= cursor_y_;
|
arg.mouse().y -= cursor_y_;
|
||||||
|
arg.mouse().previous = &latest_mouse_event_;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg.screen_ = this;
|
arg.screen_ = this;
|
||||||
component->OnEvent(arg);
|
component->OnEvent(arg);
|
||||||
frame_valid_ = false;
|
frame_valid_ = false;
|
||||||
|
|
||||||
|
if (arg.is_mouse()) {
|
||||||
|
latest_mouse_event_ = arg.mouse();
|
||||||
|
latest_mouse_event_.previous = nullptr;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,8 +174,7 @@ class SliderBase : public ComponentBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.mouse().button != Mouse::Left ||
|
if (!event.mouse().IsPressed()) {
|
||||||
event.mouse().motion != Mouse::Pressed) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,8 +225,7 @@ class WindowImpl : public ComponentBase, public WindowOptions {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.mouse().button != Mouse::Left ||
|
if (!event.mouse().IsPressed()) {
|
||||||
event.mouse().motion != Mouse::Pressed) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user