aboutsummaryrefslogtreecommitdiff
path: root/src/ui/controls
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2018-11-28 19:18:00 +0800
committercrupest <crupest@outlook.com>2018-11-28 19:18:00 +0800
commitf78458173c1baf567cc96880571b380e95a1039a (patch)
tree5bf790a573cff30071628329e1457e3affa0c2bc /src/ui/controls
parentee22597122612cd75fe62f5d808cb51478373fad (diff)
downloadcru-f78458173c1baf567cc96880571b380e95a1039a.tar.gz
cru-f78458173c1baf567cc96880571b380e95a1039a.tar.bz2
cru-f78458173c1baf567cc96880571b380e95a1039a.zip
Refactor event system.
Diffstat (limited to 'src/ui/controls')
-rw-r--r--src/ui/controls/list_item.cpp65
-rw-r--r--src/ui/controls/list_item.hpp7
-rw-r--r--src/ui/controls/popup_menu.cpp4
-rw-r--r--src/ui/controls/scroll_control.cpp245
-rw-r--r--src/ui/controls/scroll_control.hpp8
-rw-r--r--src/ui/controls/text_box.cpp220
-rw-r--r--src/ui/controls/text_box.hpp8
-rw-r--r--src/ui/controls/text_control.cpp208
-rw-r--r--src/ui/controls/text_control.hpp13
-rw-r--r--src/ui/controls/toggle_button.cpp74
-rw-r--r--src/ui/controls/toggle_button.hpp13
11 files changed, 395 insertions, 470 deletions
diff --git a/src/ui/controls/list_item.cpp b/src/ui/controls/list_item.cpp
index bf61010d..92f8750f 100644
--- a/src/ui/controls/list_item.cpp
+++ b/src/ui/controls/list_item.cpp
@@ -15,6 +15,39 @@ namespace cru::ui::controls
brushes_[State::Hover] .fill_brush = predefine_resources->list_item_hover_fill_brush;
brushes_[State::Select].border_brush = predefine_resources->list_item_select_border_brush;
brushes_[State::Select].fill_brush = predefine_resources->list_item_select_fill_brush;
+
+ draw_foreground_event.AddHandler([this](events::DrawEventArgs& args)
+ {
+ const auto device_context = args.GetDeviceContext();
+ const auto rect = Rect(Point::Zero(), GetRect(RectRange::Padding).GetSize());
+ device_context->FillRectangle(Convert(rect), brushes_[state_].fill_brush.Get());
+ device_context->DrawRectangle(Convert(rect.Shrink(Thickness(0.5))), brushes_[state_].border_brush.Get(), 1);
+ });
+
+ mouse_enter_event.bubble.AddHandler([this](events::MouseEventArgs& args)
+ {
+ if (GetState() == State::Select)
+ return;
+
+ if (IsAnyMouseButtonDown())
+ return;
+
+ SetState(State::Hover);
+ });
+
+ mouse_leave_event.bubble.AddHandler([this](events::MouseEventArgs& args)
+ {
+ if (GetState() == State::Select)
+ return;
+
+ SetState(State::Normal);
+ });
+
+ mouse_click_event.bubble.AddHandler([this](events::MouseButtonEventArgs& args)
+ {
+ if (args.GetMouseButton() == MouseButton::Left)
+ SetState(State::Select);
+ });
}
StringView ListItem::GetControlType() const
@@ -27,36 +60,4 @@ namespace cru::ui::controls
state_ = state;
InvalidateDraw();
}
-
- void ListItem::OnDrawForeground(ID2D1DeviceContext* device_context)
- {
- const auto rect = Rect(Point::Zero(), GetRect(RectRange::Padding).GetSize());
- device_context->FillRectangle(Convert(rect), brushes_[state_].fill_brush.Get());
- device_context->DrawRectangle(Convert(rect.Shrink(Thickness(0.5))), brushes_[state_].border_brush.Get(), 1);
- }
-
- void ListItem::OnMouseEnterCore(events::MouseEventArgs& args)
- {
- if (GetState() == State::Select)
- return;
-
- if (IsAnyMouseButtonDown())
- return;
-
- SetState(State::Hover);
- }
-
- void ListItem::OnMouseLeaveCore(events::MouseEventArgs& args)
- {
- if (GetState() == State::Select)
- return;
-
- SetState(State::Normal);
- }
-
- void ListItem::OnMouseClickCore(events::MouseButtonEventArgs& args)
- {
- if (args.GetMouseButton() == MouseButton::Left)
- SetState(State::Select);
- }
}
diff --git a/src/ui/controls/list_item.hpp b/src/ui/controls/list_item.hpp
index a77d13e6..e150efbb 100644
--- a/src/ui/controls/list_item.hpp
+++ b/src/ui/controls/list_item.hpp
@@ -56,13 +56,6 @@ namespace cru::ui::controls
void SetState(State state);
- protected:
- void OnDrawForeground(ID2D1DeviceContext* device_context) override;
-
- void OnMouseEnterCore(events::MouseEventArgs& args) override final;
- void OnMouseLeaveCore(events::MouseEventArgs& args) override final;
- void OnMouseClickCore(events::MouseButtonEventArgs& args) override final;
-
private:
State state_ = State::Normal;
std::map<State, StateBrush> brushes_{};
diff --git a/src/ui/controls/popup_menu.cpp b/src/ui/controls/popup_menu.cpp
index 88ea8f17..7f4b9d08 100644
--- a/src/ui/controls/popup_menu.cpp
+++ b/src/ui/controls/popup_menu.cpp
@@ -12,7 +12,7 @@ namespace cru::ui::controls
{
const auto popup = Window::CreatePopup(parent);
- popup->lose_focus_event.AddHandler([popup](events::FocusChangeEventArgs& args)
+ popup->lose_focus_event.bubble.AddHandler([popup](events::FocusChangeEventArgs& args)
{
if (args.IsWindow())
popup->Close();
@@ -29,7 +29,7 @@ namespace cru::ui::controls
ControlList{ text_block }
);
- list_item->mouse_click_event.AddHandler([popup, action](events::MouseButtonEventArgs& args)
+ list_item->mouse_click_event.bubble.AddHandler([popup, action](events::MouseButtonEventArgs& args)
{
if (args.GetMouseButton() == MouseButton::Left)
{
diff --git a/src/ui/controls/scroll_control.cpp b/src/ui/controls/scroll_control.cpp
index aa5403d4..07715892 100644
--- a/src/ui/controls/scroll_control.cpp
+++ b/src/ui/controls/scroll_control.cpp
@@ -17,6 +17,124 @@ namespace cru::ui::controls
ScrollControl::ScrollControl(const bool container) : Control(container)
{
SetClipContent(true);
+
+ draw_foreground_event.AddHandler([this](events::DrawEventArgs& args)
+ {
+ const auto device_context = args.GetDeviceContext();
+ const auto predefined = UiManager::GetInstance()->GetPredefineResources();
+
+ if (is_horizontal_scroll_bar_visible_)
+ {
+ device_context->FillRectangle(
+ Convert(horizontal_bar_info_.border),
+ predefined->scroll_bar_background_brush.Get()
+ );
+
+ device_context->FillRectangle(
+ Convert(horizontal_bar_info_.bar),
+ predefined->scroll_bar_brush.Get()
+ );
+
+ device_context->DrawLine(
+ Convert(horizontal_bar_info_.border.GetLeftTop()),
+ Convert(horizontal_bar_info_.border.GetRightTop()),
+ predefined->scroll_bar_border_brush.Get()
+ );
+ }
+
+ if (is_vertical_scroll_bar_visible_)
+ {
+ device_context->FillRectangle(
+ Convert(vertical_bar_info_.border),
+ predefined->scroll_bar_background_brush.Get()
+ );
+
+ device_context->FillRectangle(
+ Convert(vertical_bar_info_.bar),
+ predefined->scroll_bar_brush.Get()
+ );
+
+ device_context->DrawLine(
+ Convert(vertical_bar_info_.border.GetLeftTop()),
+ Convert(vertical_bar_info_.border.GetLeftBottom()),
+ predefined->scroll_bar_border_brush.Get()
+ );
+ }
+ });
+
+ mouse_down_event.bubble.AddHandler([this](events::MouseButtonEventArgs& args)
+ {
+ if (args.GetMouseButton() == MouseButton::Left)
+ {
+ const auto point = args.GetPoint(this);
+ if (is_vertical_scroll_bar_visible_ && vertical_bar_info_.bar.IsPointInside(point))
+ {
+ GetWindow()->CaptureMouseFor(this);
+ is_pressing_scroll_bar_ = Orientation::Vertical;
+ pressing_delta_ = point.y - vertical_bar_info_.bar.top;
+ return;
+ }
+
+ if (is_horizontal_scroll_bar_visible_ && horizontal_bar_info_.bar.IsPointInside(point))
+ {
+ GetWindow()->CaptureMouseFor(this);
+ pressing_delta_ = point.x - horizontal_bar_info_.bar.left;
+ is_pressing_scroll_bar_ = Orientation::Horizontal;
+ return;
+ }
+ }
+ });
+
+ mouse_move_event.bubble.AddHandler([this](events::MouseEventArgs& args)
+ {
+ const auto mouse_point = args.GetPoint(this);
+
+ if (is_pressing_scroll_bar_ == Orientation::Horizontal)
+ {
+ const auto new_head_position = mouse_point.x - pressing_delta_;
+ const auto new_offset = new_head_position / horizontal_bar_info_.border.width * view_width_;
+ SetScrollOffset(new_offset, std::nullopt);
+ return;
+ }
+
+ if (is_pressing_scroll_bar_ == Orientation::Vertical)
+ {
+ const auto new_head_position = mouse_point.y - pressing_delta_;
+ const auto new_offset = new_head_position / vertical_bar_info_.border.height * view_height_;
+ SetScrollOffset(std::nullopt, new_offset);
+ return;
+ }
+ });
+
+ mouse_up_event.bubble.AddHandler([this](events::MouseButtonEventArgs& args)
+ {
+ if (args.GetMouseButton() == MouseButton::Left && is_pressing_scroll_bar_.has_value())
+ {
+ GetWindow()->ReleaseCurrentMouseCapture();
+ is_pressing_scroll_bar_ = std::nullopt;
+ }
+ });
+
+ mouse_wheel_event.bubble.AddHandler([this](events::MouseWheelEventArgs& args)
+ {
+ constexpr const auto view_delta = 30.0f;
+
+ if (args.GetDelta() == 0.0f)
+ return;
+
+ const auto content_rect = GetRect(RectRange::Content);
+ if (IsVerticalScrollEnabled() && GetScrollOffsetY() != (args.GetDelta() > 0.0f ? 0.0f : AtLeast0(GetViewHeight() - content_rect.height)))
+ {
+ SetScrollOffset(std::nullopt, GetScrollOffsetY() - args.GetDelta() / WHEEL_DELTA * view_delta);
+ return;
+ }
+
+ if (IsHorizontalScrollEnabled() && GetScrollOffsetX() != (args.GetDelta() > 0.0f ? 0.0f : AtLeast0(GetViewWidth() - content_rect.width)))
+ {
+ SetScrollOffset(GetScrollOffsetX() - args.GetDelta() / WHEEL_DELTA * view_delta, std::nullopt);
+ return;
+ }
+ });
}
ScrollControl::~ScrollControl()
@@ -204,133 +322,6 @@ namespace cru::ui::controls
UpdateScrollBarVisibility();
}
- void ScrollControl::OnDrawForeground(ID2D1DeviceContext* device_context)
- {
- Control::OnDrawForeground(device_context);
-
- const auto predefined = UiManager::GetInstance()->GetPredefineResources();
-
- if (is_horizontal_scroll_bar_visible_)
- {
- device_context->FillRectangle(
- Convert(horizontal_bar_info_.border),
- predefined->scroll_bar_background_brush.Get()
- );
-
- device_context->FillRectangle(
- Convert(horizontal_bar_info_.bar),
- predefined->scroll_bar_brush.Get()
- );
-
- device_context->DrawLine(
- Convert(horizontal_bar_info_.border.GetLeftTop()),
- Convert(horizontal_bar_info_.border.GetRightTop()),
- predefined->scroll_bar_border_brush.Get()
- );
- }
-
- if (is_vertical_scroll_bar_visible_)
- {
- device_context->FillRectangle(
- Convert(vertical_bar_info_.border),
- predefined->scroll_bar_background_brush.Get()
- );
-
- device_context->FillRectangle(
- Convert(vertical_bar_info_.bar),
- predefined->scroll_bar_brush.Get()
- );
-
- device_context->DrawLine(
- Convert(vertical_bar_info_.border.GetLeftTop()),
- Convert(vertical_bar_info_.border.GetLeftBottom()),
- predefined->scroll_bar_border_brush.Get()
- );
- }
- }
-
- void ScrollControl::OnMouseDownCore(events::MouseButtonEventArgs& args)
- {
- Control::OnMouseDownCore(args);
-
- if (args.GetMouseButton() == MouseButton::Left)
- {
- const auto point = args.GetPoint(this);
- if (is_vertical_scroll_bar_visible_ && vertical_bar_info_.bar.IsPointInside(point))
- {
- GetWindow()->CaptureMouseFor(this);
- is_pressing_scroll_bar_ = Orientation::Vertical;
- pressing_delta_ = point.y - vertical_bar_info_.bar.top;
- return;
- }
-
- if (is_horizontal_scroll_bar_visible_ && horizontal_bar_info_.bar.IsPointInside(point))
- {
- GetWindow()->CaptureMouseFor(this);
- pressing_delta_ = point.x - horizontal_bar_info_.bar.left;
- is_pressing_scroll_bar_ = Orientation::Horizontal;
- return;
- }
- }
- }
-
- void ScrollControl::OnMouseMoveCore(events::MouseEventArgs& args)
- {
- Control::OnMouseMoveCore(args);
-
- const auto mouse_point = args.GetPoint(this);
-
- if (is_pressing_scroll_bar_ == Orientation::Horizontal)
- {
- const auto new_head_position = mouse_point.x - pressing_delta_;
- const auto new_offset = new_head_position / horizontal_bar_info_.border.width * view_width_;
- SetScrollOffset(new_offset, std::nullopt);
- return;
- }
-
- if (is_pressing_scroll_bar_ == Orientation::Vertical)
- {
- const auto new_head_position = mouse_point.y - pressing_delta_;
- const auto new_offset = new_head_position / vertical_bar_info_.border.height * view_height_;
- SetScrollOffset(std::nullopt, new_offset);
- return;
- }
- }
-
- void ScrollControl::OnMouseUpCore(events::MouseButtonEventArgs& args)
- {
- Control::OnMouseUpCore(args);
-
- if (args.GetMouseButton() == MouseButton::Left && is_pressing_scroll_bar_.has_value())
- {
- GetWindow()->ReleaseCurrentMouseCapture();
- is_pressing_scroll_bar_ = std::nullopt;
- }
- }
-
- void ScrollControl::OnMouseWheelCore(events::MouseWheelEventArgs& args)
- {
- Control::OnMouseWheelCore(args);
-
- constexpr const auto view_delta = 30.0f;
-
- if (args.GetDelta() == 0.0f)
- return;
-
- const auto content_rect = GetRect(RectRange::Content);
- if (IsVerticalScrollEnabled() && GetScrollOffsetY() != (args.GetDelta() > 0.0f ? 0.0f : AtLeast0(GetViewHeight() - content_rect.height)))
- {
- SetScrollOffset(std::nullopt, GetScrollOffsetY() - args.GetDelta() / WHEEL_DELTA * view_delta);
- return;
- }
-
- if (IsHorizontalScrollEnabled() && GetScrollOffsetX() != (args.GetDelta() > 0.0f ? 0.0f : AtLeast0(GetViewWidth() - content_rect.width)))
- {
- SetScrollOffset(GetScrollOffsetX() - args.GetDelta() / WHEEL_DELTA * view_delta, std::nullopt);
- return;
- }
- }
-
void ScrollControl::CoerceAndSetOffsets(const float offset_x, const float offset_y, const bool update_children)
{
const auto old_offset_x = offset_x_;
diff --git a/src/ui/controls/scroll_control.hpp b/src/ui/controls/scroll_control.hpp
index 0541a010..4eabc605 100644
--- a/src/ui/controls/scroll_control.hpp
+++ b/src/ui/controls/scroll_control.hpp
@@ -122,14 +122,6 @@ namespace cru::ui::controls
void AfterLayoutSelf() override;
- void OnDrawForeground(ID2D1DeviceContext* device_context) override;
-
- void OnMouseDownCore(events::MouseButtonEventArgs& args) override final;
- void OnMouseMoveCore(events::MouseEventArgs& args) override final;
- void OnMouseUpCore(events::MouseButtonEventArgs& args) override final;
-
- void OnMouseWheelCore(events::MouseWheelEventArgs& args) override;
-
private:
void CoerceAndSetOffsets(float offset_x, float offset_y, bool update_children = true);
void UpdateScrollBarVisibility();
diff --git a/src/ui/controls/text_box.cpp b/src/ui/controls/text_box.cpp
index 83311548..28e1053d 100644
--- a/src/ui/controls/text_box.cpp
+++ b/src/ui/controls/text_box.cpp
@@ -20,149 +20,145 @@ namespace cru::ui::controls
GetBorderProperty() = UiManager::GetInstance()->GetPredefineResources()->text_box_border;
SetBordered(true);
- }
-
- TextBox::~TextBox() = default;
- StringView TextBox::GetControlType() const
- {
- return control_type;
- }
-
- void TextBox::OnDrawContent(ID2D1DeviceContext* device_context)
- {
- TextControl::OnDrawContent(device_context);
- if (is_caret_show_)
+ draw_content_event.AddHandler([this](events::DrawEventArgs& args)
{
- const auto caret_half_width = UiManager::GetInstance()->GetCaretInfo().half_caret_width;
- FLOAT x, y;
- DWRITE_HIT_TEST_METRICS metrics{};
- ThrowIfFailed(text_layout_->HitTestTextPosition(caret_position_, FALSE, &x, &y, &metrics));
- device_context->FillRectangle(D2D1::RectF(metrics.left - caret_half_width, metrics.top, metrics.left + caret_half_width, metrics.top + metrics.height), caret_brush_.Get());
- }
- }
+ const auto device_context = args.GetDeviceContext();
+ if (is_caret_show_)
+ {
+ const auto caret_half_width = UiManager::GetInstance()->GetCaretInfo().half_caret_width;
+ FLOAT x, y;
+ DWRITE_HIT_TEST_METRICS metrics{};
+ ThrowIfFailed(text_layout_->HitTestTextPosition(caret_position_, FALSE, &x, &y, &metrics));
+ device_context->FillRectangle(D2D1::RectF(metrics.left - caret_half_width, metrics.top, metrics.left + caret_half_width, metrics.top + metrics.height), caret_brush_.Get());
+ }
+ });
- void TextBox::OnGetFocusCore(events::FocusChangeEventArgs& args)
- {
- TextControl::OnGetFocusCore(args);
- assert(!caret_timer_.has_value());
- is_caret_show_ = true;
- caret_timer_ = SetInterval(UiManager::GetInstance()->GetCaretInfo().caret_blink_duration, [this]
+ get_focus_event.bubble.AddHandler([this](events::FocusChangeEventArgs& args)
{
- is_caret_show_ = !is_caret_show_;
- InvalidateDraw();
+ assert(!caret_timer_.has_value());
+ is_caret_show_ = true;
+ caret_timer_ = SetInterval(UiManager::GetInstance()->GetCaretInfo().caret_blink_duration, [this]
+ {
+ is_caret_show_ = !is_caret_show_;
+ InvalidateDraw();
+ });
});
- }
- void TextBox::OnLoseFocusCore(events::FocusChangeEventArgs& args)
- {
- Control::OnLoseFocusCore(args);
- assert(caret_timer_.has_value());
- caret_timer_->Cancel();
- caret_timer_ = std::nullopt;
- is_caret_show_ = false;
- }
+ lose_focus_event.bubble.AddHandler([this](events::FocusChangeEventArgs& args)
+ {
+ assert(caret_timer_.has_value());
+ caret_timer_->Cancel();
+ caret_timer_ = std::nullopt;
+ is_caret_show_ = false;
+ });
- void TextBox::OnKeyDownCore(events::KeyEventArgs& args)
- {
- Control::OnKeyDownCore(args);
- if (args.GetVirtualCode() == VK_LEFT && caret_position_ > 0)
+ key_down_event.bubble.AddHandler([this](events::KeyEventArgs& args)
{
- if (IsKeyDown(VK_SHIFT))
+ if (args.GetVirtualCode() == VK_LEFT && caret_position_ > 0)
{
- if (GetCaretSelectionSide())
- ShiftLeftSelectionRange(-1);
- else
- ShiftRightSelectionRange(-1);
- }
- else
- {
- const auto selection = GetSelectedRange();
- if (selection.has_value())
+ if (IsKeyDown(VK_SHIFT))
{
- ClearSelection();
- caret_position_ = selection.value().position;
+ if (GetCaretSelectionSide())
+ ShiftLeftSelectionRange(-1);
+ else
+ ShiftRightSelectionRange(-1);
}
else
- caret_position_--;
+ {
+ const auto selection = GetSelectedRange();
+ if (selection.has_value())
+ {
+ ClearSelection();
+ caret_position_ = selection.value().position;
+ }
+ else
+ caret_position_--;
+ }
+ InvalidateDraw();
}
- InvalidateDraw();
- }
- if (args.GetVirtualCode() == VK_RIGHT && caret_position_ < GetText().size())
- {
- if (IsKeyDown(VK_SHIFT))
+ if (args.GetVirtualCode() == VK_RIGHT && caret_position_ < GetText().size())
{
- if (GetCaretSelectionSide())
- ShiftLeftSelectionRange(1);
- else
- ShiftRightSelectionRange(1);
- }
- else
- {
- const auto selection = GetSelectedRange();
- if (selection.has_value())
+ if (IsKeyDown(VK_SHIFT))
{
- ClearSelection();
- caret_position_ = selection.value().position + selection.value().count;
+ if (GetCaretSelectionSide())
+ ShiftLeftSelectionRange(1);
+ else
+ ShiftRightSelectionRange(1);
}
else
- caret_position_++;
+ {
+ const auto selection = GetSelectedRange();
+ if (selection.has_value())
+ {
+ ClearSelection();
+ caret_position_ = selection.value().position + selection.value().count;
+ }
+ else
+ caret_position_++;
+ }
}
- }
- }
+ });
- void TextBox::OnCharCore(events::CharEventArgs& args)
- {
- Control::OnCharCore(args);
- if (args.GetChar() == L'\b')
+ char_event.bubble.AddHandler([this](events::CharEventArgs& args)
{
- if (GetSelectedRange().has_value())
- {
- const auto selection_range = GetSelectedRange().value();
- auto text = GetText();
- text.erase(text.cbegin() + selection_range.position, text.cbegin() + selection_range.position + selection_range.count);
- SetText(text);
- caret_position_ = selection_range.position;
- ClearSelection();
- }
- else
+ if (args.GetChar() == L'\b')
{
- if (caret_position_ > 0)
+ if (GetSelectedRange().has_value())
{
+ const auto selection_range = GetSelectedRange().value();
auto text = GetText();
- if (!text.empty())
+ text.erase(text.cbegin() + selection_range.position, text.cbegin() + selection_range.position + selection_range.count);
+ SetText(text);
+ caret_position_ = selection_range.position;
+ ClearSelection();
+ }
+ else
+ {
+ if (caret_position_ > 0)
{
- const auto position = --caret_position_;
- text.erase(text.cbegin() + position);
- SetText(text);
+ auto text = GetText();
+ if (!text.empty())
+ {
+ const auto position = --caret_position_;
+ text.erase(text.cbegin() + position);
+ SetText(text);
+ }
}
}
+ return;
}
- return;
- }
- if (std::iswprint(args.GetChar()))
- {
- if (GetSelectedRange().has_value())
- {
- const auto selection_range = GetSelectedRange().value();
- auto text = GetText();
- text.erase(selection_range.position, selection_range.count);
- text.insert(text.cbegin() + selection_range.position, args.GetChar());
- SetText(text);
- caret_position_ = selection_range.position + 1;
- ClearSelection();
- }
- else
+ if (std::iswprint(args.GetChar()))
{
- ClearSelection();
- const auto position = caret_position_++;
- auto text = GetText();
- text.insert(text.cbegin() + position, { args.GetChar() });
- SetText(text);
+ if (GetSelectedRange().has_value())
+ {
+ const auto selection_range = GetSelectedRange().value();
+ auto text = GetText();
+ text.erase(selection_range.position, selection_range.count);
+ text.insert(text.cbegin() + selection_range.position, args.GetChar());
+ SetText(text);
+ caret_position_ = selection_range.position + 1;
+ ClearSelection();
+ }
+ else
+ {
+ ClearSelection();
+ const auto position = caret_position_++;
+ auto text = GetText();
+ text.insert(text.cbegin() + position, { args.GetChar() });
+ SetText(text);
+ }
}
- }
+ });
+ }
+
+ TextBox::~TextBox() = default;
+
+ StringView TextBox::GetControlType() const
+ {
+ return control_type;
}
void TextBox::RequestChangeCaretPosition(const unsigned position)
diff --git a/src/ui/controls/text_box.hpp b/src/ui/controls/text_box.hpp
index 3a30ecb2..e5cd7545 100644
--- a/src/ui/controls/text_box.hpp
+++ b/src/ui/controls/text_box.hpp
@@ -30,14 +30,6 @@ namespace cru::ui::controls
StringView GetControlType() const override final;
protected:
- void OnDrawContent(ID2D1DeviceContext* device_context) override;
-
- void OnGetFocusCore(events::FocusChangeEventArgs& args) override final;
- void OnLoseFocusCore(events::FocusChangeEventArgs& args) override final;
-
- void OnKeyDownCore(events::KeyEventArgs& args) override final;
- void OnCharCore(events::CharEventArgs& args) override final;
-
void RequestChangeCaretPosition(unsigned position) override final;
private:
diff --git a/src/ui/controls/text_control.cpp b/src/ui/controls/text_control.cpp
index d7d6b810..71a167e2 100644
--- a/src/ui/controls/text_control.cpp
+++ b/src/ui/controls/text_control.cpp
@@ -9,6 +9,40 @@
namespace cru::ui::controls
{
+ namespace
+ {
+ unsigned TextLayoutHitTest(IDWriteTextLayout* text_layout, const Point& point)
+ {
+ BOOL is_trailing, is_inside;
+ DWRITE_HIT_TEST_METRICS metrics{};
+ text_layout->HitTestPoint(point.x, point.y, &is_trailing, &is_inside, &metrics);
+ return is_trailing == 0 ? metrics.textPosition : metrics.textPosition + 1;
+ }
+
+ void DrawSelectionRect(ID2D1DeviceContext* device_context, IDWriteTextLayout* layout, ID2D1Brush* brush, const std::optional<TextRange> range)
+ {
+ if (range.has_value())
+ {
+ DWRITE_TEXT_METRICS text_metrics{};
+ ThrowIfFailed(layout->GetMetrics(&text_metrics));
+ const auto metrics_count = text_metrics.lineCount * text_metrics.maxBidiReorderingDepth;
+
+ std::vector<DWRITE_HIT_TEST_METRICS> hit_test_metrics(metrics_count);
+ UINT32 actual_count;
+ layout->HitTestTextRange(
+ range.value().position, range.value().count,
+ 0, 0,
+ hit_test_metrics.data(), metrics_count, &actual_count
+ );
+
+ hit_test_metrics.erase(hit_test_metrics.cbegin() + actual_count, hit_test_metrics.cend());
+
+ for (const auto& metrics : hit_test_metrics)
+ device_context->FillRoundedRectangle(D2D1::RoundedRect(D2D1::RectF(metrics.left, metrics.top, metrics.left + metrics.width, metrics.top + metrics.height), 3, 3), brush);
+ }
+ }
+ }
+
TextControl::TextControl(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format,
const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush) : Control(false)
{
@@ -21,6 +55,74 @@ namespace cru::ui::controls
selection_brush_ = UiManager::GetInstance()->GetPredefineResources()->text_control_selection_brush;
SetClipContent(true);
+
+ size_changed_event.AddHandler([this](events::SizeChangedEventArgs& args)
+ {
+ const auto content = GetRect(RectRange::Content);
+ ThrowIfFailed(text_layout_->SetMaxWidth(content.width));
+ ThrowIfFailed(text_layout_->SetMaxHeight(content.height));
+ InvalidateDraw();
+ });
+
+ draw_content_event.AddHandler([this](events::DrawEventArgs& args)
+ {
+ const auto device_context = args.GetDeviceContext();
+ DrawSelectionRect(device_context, text_layout_.Get(), selection_brush_.Get(), selected_range_);
+ device_context->DrawTextLayout(D2D1::Point2F(), text_layout_.Get(), brush_.Get());
+ });
+
+ mouse_down_event.bubble.AddHandler([this](events::MouseButtonEventArgs& args)
+ {
+ if (is_selectable_ && args.GetMouseButton() == MouseButton::Left && GetRect(RectRange::Padding).IsPointInside(args.GetPoint(this, RectRange::Margin)))
+ {
+ selected_range_ = std::nullopt;
+ const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this));
+ RequestChangeCaretPosition(hit_test_result);
+ mouse_down_position_ = hit_test_result;
+ is_selecting_ = true;
+ GetWindow()->CaptureMouseFor(this);
+ InvalidateDraw();
+ }
+ });
+
+ mouse_move_event.bubble.AddHandler([this](events::MouseEventArgs& args)
+ {
+ if (is_selecting_)
+ {
+ const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this));
+ RequestChangeCaretPosition(hit_test_result);
+ selected_range_ = TextRange::FromTwoSides(hit_test_result, mouse_down_position_);
+ InvalidateDraw();
+ }
+ UpdateCursor(args.GetPoint(this, RectRange::Margin));
+ });
+
+
+ mouse_up_event.bubble.AddHandler([this](events::MouseButtonEventArgs& args)
+ {
+ if (args.GetMouseButton() == MouseButton::Left)
+ {
+ if (is_selecting_)
+ {
+ is_selecting_ = false;
+ GetWindow()->ReleaseCurrentMouseCapture();
+ }
+ }
+ });
+
+ lose_focus_event.bubble.AddHandler([this](events::FocusChangeEventArgs& args)
+ {
+ if (is_selecting_)
+ {
+ is_selecting_ = false;
+ GetWindow()->ReleaseCurrentMouseCapture();
+ }
+ if (!args.IsWindow()) // If the focus lose is triggered window-wide, then save the selection state. Otherwise, clear selection.
+ {
+ selected_range_ = std::nullopt;
+ InvalidateDraw();
+ }
+ });
}
@@ -75,112 +177,6 @@ namespace cru::ui::controls
}
}
- void TextControl::OnSizeChangedCore(events::SizeChangedEventArgs& args)
- {
- Control::OnSizeChangedCore(args);
- const auto content = GetRect(RectRange::Content);
- ThrowIfFailed(text_layout_->SetMaxWidth(content.width));
- ThrowIfFailed(text_layout_->SetMaxHeight(content.height));
- InvalidateDraw();
- }
-
- namespace
- {
- unsigned TextLayoutHitTest(IDWriteTextLayout* text_layout, const Point& point)
- {
- BOOL is_trailing, is_inside;
- DWRITE_HIT_TEST_METRICS metrics{};
- text_layout->HitTestPoint(point.x, point.y, &is_trailing, &is_inside, &metrics);
- return is_trailing == 0 ? metrics.textPosition : metrics.textPosition + 1;
- }
-
- void DrawSelectionRect(ID2D1DeviceContext* device_context, IDWriteTextLayout* layout, ID2D1Brush* brush, const std::optional<TextRange> range)
- {
- if (range.has_value())
- {
- DWRITE_TEXT_METRICS text_metrics{};
- ThrowIfFailed(layout->GetMetrics(&text_metrics));
- const auto metrics_count = text_metrics.lineCount * text_metrics.maxBidiReorderingDepth;
-
- std::vector<DWRITE_HIT_TEST_METRICS> hit_test_metrics(metrics_count);
- UINT32 actual_count;
- layout->HitTestTextRange(
- range.value().position, range.value().count,
- 0, 0,
- hit_test_metrics.data(), metrics_count, &actual_count
- );
-
- hit_test_metrics.erase(hit_test_metrics.cbegin() + actual_count, hit_test_metrics.cend());
-
- for (const auto& metrics : hit_test_metrics)
- device_context->FillRoundedRectangle(D2D1::RoundedRect(D2D1::RectF(metrics.left, metrics.top, metrics.left + metrics.width, metrics.top + metrics.height), 3, 3), brush);
- }
- }
- }
- void TextControl::OnDrawContent(ID2D1DeviceContext* device_context)
- {
- Control::OnDrawContent(device_context);
- DrawSelectionRect(device_context, text_layout_.Get(), selection_brush_.Get(), selected_range_);
- device_context->DrawTextLayout(D2D1::Point2F(), text_layout_.Get(), brush_.Get());
- }
-
- void TextControl::OnMouseDownCore(events::MouseButtonEventArgs& args)
- {
- Control::OnMouseDownCore(args);
- if (is_selectable_ && args.GetMouseButton() == MouseButton::Left && GetRect(RectRange::Padding).IsPointInside(args.GetPoint(this, RectRange::Margin)))
- {
- selected_range_ = std::nullopt;
- const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this));
- RequestChangeCaretPosition(hit_test_result);
- mouse_down_position_ = hit_test_result;
- is_selecting_ = true;
- GetWindow()->CaptureMouseFor(this);
- InvalidateDraw();
- }
- }
-
- void TextControl::OnMouseMoveCore(events::MouseEventArgs& args)
- {
- Control::OnMouseMoveCore(args);
- if (is_selecting_)
- {
- const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this));
- RequestChangeCaretPosition(hit_test_result);
- selected_range_ = TextRange::FromTwoSides(hit_test_result, mouse_down_position_);
- InvalidateDraw();
- }
- UpdateCursor(args.GetPoint(this, RectRange::Margin));
- }
-
- void TextControl::OnMouseUpCore(events::MouseButtonEventArgs& args)
- {
- Control::OnMouseUpCore(args);
- if (args.GetMouseButton() == MouseButton::Left)
- {
- if (is_selecting_)
- {
- is_selecting_ = false;
- GetWindow()->ReleaseCurrentMouseCapture();
- }
- }
- }
-
- void TextControl::OnLoseFocusCore(events::FocusChangeEventArgs& args)
- {
- Control::OnLoseFocusCore(args);
- if (is_selecting_)
- {
- is_selecting_ = false;
- GetWindow()->ReleaseCurrentMouseCapture();
- }
- if (!args.IsWindow()) // If the focus lose is triggered window-wide, then save the selection state. Otherwise, clear selection.
- {
- selected_range_ = std::nullopt;
- InvalidateDraw();
- }
- }
-
-
Size TextControl::OnMeasureContent(const Size& available_size)
{
ThrowIfFailed(text_layout_->SetMaxWidth(available_size.width));
diff --git a/src/ui/controls/text_control.hpp b/src/ui/controls/text_control.hpp
index 762d85f3..1e4c985d 100644
--- a/src/ui/controls/text_control.hpp
+++ b/src/ui/controls/text_control.hpp
@@ -62,18 +62,7 @@ namespace cru::ui::controls
protected:
void SetSelectable(bool is_selectable);
- protected:
- void OnSizeChangedCore(events::SizeChangedEventArgs& args) override final;
- void OnDrawContent(ID2D1DeviceContext* device_context) override;
-
- void OnMouseDownCore(events::MouseButtonEventArgs& args) override final;
- void OnMouseMoveCore(events::MouseEventArgs& args) override final;
- void OnMouseUpCore(events::MouseButtonEventArgs& args) override final;
-
- void OnLoseFocusCore(events::FocusChangeEventArgs& args) override;
-
- Size OnMeasureContent(const Size& available_size) override;
-
+ Size OnMeasureContent(const Size& available_size) override final;
virtual void RequestChangeCaretPosition(unsigned position);
diff --git a/src/ui/controls/toggle_button.cpp b/src/ui/controls/toggle_button.cpp
index e3d8662a..874a245f 100644
--- a/src/ui/controls/toggle_button.cpp
+++ b/src/ui/controls/toggle_button.cpp
@@ -3,6 +3,7 @@
#include "graph/graph.hpp"
#include "ui/animations/animation.hpp"
#include "ui/ui_manager.hpp"
+#include "ui/convert_util.hpp"
namespace cru::ui::controls
{
@@ -21,13 +22,34 @@ namespace cru::ui::controls
on_brush_ = UiManager::GetInstance()->GetPredefineResources()->toggle_button_on_brush;
off_brush_ = UiManager::GetInstance()->GetPredefineResources()->toggle_button_off_brush;
- }
- inline D2D1_POINT_2F ConvertPoint(const Point& point)
- {
- return D2D1::Point2F(point.x, point.y);
+ draw_content_event.AddHandler([this](events::DrawEventArgs& args)
+ {
+ const auto device_context = args.GetDeviceContext();
+ const auto size = GetSize();
+ graph::WithTransform(device_context, D2D1::Matrix3x2F::Translation(size.width / 2, size.height / 2), [this](ID2D1DeviceContext* device_context)
+ {
+ if (state_)
+ {
+ device_context->DrawGeometry(frame_path_.Get(), on_brush_.Get(), stroke_width);
+ device_context->FillEllipse(D2D1::Ellipse(D2D1::Point2F(current_circle_position_, 0), inner_circle_radius, inner_circle_radius), on_brush_.Get());
+ }
+ else
+ {
+ device_context->DrawGeometry(frame_path_.Get(), off_brush_.Get(), stroke_width);
+ device_context->FillEllipse(D2D1::Ellipse(D2D1::Point2F(current_circle_position_, 0), inner_circle_radius, inner_circle_radius), off_brush_.Get());
+ }
+ });
+ });
+
+ mouse_click_event.bubble.AddHandler([this](events::MouseButtonEventArgs& args)
+ {
+ if (args.GetMouseButton() == MouseButton::Left)
+ Toggle();
+ });
}
+
StringView ToggleButton::GetControlType() const
{
return control_type;
@@ -38,9 +60,9 @@ namespace cru::ui::controls
const auto size = GetSize();
const auto transform = D2D1::Matrix3x2F::Translation(size.width / 2, size.height / 2);
BOOL contains;
- frame_path_->FillContainsPoint(ConvertPoint(point), transform, &contains);
+ frame_path_->FillContainsPoint(Convert(point), transform, &contains);
if (!contains)
- frame_path_->StrokeContainsPoint(ConvertPoint(point), stroke_width, nullptr, transform, &contains);
+ frame_path_->StrokeContainsPoint(Convert(point), stroke_width, nullptr, transform, &contains);
return contains != 0;
}
@@ -72,7 +94,8 @@ namespace cru::ui::controls
})
.Start();
- RaiseToggleEvent(state);
+ events::ToggleEventArgs args(this, this, state);
+ toggle_event.Raise(args);
InvalidateDraw();
}
}
@@ -82,36 +105,6 @@ namespace cru::ui::controls
SetState(!GetState());
}
- void ToggleButton::OnToggle(events::ToggleEventArgs& args)
- {
-
- }
-
- void ToggleButton::OnDrawContent(ID2D1DeviceContext* device_context)
- {
- Control::OnDrawContent(device_context);
- const auto size = GetSize();
- graph::WithTransform(device_context, D2D1::Matrix3x2F::Translation(size.width / 2, size.height / 2), [this](ID2D1DeviceContext* device_context)
- {
- if (state_)
- {
- device_context->DrawGeometry(frame_path_.Get(), on_brush_.Get(), stroke_width);
- device_context->FillEllipse(D2D1::Ellipse(D2D1::Point2F(current_circle_position_, 0), inner_circle_radius, inner_circle_radius), on_brush_.Get());
- }
- else
- {
- device_context->DrawGeometry(frame_path_.Get(), off_brush_.Get(), stroke_width);
- device_context->FillEllipse(D2D1::Ellipse(D2D1::Point2F(current_circle_position_, 0), inner_circle_radius, inner_circle_radius), off_brush_.Get());
- }
- });
- }
-
- void ToggleButton::OnMouseClickCore(events::MouseButtonEventArgs& args)
- {
- Control::OnMouseClickCore(args);
- Toggle();
- }
-
Size ToggleButton::OnMeasureContent(const Size& available_size)
{
const Size result_size(
@@ -121,11 +114,4 @@ namespace cru::ui::controls
return result_size;
}
-
- void ToggleButton::RaiseToggleEvent(bool new_state)
- {
- events::ToggleEventArgs args(this, this, new_state);
- OnToggle(args);
- toggle_event.Raise(args);
- }
}
diff --git a/src/ui/controls/toggle_button.hpp b/src/ui/controls/toggle_button.hpp
index 4cbb4f37..8b7402c8 100644
--- a/src/ui/controls/toggle_button.hpp
+++ b/src/ui/controls/toggle_button.hpp
@@ -40,23 +40,12 @@ namespace cru::ui::controls
void Toggle();
- public:
- events::ToggleEvent toggle_event;
-
- protected:
- virtual void OnToggle(events::ToggleEventArgs& args);
+ Event<events::ToggleEventArgs> toggle_event;
protected:
- void OnDrawContent(ID2D1DeviceContext* device_context) override;
-
- void OnMouseClickCore(events::MouseButtonEventArgs& args) override;
-
Size OnMeasureContent(const Size& available_size) override;
private:
- void RaiseToggleEvent(bool new_state);
-
- private:
bool state_ = false;
float current_circle_position_;