From 0e35b2c022599bca2df61488945f07e4d6b4eb35 Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Sun, 11 Aug 2019 01:09:49 +0800 Subject: ... --- include/cru/ui/control.hpp | 16 +++++- include/cru/ui/controls/button.hpp | 79 ++++++++++++++++++++++++++ include/cru/ui/event/ui_event.hpp | 20 +++++-- include/cru/ui/render/border_render_object.hpp | 36 +++++++++--- 4 files changed, 135 insertions(+), 16 deletions(-) (limited to 'include/cru/ui') 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 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_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 #include 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 class RoutedEvent { public: @@ -45,16 +48,19 @@ class RoutedEvent { using EventArgs = TEventArgs; - RoutedEvent() = default; + RoutedEvent() + : direct(new Event()), + bubble(new Event()), + tunnel(new Event()) {} RoutedEvent(const RoutedEvent& other) = delete; RoutedEvent(RoutedEvent&& other) = delete; RoutedEvent& operator=(const RoutedEvent& other) = delete; RoutedEvent& operator=(RoutedEvent&& other) = delete; ~RoutedEvent() = default; - Event direct; - Event bubble; - Event tunnel; + const std::unique_ptr> direct; + const std::unique_ptr> bubble; + const std::unique_ptr> 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 @@ -30,6 +32,12 @@ struct CornerRadius { Point right_bottom; }; +struct BorderStyle { + std::shared_ptr brush; + Thickness thickness; + CornerRadius corner_radius; +}; + class BorderRenderObject : public RenderObject { public: explicit BorderRenderObject(std::shared_ptr brush); @@ -43,20 +51,30 @@ class BorderRenderObject : public RenderObject { void SetEnabled(bool enabled) { is_enabled_ = enabled; } std::shared_ptr GetBrush() const { - return border_brush_; + return style_.brush; } void SetBrush(std::shared_ptr 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 border_brush_ = nullptr; - Thickness border_thickness_{}; - CornerRadius corner_radius_{}; + BorderStyle style_; + // The ring. Used for painting. std::shared_ptr geometry_ = nullptr; + // Area including border ring and inner area. Used for hit test. std::shared_ptr border_outer_geometry_ = nullptr; }; } // namespace cru::ui::render -- cgit v1.2.3