diff options
-rw-r--r-- | include/cru/platform/graphic_base.hpp | 12 | ||||
-rw-r--r-- | include/cru/platform/native/native_window.hpp | 1 | ||||
-rw-r--r-- | include/cru/ui/click_detector.hpp | 8 | ||||
-rw-r--r-- | include/cru/ui/control.hpp | 12 | ||||
-rw-r--r-- | include/cru/ui/controls/button.hpp | 10 | ||||
-rw-r--r-- | include/cru/win/native/native_window.hpp | 1 | ||||
-rw-r--r-- | src/ui/click_detector.cpp | 7 | ||||
-rw-r--r-- | src/ui/control.cpp | 19 | ||||
-rw-r--r-- | src/ui/controls/button.cpp | 84 | ||||
-rw-r--r-- | src/ui/controls/flex_layout.cpp | 5 | ||||
-rw-r--r-- | src/ui/controls/text_block.cpp | 1 | ||||
-rw-r--r-- | src/ui/render/border_render_object.cpp | 2 | ||||
-rw-r--r-- | src/ui/render/flex_layout_render_object.cpp | 2 | ||||
-rw-r--r-- | src/ui/render/window_render_object.cpp | 2 | ||||
-rw-r--r-- | src/ui/window.cpp | 8 | ||||
-rw-r--r-- | src/win/native/native_window.cpp | 9 |
16 files changed, 132 insertions, 51 deletions
diff --git a/include/cru/platform/graphic_base.hpp b/include/cru/platform/graphic_base.hpp index 2aa4e2cb..fd479e56 100644 --- a/include/cru/platform/graphic_base.hpp +++ b/include/cru/platform/graphic_base.hpp @@ -239,8 +239,14 @@ struct Color { : red(red), green(green), blue(blue), alpha(alpha) {} constexpr static Color FromHex(std::uint32_t hex) { - return Color(hex & (0b11111111 << 16), hex & (0b11111111 << 8), - hex & (0b11111111), hex & (0b11111111 << 24)); + const std::uint32_t mask = 0b11111111; + return Color((hex >> 16) & mask, (hex >> 8) & mask, hex & mask, 255); + } + + constexpr static Color FromHexAlpha(std::uint32_t hex) { + const std::uint32_t mask = 0b11111111; + return Color((hex >> 16) & mask, (hex >> 8) & mask, hex & mask, + (hex >> 24) & mask); } std::uint8_t red; @@ -254,4 +260,4 @@ constexpr Color black{0, 0, 0}; constexpr Color white{255, 255, 255}; constexpr Color skyblue = Color::FromHex(0x87ceeb); } // namespace colors -} // namespace cru::ui +} // namespace cru::platform diff --git a/include/cru/platform/native/native_window.hpp b/include/cru/platform/native/native_window.hpp index b557a0dd..d4e608b4 100644 --- a/include/cru/platform/native/native_window.hpp +++ b/include/cru/platform/native/native_window.hpp @@ -62,6 +62,7 @@ class NativeWindow : public NativeResource { virtual bool CaptureMouse() = 0; virtual bool ReleaseMouse() = 0; + virtual void Repaint() = 0; virtual graph::Painter* BeginPaint() = 0; virtual IEvent<std::nullptr_t>* DestroyEvent() = 0; diff --git a/include/cru/ui/click_detector.hpp b/include/cru/ui/click_detector.hpp index e7d5e417..3806dd82 100644 --- a/include/cru/ui/click_detector.hpp +++ b/include/cru/ui/click_detector.hpp @@ -47,7 +47,7 @@ class ClickDetector : public Object { // Return a union of buttons being pressed. Return 0 if no button is being // pressed. - MouseButton IsPressing() const { + MouseButton GetPressingButton() const { unsigned result = 0; if (click_map_.left.has_value()) result |= MouseButton::Left; if (click_map_.middle.has_value()) result |= MouseButton::Middle; @@ -57,6 +57,9 @@ class ClickDetector : public Object { IEvent<ClickEventArgs>* ClickEvent() { return &event_; } + IEvent<MouseButton>* ClickBeginEvent() { return &begin_event_; } + IEvent<MouseButton>* ClickEndEvent() { return &end_event_; } + private: std::optional<Point>& FromButton(MouseButton button) { switch (button) { @@ -76,6 +79,9 @@ class ClickDetector : public Object { Event<ClickEventArgs> event_; + Event<MouseButton> begin_event_; + Event<MouseButton> end_event_; + std::forward_list<EventRevokerGuard> event_rovoker_guards_; struct { diff --git a/include/cru/ui/control.hpp b/include/cru/ui/control.hpp index b39b59a0..f312272e 100644 --- a/include/cru/ui/control.hpp +++ b/include/cru/ui/control.hpp @@ -62,9 +62,11 @@ class Control : public Object { public: bool IsMouseOver() const { return is_mouse_over_; } - bool CaptureMouse(); // TODO + bool CaptureMouse(); - bool IsMouseCaptured(); // TODO + bool ReleaseMouse(); + + bool IsMouseCaptured(); //*************** region: events *************** public: @@ -128,12 +130,6 @@ class Control : public Object { virtual void OnAttachToWindow(Window* window); virtual void OnDetachToWindow(Window* window); - //*************** region: additional mouse event *************** - 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; diff --git a/include/cru/ui/controls/button.hpp b/include/cru/ui/controls/button.hpp index 648bb6bc..ca3dcae9 100644 --- a/include/cru/ui/controls/button.hpp +++ b/include/cru/ui/controls/button.hpp @@ -1,10 +1,10 @@ #pragma once #include "../content_control.hpp" +#include "../click_detector.hpp" +#include "../render/border_render_object.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> @@ -94,13 +94,11 @@ class Button : public ContentControl { 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) { + if (state_ == newState) return; const auto oldState = state_; state_ = newState; OnStateChange(oldState, newState); @@ -114,5 +112,7 @@ class Button : public ContentControl { MouseButton trigger_button_ = MouseButton::Left; ButtonBorderStyle border_style_; + + ClickDetector click_detector_; }; } // namespace cru::ui::controls diff --git a/include/cru/win/native/native_window.hpp b/include/cru/win/native/native_window.hpp index b044aef8..ccbdff40 100644 --- a/include/cru/win/native/native_window.hpp +++ b/include/cru/win/native/native_window.hpp @@ -53,6 +53,7 @@ class WinNativeWindow : public NativeWindow { bool CaptureMouse() override; bool ReleaseMouse() override; + void Repaint() override; graph::Painter* BeginPaint() override; IEvent<std::nullptr_t>* DestroyEvent() override { return &destroy_event_; } diff --git a/src/ui/click_detector.cpp b/src/ui/click_detector.cpp index 1442b885..b335f3b5 100644 --- a/src/ui/click_detector.cpp +++ b/src/ui/click_detector.cpp @@ -12,8 +12,9 @@ ClickDetector::ClickDetector(Control* control) { 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 + const auto button = args.GetMouseButton(); + FromButton(button) = args.GetPoint(); // save mouse down point + begin_event_.Raise(button); }))); event_rovoker_guards_.push_front( @@ -25,8 +26,10 @@ ClickDetector::ClickDetector(Control* control) { if (down_point.has_value()) { event_.Raise(ClickEventArgs(control, down_point.value(), args.GetPoint(), button)); + end_event_.Raise(button); down_point = std::nullopt; } + control->ReleaseMouse(); }))); } } // namespace cru::ui diff --git a/src/ui/control.cpp b/src/ui/control.cpp index d529b687..7bd33d84 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -54,6 +54,7 @@ void Control::_TraverseDescendants( predicate(control); for (auto c : control->GetChildren()) _TraverseDescendants(c, predicate); } + bool Control::RequestFocus() { auto window = GetWindow(); if (window == nullptr) return false; @@ -68,15 +69,21 @@ bool Control::HasFocus() { return window->GetFocusControl() == this; } -void Control::OnParentChanged(Control* old_parent, Control* new_parent) {} +bool Control::CaptureMouse() { + return GetWindow()->CaptureMouseFor(this); +} -void Control::OnAttachToWindow(Window* window) {} +bool Control::ReleaseMouse() { + return GetWindow()->CaptureMouseFor(nullptr); +} -void Control::OnDetachToWindow(Window* window) {} +bool Control::IsMouseCaptured() { + return GetWindow()->GetMouseCaptureControl() == this; +} -void Control::OnMouseClickBegin(platform::native::MouseButton button) {} +void Control::OnParentChanged(Control* old_parent, Control* new_parent) {} -void Control::OnMouseClickEnd(platform::native::MouseButton button) {} +void Control::OnAttachToWindow(Window* window) {} -void Control::OnMouseClickCancel(platform::native::MouseButton button) {} +void Control::OnDetachToWindow(Window* window) {} } // namespace cru::ui diff --git a/src/ui/controls/button.cpp b/src/ui/controls/button.cpp index 618371fb..42a08e33 100644 --- a/src/ui/controls/button.cpp +++ b/src/ui/controls/button.cpp @@ -1,17 +1,60 @@ #include "cru/ui/controls/button.hpp" +#include <memory> +#include "cru/platform/graph/brush.hpp" +#include "cru/platform/graph/graph_factory.hpp" +#include "cru/platform/native/native_window.hpp" #include "cru/ui/render/border_render_object.hpp" #include "cru/ui/ui_manager.hpp" +#include "cru/ui/window.hpp" namespace cru::ui::controls { -Button::Button() { - const auto predefined_resource = - UiManager::GetInstance()->GetPredefineResources(); - render_object_.reset(new render::BorderRenderObject( - predefined_resource->button_normal_border_brush)); +Button::Button() : click_detector_(this) { + // const auto predefined_resource = + // UiManager::GetInstance()->GetPredefineResources(); + + const auto factory = platform::graph::GraphFactory::GetInstance(); + border_style_.normal.brush = std::shared_ptr<platform::graph::Brush>( + factory->CreateSolidColorBrush(Color::FromHex(0x00bfff))); + border_style_.hover.brush = std::shared_ptr<platform::graph::Brush>( + factory->CreateSolidColorBrush(Color::FromHex(0x47d1ff))); + border_style_.press.brush = std::shared_ptr<platform::graph::Brush>( + factory->CreateSolidColorBrush(Color::FromHex(0x91e4ff))); + + border_style_.normal.thickness = border_style_.hover.thickness = + border_style_.press.thickness = Thickness{3}; + + border_style_.normal.corner_radius = border_style_.hover.corner_radius = + border_style_.press.corner_radius = render::CornerRadius{Point{10, 5}}; + + render_object_.reset( + new render::BorderRenderObject(border_style_.normal.brush)); + render_object_->SetAttachedControl(this); render_object_->SetEnabled(true); - render_object_->SetBorderWidth(Thickness{3}); - render_object_->SetCornerRadius(render::CornerRadius{Point{10, 5}}); + render_object_->SetStyle(border_style_.normal); + + MouseEnterEvent()->Direct()->AddHandler([this](event::MouseEventArgs& args) { + if (click_detector_.GetPressingButton() & trigger_button_) { + SetState(ButtonState::Press); + } else { + SetState(ButtonState::Hover); + } + }); + + MouseLeaveEvent()->Direct()->AddHandler( + [this](event::MouseEventArgs& args) { SetState(ButtonState::Normal); }); + + click_detector_.ClickBeginEvent()->AddHandler([this](MouseButton button) { + if (button & trigger_button_) { + SetState(ButtonState::Press); + } + }); + + click_detector_.ClickEndEvent()->AddHandler([this](MouseButton button) { + if (button & trigger_button_) { + SetState(ButtonState::Normal); + } + }); } render::RenderObject* Button::GetRenderObject() const { @@ -24,21 +67,18 @@ void Button::OnChildChanged(Control* old_child, Control* new_child) { render_object_->AddChild(new_child->GetRenderObject(), 0); } -void Button::OnMouseClickBegin(platform::native::MouseButton button) { - if (button & trigger_button_) { - SetState(ButtonState::Press); - //TODO! - } -} - -void Button::OnMouseClickEnd(platform::native::MouseButton button) { - if (button & trigger_button_) { - SetState(ButtonState::Normal); - //TODO! - } -} - void Button::OnStateChange(ButtonState oldState, ButtonState newState) { - + switch (newState) { + case ButtonState::Normal: + render_object_->SetStyle(border_style_.normal); + break; + case ButtonState::Hover: + render_object_->SetStyle(border_style_.hover); + break; + case ButtonState::Press: + render_object_->SetStyle(border_style_.press); + break; + } + GetWindow()->GetNativeWindow()->Repaint(); } } // namespace cru::ui::controls diff --git a/src/ui/controls/flex_layout.cpp b/src/ui/controls/flex_layout.cpp index 3b70c98c..340710cc 100644 --- a/src/ui/controls/flex_layout.cpp +++ b/src/ui/controls/flex_layout.cpp @@ -5,7 +5,10 @@ namespace cru::ui::controls { using render::FlexLayoutRenderObject; -FlexLayout::FlexLayout() { render_object_.reset(new FlexLayoutRenderObject()); } +FlexLayout::FlexLayout() { + render_object_.reset(new FlexLayoutRenderObject()); + render_object_->SetAttachedControl(this); +} render::RenderObject* FlexLayout::GetRenderObject() const { return render_object_.get(); diff --git a/src/ui/controls/text_block.cpp b/src/ui/controls/text_block.cpp index 55d83acc..71903981 100644 --- a/src/ui/controls/text_block.cpp +++ b/src/ui/controls/text_block.cpp @@ -13,6 +13,7 @@ TextBlock::TextBlock() { new TextRenderObject(predefined_resources->text_block_text_brush, predefined_resources->text_block_font, predefined_resources->text_block_selection_brush)); + render_object_->SetAttachedControl(this); } render::RenderObject* TextBlock::GetRenderObject() const { diff --git a/src/ui/render/border_render_object.cpp b/src/ui/render/border_render_object.cpp index 1bec3e0b..4b61e511 100644 --- a/src/ui/render/border_render_object.cpp +++ b/src/ui/render/border_render_object.cpp @@ -30,7 +30,7 @@ RenderObject* BorderRenderObject::HitTest(const Point& point) { if (const auto child = GetChild()) { auto offset = child->GetOffset(); Point p{point.x - offset.x, point.y - offset.y}; - const auto result = child->HitTest(point); + const auto result = child->HitTest(p); if (result != nullptr) { return result; } diff --git a/src/ui/render/flex_layout_render_object.cpp b/src/ui/render/flex_layout_render_object.cpp index 8ce2db0a..5e313e49 100644 --- a/src/ui/render/flex_layout_render_object.cpp +++ b/src/ui/render/flex_layout_render_object.cpp @@ -29,7 +29,7 @@ RenderObject* FlexLayoutRenderObject::HitTest(const Point& point) { for (auto i = children.crbegin(); i != children.crend(); ++i) { auto offset = (*i)->GetOffset(); Point p{point.x - offset.x, point.y - offset.y}; - const auto result = (*i)->HitTest(point); + const auto result = (*i)->HitTest(p); if (result != nullptr) { return result; } diff --git a/src/ui/render/window_render_object.cpp b/src/ui/render/window_render_object.cpp index 89bb0beb..18faeee8 100644 --- a/src/ui/render/window_render_object.cpp +++ b/src/ui/render/window_render_object.cpp @@ -27,7 +27,7 @@ RenderObject* WindowRenderObject::HitTest(const Point& point) { if (const auto child = GetChild()) { auto offset = child->GetOffset(); Point p{point.x - offset.x, point.y - offset.y}; - const auto result = child->HitTest(point); + const auto result = child->HitTest(p); if (result != nullptr) { return result; } diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 47509749..1ec34c1d 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -7,6 +7,7 @@ #include "routed_event_dispatch.hpp" #include <cassert> +#include <list> namespace cru::ui { namespace { @@ -54,6 +55,7 @@ Control* FindLowestCommonAncestor(Control* left, Control* right, *find_result = in_right; return result; } + ++right_i; } return result; } @@ -64,6 +66,7 @@ Control* FindLowestCommonAncestor(Control* left, Control* right, *find_result = in_left; return result; } + ++left_i; } return result; } @@ -75,13 +78,16 @@ Control* FindLowestCommonAncestor(Control* left, Control* right, *find_result = in_right; return result; } + ++right_i; } while (left_i != left_list.cend()) { if (*left_i == find_control) { *find_result = in_left; return result; } + ++left_i; } + return result; } ++left_i; ++right_i; @@ -107,9 +113,11 @@ Window::Window(tag_overlapped_constructor) : mouse_hover_control_(nullptr), focus_control_(this), mouse_captured_control_(nullptr) { + window_ = this; native_window_ = platform::native::UiApplication::GetInstance()->CreateWindow(nullptr); render_object_.reset(new render::WindowRenderObject(this)); + render_object_->SetAttachedControl(this); BindNativeEvent(this, native_window_->DestroyEvent(), &Window::OnNativeDestroy, event_revoker_guards_); diff --git a/src/win/native/native_window.cpp b/src/win/native/native_window.cpp index 5da121cf..f301f955 100644 --- a/src/win/native/native_window.cpp +++ b/src/win/native/native_window.cpp @@ -147,6 +147,15 @@ bool WinNativeWindow::ReleaseMouse() { return false; } +void WinNativeWindow::Repaint() { + if (IsValid()) { + if (!::InvalidateRect(hwnd_, nullptr, FALSE)) + throw Win32Error(::GetLastError(), "Failed to invalidate window."); + if (!::UpdateWindow(hwnd_)) + throw Win32Error(::GetLastError(), "Failed to update window."); + } +} + graph::Painter* WinNativeWindow::BeginPaint() { return new WindowD2DPainter(this); } |