Skip to content

Commit

Permalink
Checkbox button debounce (#774)
Browse files Browse the repository at this point in the history
This fixes: #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>
  • Loading branch information
clement-roblot and ArthurSonzogni authored Nov 11, 2023
1 parent e8589dd commit c31aecf
Show file tree
Hide file tree
Showing 14 changed files with 81 additions and 18 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions include/ftxui/component/mouse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ struct Mouse {
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::None;

Expand All @@ -37,6 +42,9 @@ struct Mouse {
// Coordinates:
int x = 0;
int y = 0;

// Previous mouse event, if any.
Mouse* previous = nullptr;
};

} // namespace ftxui
Expand Down
1 change: 1 addition & 0 deletions include/ftxui/component/screen_interactive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class ScreenInteractive : public Screen {

bool frame_valid_ = false;

Mouse latest_mouse_event_;
friend class Loop;

public:
Expand Down
3 changes: 1 addition & 2 deletions src/ftxui/component/button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions src/ftxui/component/checkbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions src/ftxui/component/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
6 changes: 2 additions & 4 deletions src/ftxui/component/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}
Expand Down
36 changes: 36 additions & 0 deletions src/ftxui/component/mouse.cpp
Original file line number Diff line number Diff line change
@@ -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
3 changes: 1 addition & 2 deletions src/ftxui/component/radiobox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
3 changes: 1 addition & 2 deletions src/ftxui/component/resizable_split.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions src/ftxui/component/screen_interactive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
3 changes: 1 addition & 2 deletions src/ftxui/component/slider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
3 changes: 1 addition & 2 deletions src/ftxui/component/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit c31aecf

Please sign in to comment.