aboutsummaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/CMakeLists.txt2
-rw-r--r--src/ui/control.cpp73
-rw-r--r--src/ui/controls/button.cpp14
-rw-r--r--src/ui/render/border_render_object.cpp27
-rw-r--r--src/ui/routed_event_dispatch.hpp60
-rw-r--r--src/ui/window.cpp56
6 files changed, 161 insertions, 71 deletions
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 6d6fc02d..62ae1775 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -1,6 +1,8 @@
file(GLOB CRU_UI_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/ui)
add_library(cru_ui STATIC
+ routed_event_dispatch.hpp
+
content_control.cpp
control.cpp
layout_control.cpp
diff --git a/src/ui/control.cpp b/src/ui/control.cpp
index 7563dc91..51e1937a 100644
--- a/src/ui/control.cpp
+++ b/src/ui/control.cpp
@@ -1,6 +1,10 @@
#include "cru/ui/control.hpp"
+#include "cru/platform/native/basic_types.hpp"
+#include "cru/ui/base.hpp"
+#include "cru/ui/event/ui_event.hpp"
#include "cru/ui/window.hpp"
+#include "routed_event_dispatch.hpp"
#include <cassert>
@@ -10,7 +14,69 @@ void Control::_SetParent(Control* parent) {
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;
@@ -40,8 +106,7 @@ void Control::TraverseDescendants(
void Control::_TraverseDescendants(
Control* control, const std::function<void(Control*)>& predicate) {
predicate(control);
- for (auto c : control->GetChildren())
- _TraverseDescendants(c, predicate);
+ for (auto c : control->GetChildren()) _TraverseDescendants(c, predicate);
}
bool Control::RequestFocus() {
auto window = GetWindow();
@@ -66,4 +131,6 @@ void Control::OnDetachToWindow(Window* window) {}
void Control::OnMouseClickBegin(platform::native::MouseButton button) {}
void Control::OnMouseClickEnd(platform::native::MouseButton button) {}
+
+void Control::OnMouseClickCancel(platform::native::MouseButton button) {}
} // namespace cru::ui
diff --git a/src/ui/controls/button.cpp b/src/ui/controls/button.cpp
index 0ac65d26..2228343c 100644
--- a/src/ui/controls/button.cpp
+++ b/src/ui/controls/button.cpp
@@ -23,4 +23,18 @@ void Button::OnChildChanged(Control* old_child, Control* new_child) {
if (new_child != nullptr)
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!
+ }
+}
} // namespace cru::ui::controls
diff --git a/src/ui/render/border_render_object.cpp b/src/ui/render/border_render_object.cpp
index 16d2f1ea..1bec3e0b 100644
--- a/src/ui/render/border_render_object.cpp
+++ b/src/ui/render/border_render_object.cpp
@@ -12,12 +12,12 @@ namespace cru::ui::render {
BorderRenderObject::BorderRenderObject(
std::shared_ptr<platform::graph::Brush> brush) {
assert(brush);
- this->border_brush_ = std::move(brush);
+ this->style_.brush = std::move(brush);
RecreateGeometry();
}
void BorderRenderObject::Draw(platform::graph::Painter* painter) {
- painter->FillGeometry(geometry_.get(), border_brush_.get());
+ painter->FillGeometry(geometry_.get(), style_.brush.get());
if (const auto child = GetChild()) {
auto offset = child->GetOffset();
platform::graph::util::WithTransform(
@@ -69,8 +69,8 @@ void BorderRenderObject::OnMeasureCore(const Size& available_size) {
margin.GetVerticalTotal() + padding.GetVerticalTotal()};
if (is_enabled_) {
- margin_border_padding_size.width += border_thickness_.GetHorizontalTotal();
- margin_border_padding_size.height += border_thickness_.GetVerticalTotal();
+ margin_border_padding_size.width += style_.thickness.GetHorizontalTotal();
+ margin_border_padding_size.height += style_.thickness.GetVerticalTotal();
}
auto coerced_margin_border_padding_size = margin_border_padding_size;
@@ -104,8 +104,8 @@ void BorderRenderObject::OnLayoutCore(const Rect& rect) {
margin.GetVerticalTotal() + padding.GetVerticalTotal()};
if (is_enabled_) {
- margin_border_padding_size.width += border_thickness_.GetHorizontalTotal();
- margin_border_padding_size.height += border_thickness_.GetVerticalTotal();
+ margin_border_padding_size.width += style_.thickness.GetHorizontalTotal();
+ margin_border_padding_size.height += style_.thickness.GetVerticalTotal();
}
const auto content_available_size =
@@ -121,14 +121,13 @@ void BorderRenderObject::OnLayoutCore(const Rect& rect) {
if (coerced_content_available_size.height < 0) {
platform::DebugMessage(
L"Layout: vertical length of padding, border and margin is bigger "
- L"than "
- L"available length.");
+ L"than available length.");
coerced_content_available_size.height = 0;
}
OnLayoutContent(Rect{
- margin.left + (is_enabled_ ? border_thickness_.left : 0) + padding.left,
- margin.top + (is_enabled_ ? border_thickness_.top : 0) + padding.top,
+ margin.left + (is_enabled_ ? style_.thickness.left : 0) + padding.left,
+ margin.top + (is_enabled_ ? style_.thickness.top : 0) + padding.top,
coerced_content_available_size.width,
coerced_content_available_size.height});
}
@@ -184,14 +183,14 @@ void BorderRenderObject::RecreateGeometry() {
const auto graph_factory = platform::graph::GraphFactory::GetInstance();
std::unique_ptr<platform::graph::GeometryBuilder> builder{
graph_factory->CreateGeometryBuilder()};
- f(builder.get(), outer_rect, corner_radius_);
+ f(builder.get(), outer_rect, style_.corner_radius);
border_outer_geometry_.reset(builder->Build());
builder.reset();
- const Rect inner_rect = outer_rect.Shrink(border_thickness_);
+ const Rect inner_rect = outer_rect.Shrink(style_.thickness);
builder.reset(graph_factory->CreateGeometryBuilder());
- f(builder.get(), outer_rect, corner_radius_);
- f(builder.get(), inner_rect, corner_radius_);
+ f(builder.get(), outer_rect, style_.corner_radius);
+ f(builder.get(), inner_rect, style_.corner_radius);
geometry_.reset(builder->Build());
builder.reset();
}
diff --git a/src/ui/routed_event_dispatch.hpp b/src/ui/routed_event_dispatch.hpp
new file mode 100644
index 00000000..3427441b
--- /dev/null
+++ b/src/ui/routed_event_dispatch.hpp
@@ -0,0 +1,60 @@
+#pragma once
+#include "cru/ui/control.hpp"
+
+namespace cru::ui {
+// Dispatch the event.
+//
+// This will raise routed event of the control and its parent and parent's
+// parent ... (until "last_receiver" if it's not nullptr) with appropriate args.
+//
+// First tunnel from top to bottom possibly stopped by "handled" flag in
+// EventArgs. Second bubble from bottom to top possibly stopped by "handled"
+// flag in EventArgs. Last direct to each control.
+//
+// Args is of type "EventArgs". The first init argument is "sender", which is
+// automatically bound to each receiving control. The second init argument is
+// "original_sender", which is unchanged. And "args" will be perfectly forwarded
+// as the rest arguments.
+template <typename EventArgs, typename... Args>
+void DispatchEvent(Control* const original_sender,
+ event::RoutedEvent<EventArgs>* (Control::*event_ptr)(),
+ Control* const last_receiver, Args&&... args) {
+ std::list<Control*> receive_list;
+
+ auto parent = original_sender;
+ while (parent != last_receiver) {
+ receive_list.push_back(parent);
+ parent = parent->GetParent();
+ }
+
+ auto handled = false;
+
+ // tunnel
+ for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) {
+ EventArgs event_args(*i, original_sender, std::forward<Args>(args)...);
+ static_cast<Event<EventArgs>*>(((*i)->*event_ptr)()->tunnel.get())
+ ->Raise(event_args);
+ if (event_args.IsHandled()) {
+ handled = true;
+ break;
+ }
+ }
+
+ // bubble
+ if (!handled) {
+ for (auto i : receive_list) {
+ EventArgs event_args(i, original_sender, std::forward<Args>(args)...);
+ static_cast<Event<EventArgs>*>((i->*event_ptr)()->bubble.get())
+ ->Raise(event_args);
+ if (event_args.IsHandled()) break;
+ }
+ }
+
+ // direct
+ for (auto i : receive_list) {
+ EventArgs event_args(i, original_sender, std::forward<Args>(args)...);
+ static_cast<Event<EventArgs>*>((i->*event_ptr)()->direct.get())
+ ->Raise(event_args);
+ }
+}
+} // namespace cru::ui
diff --git a/src/ui/window.cpp b/src/ui/window.cpp
index 9eabc4a6..e17d603c 100644
--- a/src/ui/window.cpp
+++ b/src/ui/window.cpp
@@ -4,64 +4,12 @@
#include "cru/platform/native/native_window.hpp"
#include "cru/platform/native/ui_applicaition.hpp"
#include "cru/ui/render/window_render_object.hpp"
+#include "routed_event_dispatch.hpp"
#include <cassert>
namespace cru::ui {
namespace {
-// Dispatch the event.
-//
-// This will raise routed event of the control and its parent and parent's
-// parent ... (until "last_receiver" if it's not nullptr) with appropriate args.
-//
-// First tunnel from top to bottom possibly stopped by "handled" flag in
-// EventArgs. Second bubble from bottom to top possibly stopped by "handled"
-// flag in EventArgs. Last direct to each control.
-//
-// Args is of type "EventArgs". The first init argument is "sender", which is
-// automatically bound to each receiving control. The second init argument is
-// "original_sender", which is unchanged. And "args" will be perfectly forwarded
-// as the rest arguments.
-template <typename EventArgs, typename... Args>
-void DispatchEvent(Control* const original_sender,
- event::RoutedEvent<EventArgs>* (Control::*event_ptr)(),
- Control* const last_receiver, Args&&... args) {
- std::list<Control*> receive_list;
-
- auto parent = original_sender;
- while (parent != last_receiver) {
- receive_list.push_back(parent);
- parent = parent->GetParent();
- }
-
- auto handled = false;
-
- // tunnel
- for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) {
- EventArgs event_args(*i, original_sender, std::forward<Args>(args)...);
- (*i->*event_ptr)()->tunnel.Raise(event_args);
- if (event_args.IsHandled()) {
- handled = true;
- break;
- }
- }
-
- // bubble
- if (!handled) {
- for (auto i : receive_list) {
- EventArgs event_args(i, original_sender, std::forward<Args>(args)...);
- (i->*event_ptr)()->bubble.Raise(event_args);
- if (event_args.IsHandled()) break;
- }
- }
-
- // direct
- for (auto i : receive_list) {
- EventArgs event_args(i, original_sender, std::forward<Args>(args)...);
- (i->*event_ptr)()->direct.Raise(event_args);
- }
-}
-
std::list<Control*> GetAncestorList(Control* control) {
std::list<Control*> l;
while (control != nullptr) {
@@ -157,7 +105,7 @@ void Window::InvalidateLayout() {
window->Relayout();
window->need_layout_ = false;
}
- });
+ });
need_layout_ = true;
}
}