aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author杨宇千 <crupest@outlook.com>2019-08-11 22:08:49 +0800
committer杨宇千 <crupest@outlook.com>2019-08-11 22:08:49 +0800
commit99a322a6badf5b6d95be4944e80d92fc1cb2589e (patch)
tree4227de0cbb1fd73ef99de4bc57041492a0450208
parent3a8abe0aed9bb72ed64cbfe9f2f83a0db285e14c (diff)
downloadcru-99a322a6badf5b6d95be4944e80d92fc1cb2589e.tar.gz
cru-99a322a6badf5b6d95be4944e80d92fc1cb2589e.tar.bz2
cru-99a322a6badf5b6d95be4944e80d92fc1cb2589e.zip
...
-rw-r--r--.editorconfig13
-rw-r--r--include/cru/common/base.hpp16
-rw-r--r--include/cru/ui/click_detector.hpp87
-rw-r--r--include/cru/ui/control.hpp14
-rw-r--r--include/cru/win/graph/direct/text_layout.hpp4
-rw-r--r--src/ui/CMakeLists.txt2
-rw-r--r--src/ui/click_detector.cpp32
-rw-r--r--src/ui/control.cpp72
8 files changed, 167 insertions, 73 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..a957f24a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+root = true
+
+[*]
+end_of_line = crlf
+insert_final_newline = true
+
+[*.cpp]
+indent_style = space
+indent_size = 2
+
+[*.hpp]
+indent_style = space
+indent_size = 2
diff --git a/include/cru/common/base.hpp b/include/cru/common/base.hpp
index d72b97f2..920fe569 100644
--- a/include/cru/common/base.hpp
+++ b/include/cru/common/base.hpp
@@ -1,6 +1,22 @@
#pragma once
#include "pre_config.hpp"
+#define CRU_DEFAULT_COPY(classname) \
+ classname(const classname&) = default; \
+ classname& operator=(const classname&) = default;
+
+#define CRU_DEFAULT_MOVE(classname) \
+ classname(classname&&) = default; \
+ classname& operator=(classname&&) = default;
+
+#define CRU_DELETE_COPY(classname) \
+ classname(const classname&) = delete; \
+ classname& operator=(const classname&) = delete;
+
+#define CRU_DELETE_MOVE(classname) \
+ classname(classname&&) = delete; \
+ classname& operator=(classname&&) = delete;
+
namespace cru {
class Object {
public:
diff --git a/include/cru/ui/click_detector.hpp b/include/cru/ui/click_detector.hpp
new file mode 100644
index 00000000..e7d5e417
--- /dev/null
+++ b/include/cru/ui/click_detector.hpp
@@ -0,0 +1,87 @@
+#pragma once
+#include "control.hpp"
+
+#include <cstdlib>
+#include <forward_list>
+#include <optional>
+
+namespace cru::ui {
+class ClickEventArgs : Object {
+ public:
+ ClickEventArgs(Control* sender, const Point& down_point,
+ const Point& up_point, MouseButton button)
+ : sender_(sender),
+ down_point_(down_point),
+ up_point_(up_point),
+ button_(button) {}
+
+ CRU_DEFAULT_COPY(ClickEventArgs)
+ CRU_DEFAULT_MOVE(ClickEventArgs)
+
+ ~ClickEventArgs() override = default;
+
+ Control* GetSender() const { return sender_; }
+ Point GetDownPoint() const { return down_point_; }
+ Point GetUpPoint() const { return up_point_; }
+ MouseButton GetButton() const { return button_; }
+
+ private:
+ Control* sender_;
+ Point down_point_;
+ Point up_point_;
+ MouseButton button_;
+};
+
+class ClickDetector : public Object {
+ public:
+ explicit ClickDetector(Control* control);
+
+ ClickDetector(const ClickDetector& other) = delete;
+ ClickDetector& operator=(const ClickDetector& other) = delete;
+ ClickDetector(ClickDetector&& other) = delete;
+ ClickDetector& operator=(ClickDetector&& other) = delete;
+
+ ~ClickDetector() override = default;
+
+ Control* GetControl() const { return control_; }
+
+ // Return a union of buttons being pressed. Return 0 if no button is being
+ // pressed.
+ MouseButton IsPressing() const {
+ unsigned result = 0;
+ if (click_map_.left.has_value()) result |= MouseButton::Left;
+ if (click_map_.middle.has_value()) result |= MouseButton::Middle;
+ if (click_map_.right.has_value()) result |= MouseButton::Right;
+ return static_cast<MouseButton>(result);
+ }
+
+ IEvent<ClickEventArgs>* ClickEvent() { return &event_; }
+
+ private:
+ std::optional<Point>& FromButton(MouseButton button) {
+ switch (button) {
+ case MouseButton::Left:
+ return click_map_.left;
+ case MouseButton::Middle:
+ return click_map_.middle;
+ case MouseButton::Right:
+ return click_map_.right;
+ default:
+ std::abort();
+ }
+ }
+
+ private:
+ Control* control_;
+
+ Event<ClickEventArgs> event_;
+
+ std::forward_list<EventRevokerGuard> event_rovoker_guards_;
+
+ struct {
+ std::optional<Point> left = std::nullopt;
+ std::optional<Point> middle = std::nullopt;
+ std::optional<Point> right = std::nullopt;
+ } click_map_;
+};
+} // namespace cru::ui
diff --git a/include/cru/ui/control.hpp b/include/cru/ui/control.hpp
index f78557a3..b39b59a0 100644
--- a/include/cru/ui/control.hpp
+++ b/include/cru/ui/control.hpp
@@ -18,7 +18,7 @@ class Control : public Object {
friend class Window;
protected:
- Control() = default;
+ Control();
public:
Control(const Control& other) = delete;
@@ -58,10 +58,14 @@ class Control : public Object {
bool HasFocus();
- //*************** region: focus ***************
+ //*************** region: mouse ***************
public:
bool IsMouseOver() const { return is_mouse_over_; }
+ bool CaptureMouse(); // TODO
+
+ bool IsMouseCaptured(); // TODO
+
//*************** region: events ***************
public:
// Raised when mouse enter the control.
@@ -84,11 +88,6 @@ class Control : public Object {
event::RoutedEvent<event::MouseButtonEventArgs>* MouseUpEvent() {
return &mouse_up_event_;
}
- // Raised when a mouse button is pressed in the control and released in the
- // control with mouse not leaving it between two operations.
- event::RoutedEvent<event::MouseButtonEventArgs>* MouseClickEvent() {
- return &mouse_click_event_;
- }
event::RoutedEvent<event::MouseWheelEventArgs>* MouseWheelEvent() {
return &mouse_wheel_event_;
}
@@ -114,7 +113,6 @@ class Control : public Object {
event::RoutedEvent<event::MouseEventArgs> mouse_move_event_;
event::RoutedEvent<event::MouseButtonEventArgs> mouse_down_event_;
event::RoutedEvent<event::MouseButtonEventArgs> mouse_up_event_;
- event::RoutedEvent<event::MouseButtonEventArgs> mouse_click_event_;
event::RoutedEvent<event::MouseWheelEventArgs> mouse_wheel_event_;
event::RoutedEvent<event::KeyEventArgs> key_down_event_;
diff --git a/include/cru/win/graph/direct/text_layout.hpp b/include/cru/win/graph/direct/text_layout.hpp
index c7657762..a20591c2 100644
--- a/include/cru/win/graph/direct/text_layout.hpp
+++ b/include/cru/win/graph/direct/text_layout.hpp
@@ -35,8 +35,8 @@ class DWriteTextLayout : public TextLayout,
std::wstring GetText() override;
void SetText(std::wstring new_text) override;
- std::shared_ptr<Font> GetFont();
- void SetFont(std::shared_ptr<Font> font);
+ std::shared_ptr<Font> GetFont() override;
+ void SetFont(std::shared_ptr<Font> font) override;
void SetMaxWidth(float max_width) override;
void SetMaxHeight(float max_height) override;
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 62ae1775..3186b0f5 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -3,6 +3,7 @@ file(GLOB CRU_UI_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/ui)
add_library(cru_ui STATIC
routed_event_dispatch.hpp
+ click_detector.cpp
content_control.cpp
control.cpp
layout_control.cpp
@@ -20,6 +21,7 @@ add_library(cru_ui STATIC
)
target_sources(cru_ui PUBLIC
${CRU_UI_INCLUDE_DIR}/base.hpp
+ ${CRU_UI_INCLUDE_DIR}/click_detector.hpp
${CRU_UI_INCLUDE_DIR}/content_control.hpp
${CRU_UI_INCLUDE_DIR}/control.hpp
${CRU_UI_INCLUDE_DIR}/layout_control.hpp
diff --git a/src/ui/click_detector.cpp b/src/ui/click_detector.cpp
new file mode 100644
index 00000000..1442b885
--- /dev/null
+++ b/src/ui/click_detector.cpp
@@ -0,0 +1,32 @@
+#include "cru/ui/click_detector.hpp"
+
+#include <cassert>
+#include <optional>
+
+namespace cru::ui {
+ClickDetector::ClickDetector(Control* control) {
+ assert(control);
+ control_ = control;
+
+ event_rovoker_guards_.push_front(
+ EventRevokerGuard(control->MouseDownEvent()->Direct()->AddHandler(
+ [this, control](event::MouseButtonEventArgs& args) {
+ if (!control->CaptureMouse()) return; // capture failed
+ FromButton(args.GetMouseButton()) =
+ args.GetPoint(); // save mouse down point
+ })));
+
+ event_rovoker_guards_.push_front(
+ EventRevokerGuard(control->MouseUpEvent()->Direct()->AddHandler(
+ [this, control](event::MouseButtonEventArgs& args) {
+ if (!control->IsMouseCaptured()) return;
+ const auto button = args.GetMouseButton();
+ auto& down_point = FromButton(button);
+ if (down_point.has_value()) {
+ event_.Raise(ClickEventArgs(control, down_point.value(),
+ args.GetPoint(), button));
+ down_point = std::nullopt;
+ }
+ })));
+}
+} // namespace cru::ui
diff --git a/src/ui/control.cpp b/src/ui/control.cpp
index bcf56c5e..d529b687 100644
--- a/src/ui/control.cpp
+++ b/src/ui/control.cpp
@@ -9,74 +9,20 @@
#include <cassert>
namespace cru::ui {
+Control::Control() {
+ MouseEnterEvent()->Direct()->AddHandler(
+ [this](event::MouseEventArgs&) { this->is_mouse_over_ = true; });
+
+ MouseLeaveEvent()->Direct()->AddHandler(
+ [this](event::MouseEventArgs&) { this->is_mouse_over_ = false; });
+}
+
void Control::_SetParent(Control* parent) {
const auto old_parent = GetParent();
parent_ = parent;
const auto new_parent = GetParent();
if (old_parent != new_parent) OnParentChanged(old_parent, new_parent);
-
- MouseDownEvent()->Direct()->AddHandler(
- [this](event::MouseButtonEventArgs& args) {
- switch (args.GetMouseButton()) {
- case MouseButton::Left:
- click_map_.left = true;
- OnMouseClickBegin(MouseButton::Left);
- break;
- case MouseButton::Middle:
- click_map_.middle = true;
- OnMouseClickBegin(MouseButton::Middle);
- break;
- case MouseButton::Right:
- click_map_.right = true;
- OnMouseClickBegin(MouseButton::Right);
- break;
- }
- });
-
- MouseEnterEvent()->Direct()->AddHandler([this](event::MouseEventArgs&) {
- this->is_mouse_over_ = true;
- });
-
- MouseLeaveEvent()->Direct()->AddHandler([this](event::MouseEventArgs&) {
- this->is_mouse_over_ = false;
- if (click_map_.left) {
- OnMouseClickCancel(MouseButton::Left);
- }
- if (click_map_.middle) {
- OnMouseClickCancel(MouseButton::Middle);
- }
- if (click_map_.right) {
- OnMouseClickCancel(MouseButton::Right);
- }
- click_map_.left = click_map_.middle = click_map_.right = false;
- });
-
- MouseUpEvent()->Direct()->AddHandler([this](event::MouseButtonEventArgs& args) {
- switch (args.GetMouseButton()) {
- case MouseButton::Left:
- if (click_map_.left) {
- click_map_.left = false;
- OnMouseClickEnd(MouseButton::Left);
- DispatchEvent(this, &Control::MouseClickEvent, nullptr, args.GetPoint(), args.GetMouseButton());
- }
- break;
- case MouseButton::Middle:
- if (click_map_.middle) {
- click_map_.middle = false;
- OnMouseClickEnd(MouseButton::Middle);
- DispatchEvent(this, &Control::MouseClickEvent, nullptr, args.GetPoint(), args.GetMouseButton());
- }
- break;
- case MouseButton::Right:
- if (click_map_.right) {
- click_map_.right = false;
- OnMouseClickEnd(MouseButton::Right);
- DispatchEvent(this, &Control::MouseClickEvent, nullptr, args.GetPoint(), args.GetMouseButton());
- }
- break;
- }
- });
-} // namespace cru::ui
+}
void Control::_SetDescendantWindow(Window* window) {
if (window == nullptr && window_ == nullptr) return;