diff options
author | crupest <crupest@outlook.com> | 2021-03-24 19:14:19 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-03-24 19:14:19 +0800 |
commit | 7f15a1ff9a2007e119798053083a0a87d042990a (patch) | |
tree | cb35c01a7eaee867376d959b96c9bbd15df939e5 /src/ui/helper/ClickDetector.cpp | |
parent | 74956951ee663012df0c3fe4ebe29799cb2f7732 (diff) | |
parent | 7703063a5816b089483e78ccd74bb9902ccfbea8 (diff) | |
download | cru-7f15a1ff9a2007e119798053083a0a87d042990a.tar.gz cru-7f15a1ff9a2007e119798053083a0a87d042990a.tar.bz2 cru-7f15a1ff9a2007e119798053083a0a87d042990a.zip |
Merge branch 'master' of https://github.com/crupest/CruUI
Diffstat (limited to 'src/ui/helper/ClickDetector.cpp')
-rw-r--r-- | src/ui/helper/ClickDetector.cpp | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/ui/helper/ClickDetector.cpp b/src/ui/helper/ClickDetector.cpp new file mode 100644 index 00000000..309685d3 --- /dev/null +++ b/src/ui/helper/ClickDetector.cpp @@ -0,0 +1,134 @@ +#include "cru/ui/helper/ClickDetector.hpp" + +#include "cru/common/Logger.hpp" +#include "cru/ui/DebugFlags.hpp" + +#include <optional> + +namespace cru::ui::helper { +ClickDetector::ClickDetector(controls::Control* control) { + Expects(control); + control_ = control; + + event_rovoker_guards_.push_back( + EventRevokerGuard(control->MouseEnterEvent()->Direct()->AddHandler( + [this](event::MouseEventArgs&) { + if (this->enable_) { + if (this->state_ == ClickState::PressInactive) { + if ((this->button_ & this->trigger_button_)) { + this->SetState(ClickState::Press); + } + } else { + this->SetState(ClickState::Hover); + } + } + }))); + + event_rovoker_guards_.push_back( + EventRevokerGuard(control->MouseLeaveEvent()->Direct()->AddHandler( + [this](event::MouseEventArgs&) { + if (this->enable_) { + if (this->state_ == ClickState::Press) { + if ((this->button_ & this->trigger_button_)) { + this->SetState(ClickState::PressInactive); + } + } else { + this->SetState(ClickState::None); + } + } + }))); + + event_rovoker_guards_.push_back( + EventRevokerGuard(control->MouseDownEvent()->Direct()->AddHandler( + [this](event::MouseButtonEventArgs& args) { + const auto button = args.GetButton(); + if (this->enable_ && (button & this->trigger_button_) && + this->state_ == ClickState::Hover) { + if (!this->control_->CaptureMouse()) { + if constexpr (debug_flags::click_detector) { + log::TagDebug(log_tag, + u"Failed to capture mouse when begin click."); + } + return; + } + this->down_point_ = args.GetPoint(); + this->button_ = button; + this->SetState(ClickState::Press); + } + }))); + + event_rovoker_guards_.push_back( + EventRevokerGuard(control->MouseUpEvent()->Direct()->AddHandler( + [this](event::MouseButtonEventArgs& args) { + const auto button = args.GetButton(); + if (this->enable_ && (button & this->trigger_button_) && + button == button_) { + if (this->state_ == ClickState::Press) { + this->SetState(ClickState::Hover); + this->event_.Raise(ClickEventArgs{this->control_, + this->down_point_, + args.GetPoint(), button}); + this->control_->ReleaseMouse(); + } else if (this->state_ == ClickState::PressInactive) { + this->SetState(ClickState::None); + this->control_->ReleaseMouse(); + } + } + }))); +} // namespace cru::ui + +void ClickDetector::SetEnabled(bool enable) { + if (enable == enable_) { + return; + } + + enable_ = enable; + if (enable) { + SetState(control_->IsMouseOver() ? ClickState::Hover : ClickState::None); + } else { + if (state_ == ClickState::Press || state_ == ClickState::PressInactive) { + SetState(ClickState::None); + control_->ReleaseMouse(); + } else if (state_ == ClickState::Hover) { + SetState(ClickState::None); + } + } +} + +void ClickDetector::SetTriggerButton(MouseButton trigger_button) { + if (trigger_button == trigger_button_) { + return; + } + + trigger_button_ = trigger_button; + if ((state_ == ClickState::Press || state_ == ClickState::PressInactive) && + !(button_ & trigger_button)) { + SetState(control_->IsMouseOver() ? ClickState::Hover : ClickState::None); + control_->ReleaseMouse(); + } +} + +void ClickDetector::SetState(ClickState state) { + if constexpr (debug_flags::click_detector) { + auto to_string = [](ClickState state) -> std::u16string_view { + switch (state) { + case ClickState::None: + return u"None"; + case ClickState::Hover: + return u"Hover"; + case ClickState::Press: + return u"Press"; + case ClickState::PressInactive: + return u"PressInvactive"; + default: + UnreachableCode(); + } + }; + log::TagDebug(log_tag, u"Click state changed, new state: {}.", + to_string(state)); + } + + state_ = state; + state_change_event_.Raise(state); +} +} // namespace cru::ui::helper |