aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/cru/common/event.hpp2
-rw-r--r--include/cru/platform/exception.hpp2
-rw-r--r--include/cru/platform/native/basic_types.hpp4
-rw-r--r--include/cru/ui/control.hpp16
-rw-r--r--include/cru/ui/controls/button.hpp79
-rw-r--r--include/cru/ui/event/ui_event.hpp20
-rw-r--r--include/cru/ui/render/border_render_object.hpp36
7 files changed, 139 insertions, 20 deletions
diff --git a/include/cru/common/event.hpp b/include/cru/common/event.hpp
index 50918dd0..12c0d0cd 100644
--- a/include/cru/common/event.hpp
+++ b/include/cru/common/event.hpp
@@ -148,7 +148,7 @@ class Event : public details::EventBase, public IEvent<TEventArgs> {
// Thanks to this behavior, all handlers will be taken a snapshot when Raise
// is called, so even if you delete a handler during this period, all handlers
// in the snapshot will be executed.
- void Raise(EventArgs args) {
+ void Raise(typename IEvent<TEventArgs>::EventArgs args) {
std::forward_list<EventHandler> handlers;
auto iter = handlers.cbefore_begin();
for (const auto& data : this->handler_data_list_) {
diff --git a/include/cru/platform/exception.hpp b/include/cru/platform/exception.hpp
index b1e505e0..ad6827c0 100644
--- a/include/cru/platform/exception.hpp
+++ b/include/cru/platform/exception.hpp
@@ -11,7 +11,7 @@ class PlatformException : public std::runtime_error {
// This exception is throwed when a resource has been disposed and not usable
// again.
-// For example, calling Build twice on a GeometryBuild will lead to this
+// For example, calling Build twice on a GeometryBuilder::Build will lead to this
// exception.
class ReuseException : public std::runtime_error {
public:
diff --git a/include/cru/platform/native/basic_types.hpp b/include/cru/platform/native/basic_types.hpp
index 573a9e76..5a7155ee 100644
--- a/include/cru/platform/native/basic_types.hpp
+++ b/include/cru/platform/native/basic_types.hpp
@@ -7,5 +7,5 @@ struct Dpi {
float y;
};
-enum class MouseButton { Left, Right, Middle };
-} // namespace cru::platform
+enum MouseButton : unsigned { Left = 1, Right = 2, Middle = 4 };
+} // namespace cru::platform::native
diff --git a/include/cru/ui/control.hpp b/include/cru/ui/control.hpp
index 15eeb6fa..f78557a3 100644
--- a/include/cru/ui/control.hpp
+++ b/include/cru/ui/control.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include "cru/common/base.hpp"
#include "base.hpp"
+#include "cru/common/base.hpp"
#include "cru/platform/native/basic_types.hpp"
#include "event/ui_event.hpp"
@@ -58,6 +58,10 @@ class Control : public Object {
bool HasFocus();
+ //*************** region: focus ***************
+ public:
+ bool IsMouseOver() const { return is_mouse_over_; }
+
//*************** region: events ***************
public:
// Raised when mouse enter the control.
@@ -130,9 +134,19 @@ class Control : public Object {
protected:
virtual void OnMouseClickBegin(platform::native::MouseButton button);
virtual void OnMouseClickEnd(platform::native::MouseButton button);
+ virtual void OnMouseClickCancel(platform::native::MouseButton button);
private:
Window* window_ = nullptr;
Control* parent_ = nullptr;
+
+ private:
+ bool is_mouse_over_ = false;
+
+ struct {
+ bool left;
+ bool middle;
+ bool right;
+ } click_map_;
};
} // namespace cru::ui
diff --git a/include/cru/ui/controls/button.hpp b/include/cru/ui/controls/button.hpp
index 348416c5..648bb6bc 100644
--- a/include/cru/ui/controls/button.hpp
+++ b/include/cru/ui/controls/button.hpp
@@ -1,6 +1,11 @@
#pragma once
#include "../content_control.hpp"
+#include "cru/platform/graph/brush.hpp"
+#include "cru/platform/native/basic_types.hpp"
+#include "cru/ui/base.hpp"
+#include "cru/ui/render/border_render_object.hpp"
+
#include <memory>
namespace cru::ui::render {
@@ -8,6 +13,24 @@ class BorderRenderObject;
}
namespace cru::ui::controls {
+struct ButtonBorderStyle {
+ // corresponds to ButtonState::Normal
+ render::BorderStyle normal;
+ // corresponds to ButtonState::Hover
+ render::BorderStyle hover;
+ // corresponds to ButtonState::Press
+ render::BorderStyle press;
+};
+
+enum class ButtonState {
+ // mouse is not in it
+ Normal,
+ // mouse is in it and not pressed
+ Hover,
+ // mouse is pressed in it (click begins)
+ Press
+};
+
class Button : public ContentControl {
public:
static constexpr auto control_type = L"Button";
@@ -30,10 +53,66 @@ class Button : public ContentControl {
render::RenderObject* GetRenderObject() const override;
+ public:
+ render::BorderStyle GetNormalBorderStyle() const {
+ return border_style_.normal;
+ }
+ void SetNormalBorderStyle(render::BorderStyle newStyle) {
+ border_style_.normal = std::move(newStyle);
+ }
+
+ render::BorderStyle GetHoverBorderStyle() const {
+ return border_style_.hover;
+ }
+ void SetHoverBorderStyle(render::BorderStyle newStyle) {
+ border_style_.hover = std::move(newStyle);
+ }
+
+ render::BorderStyle GetPressBorderStyle() const {
+ return border_style_.press;
+ }
+ void SetPressBorderStyle(render::BorderStyle newStyle) {
+ border_style_.press = std::move(newStyle);
+ }
+
+ ButtonBorderStyle GetBorderStyle() const { return border_style_; }
+ void SetBorderStyle(ButtonBorderStyle newStyle) {
+ border_style_ = std::move(newStyle);
+ }
+
+ ButtonState GetState() const { return state_; }
+
+ // Get the trigger mouse button(s). Return value might be a union of Left,
+ // Middle and Right.
+ MouseButton GetTriggerButton() const { return trigger_button_; }
+ // Set the trigger mouse button(s). You can set multiple buttons by passing a
+ // union of Left, Middle and Right. If you disable a button when user is
+ // pressing the same one, click will be stopped.
+ // Default is only Left.
+ void SetTriggerButton(MouseButton newTrigger);
+
protected:
void OnChildChanged(Control* old_child, Control* new_child) override;
+ void OnMouseClickBegin(platform::native::MouseButton button) override;
+ void OnMouseClickEnd(platform::native::MouseButton button) override;
+
+ virtual void OnStateChange(ButtonState oldState, ButtonState newState);
+
+ private:
+ void SetState(ButtonState newState) {
+ const auto oldState = state_;
+ state_ = newState;
+ OnStateChange(oldState, newState);
+ }
+
private:
std::shared_ptr<render::BorderRenderObject> render_object_{};
+
+ ButtonState state_ = ButtonState::Normal;
+
+ MouseButton trigger_button_ = MouseButton::Left;
+
+ ButtonBorderStyle border_style_;
};
} // namespace cru::ui::controls
diff --git a/include/cru/ui/event/ui_event.hpp b/include/cru/ui/event/ui_event.hpp
index 62045808..f36e40a2 100644
--- a/include/cru/ui/event/ui_event.hpp
+++ b/include/cru/ui/event/ui_event.hpp
@@ -4,6 +4,7 @@
#include "../base.hpp"
#include "cru/common/event.hpp"
+#include <memory>
#include <optional>
namespace cru::platform::graph {
@@ -37,6 +38,8 @@ class UiEventArgs : public Object {
bool handled_;
};
+// TEventArgs must not be a reference type. This class help add reference.
+// EventArgs must be reference because the IsHandled property must be settable.
template <typename TEventArgs>
class RoutedEvent {
public:
@@ -45,16 +48,19 @@ class RoutedEvent {
using EventArgs = TEventArgs;
- RoutedEvent() = default;
+ RoutedEvent()
+ : direct(new Event<TEventArgs&>()),
+ bubble(new Event<TEventArgs&>()),
+ tunnel(new Event<TEventArgs&>()) {}
RoutedEvent(const RoutedEvent& other) = delete;
RoutedEvent(RoutedEvent&& other) = delete;
RoutedEvent& operator=(const RoutedEvent& other) = delete;
RoutedEvent& operator=(RoutedEvent&& other) = delete;
~RoutedEvent() = default;
- Event<TEventArgs> direct;
- Event<TEventArgs> bubble;
- Event<TEventArgs> tunnel;
+ const std::unique_ptr<IEvent<TEventArgs&>> direct;
+ const std::unique_ptr<IEvent<TEventArgs&>> bubble;
+ const std::unique_ptr<IEvent<TEventArgs&>> tunnel;
};
class MouseEventArgs : public UiEventArgs {
@@ -77,9 +83,11 @@ class MouseEventArgs : public UiEventArgs {
class MouseButtonEventArgs : public MouseEventArgs {
public:
MouseButtonEventArgs(Object* sender, Object* original_sender,
- const Point& point,
- const MouseButton button)
+ const Point& point, const MouseButton button)
: MouseEventArgs(sender, original_sender, point), button_(button) {}
+ MouseButtonEventArgs(Object* sender, Object* original_sender,
+ const MouseButton button)
+ : MouseEventArgs(sender, original_sender), button_(button) {}
MouseButtonEventArgs(const MouseButtonEventArgs& other) = default;
MouseButtonEventArgs(MouseButtonEventArgs&& other) = default;
MouseButtonEventArgs& operator=(const MouseButtonEventArgs& other) = default;
diff --git a/include/cru/ui/render/border_render_object.hpp b/include/cru/ui/render/border_render_object.hpp
index ab424e60..69372eb8 100644
--- a/include/cru/ui/render/border_render_object.hpp
+++ b/include/cru/ui/render/border_render_object.hpp
@@ -1,4 +1,6 @@
#pragma once
+#include "cru/platform/graph/brush.hpp"
+#include "cru/ui/base.hpp"
#include "render_object.hpp"
#include <memory>
@@ -30,6 +32,12 @@ struct CornerRadius {
Point right_bottom;
};
+struct BorderStyle {
+ std::shared_ptr<platform::graph::Brush> brush;
+ Thickness thickness;
+ CornerRadius corner_radius;
+};
+
class BorderRenderObject : public RenderObject {
public:
explicit BorderRenderObject(std::shared_ptr<platform::graph::Brush> brush);
@@ -43,20 +51,30 @@ class BorderRenderObject : public RenderObject {
void SetEnabled(bool enabled) { is_enabled_ = enabled; }
std::shared_ptr<platform::graph::Brush> GetBrush() const {
- return border_brush_;
+ return style_.brush;
}
void SetBrush(std::shared_ptr<platform::graph::Brush> new_brush) {
- border_brush_ = std::move(new_brush);
+ style_.brush = std::move(new_brush);
}
- Thickness GetBorderWidth() const { return border_thickness_; }
+ Thickness GetBorderWidth() const { return style_.thickness; }
+ // Remember to call Refresh after set shape properties.
void SetBorderWidth(const Thickness& thickness) {
- border_thickness_ = thickness;
+ style_.thickness = thickness;
}
- CornerRadius GetCornerRadius() const { return corner_radius_; }
+ CornerRadius GetCornerRadius() const { return style_.corner_radius; }
+ // Remember to call Refresh after set shape properties.
void SetCornerRadius(const CornerRadius& new_corner_radius) {
- corner_radius_ = new_corner_radius;
+ style_.corner_radius = new_corner_radius;
+ }
+
+ BorderStyle GetStyle() const {
+ return style_;
+ }
+ // Remember to call Refresh after set shape properties.
+ void SetStyle(BorderStyle newStyle) {
+ style_ = std::move(newStyle);
}
void Refresh() { RecreateGeometry(); }
@@ -85,11 +103,11 @@ class BorderRenderObject : public RenderObject {
private:
bool is_enabled_ = false;
- std::shared_ptr<platform::graph::Brush> border_brush_ = nullptr;
- Thickness border_thickness_{};
- CornerRadius corner_radius_{};
+ BorderStyle style_;
+ // The ring. Used for painting.
std::shared_ptr<platform::graph::Geometry> geometry_ = nullptr;
+ // Area including border ring and inner area. Used for hit test.
std::shared_ptr<platform::graph::Geometry> border_outer_geometry_ = nullptr;
};
} // namespace cru::ui::render