aboutsummaryrefslogtreecommitdiff
path: root/src/ui/helper/ClickDetector.cpp
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-11-08 17:45:41 +0800
committercrupest <crupest@outlook.com>2020-11-08 17:45:41 +0800
commit2188845a7acffa653015a1000139ec0a9a3984bc (patch)
tree7e8ed6eca5868a0943af6fcad6467115f369987c /src/ui/helper/ClickDetector.cpp
parent93265251d56c91b05f160423077ce95339786f87 (diff)
downloadcru-2188845a7acffa653015a1000139ec0a9a3984bc.tar.gz
cru-2188845a7acffa653015a1000139ec0a9a3984bc.tar.bz2
cru-2188845a7acffa653015a1000139ec0a9a3984bc.zip
...
Diffstat (limited to 'src/ui/helper/ClickDetector.cpp')
-rw-r--r--src/ui/helper/ClickDetector.cpp131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/ui/helper/ClickDetector.cpp b/src/ui/helper/ClickDetector.cpp
new file mode 100644
index 00000000..4059f890
--- /dev/null
+++ b/src/ui/helper/ClickDetector.cpp
@@ -0,0 +1,131 @@
+#include "cru/ui/helper/ClickDetector.hpp"
+
+#include "cru/common/Logger.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()) {
+ 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) {
+#ifdef CRU_DEBUG
+ 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));
+#endif
+
+ state_ = state;
+ state_change_event_.Raise(state);
+}
+} // namespace cru::ui::helper