aboutsummaryrefslogtreecommitdiff
path: root/CruUI/ui/controls
diff options
context:
space:
mode:
Diffstat (limited to 'CruUI/ui/controls')
-rw-r--r--CruUI/ui/controls/button.cpp33
-rw-r--r--CruUI/ui/controls/button.h41
-rw-r--r--CruUI/ui/controls/linear_layout.cpp178
-rw-r--r--CruUI/ui/controls/linear_layout.h41
-rw-r--r--CruUI/ui/controls/margin_container.cpp63
-rw-r--r--CruUI/ui/controls/margin_container.h44
-rw-r--r--CruUI/ui/controls/text_block.cpp283
-rw-r--r--CruUI/ui/controls/text_block.h116
-rw-r--r--CruUI/ui/controls/text_box.cpp244
-rw-r--r--CruUI/ui/controls/text_box.h85
-rw-r--r--CruUI/ui/controls/toggle_button.cpp150
-rw-r--r--CruUI/ui/controls/toggle_button.h61
12 files changed, 0 insertions, 1339 deletions
diff --git a/CruUI/ui/controls/button.cpp b/CruUI/ui/controls/button.cpp
deleted file mode 100644
index b7614f93..00000000
--- a/CruUI/ui/controls/button.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "button.h"
-
-#include "graph/graph.h"
-
-namespace cru::ui::controls
-{
- using graph::CreateSolidBrush;
-
- Button::Button() : Control(true)
- {
- normal_border_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::RoyalBlue));
- pressed_border_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::MediumBlue));
- current_border_brush_ = normal_border_brush_.Get();
- }
-
- void Button::OnDraw(ID2D1DeviceContext* device_context)
- {
- Control::OnDraw(device_context);
- device_context->DrawRoundedRectangle(D2D1::RoundedRect(D2D1::RectF(0, 0, GetSize().width, GetSize().height), 6, 6), current_border_brush_, 2);
- }
-
- void Button::OnMouseClickBegin(MouseButton button)
- {
- current_border_brush_ = pressed_border_brush_.Get();
- Repaint();
- }
-
- void Button::OnMouseClickEnd(MouseButton button)
- {
- current_border_brush_ = normal_border_brush_.Get();
- Repaint();
- }
-}
diff --git a/CruUI/ui/controls/button.h b/CruUI/ui/controls/button.h
deleted file mode 100644
index bd3f6eb3..00000000
--- a/CruUI/ui/controls/button.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#pragma once
-
-#include <initializer_list>
-
-#include "ui/control.h"
-
-namespace cru::ui::controls
-{
- class Button : public Control
- {
- public:
- static Button* Create(const std::initializer_list<Control*>& children = std::initializer_list<Control*>())
- {
- const auto button = new Button();
- for (const auto control : children)
- button->AddChild(control);
- return button;
- }
-
- protected:
- Button();
-
- public:
- Button(const Button& other) = delete;
- Button(Button&& other) = delete;
- Button& operator=(const Button& other) = delete;
- Button& operator=(Button&& other) = delete;
- ~Button() override = default;
-
- protected:
- void OnDraw(ID2D1DeviceContext* device_context) override;
-
- void OnMouseClickBegin(MouseButton button) override final;
- void OnMouseClickEnd(MouseButton button) override final;
-
- private:
- Microsoft::WRL::ComPtr<ID2D1Brush> normal_border_brush_;
- Microsoft::WRL::ComPtr<ID2D1Brush> pressed_border_brush_;
- ID2D1Brush* current_border_brush_;
- };
-}
diff --git a/CruUI/ui/controls/linear_layout.cpp b/CruUI/ui/controls/linear_layout.cpp
deleted file mode 100644
index 8f537ea8..00000000
--- a/CruUI/ui/controls/linear_layout.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-#include "linear_layout.h"
-
-namespace cru::ui::controls
-{
- LinearLayout::LinearLayout(const Orientation orientation)
- : Control(true), orientation_(orientation)
- {
-
- }
-
- inline float AtLeast0(const float value)
- {
- return value < 0 ? 0 : value;
- }
-
- inline Size AtLeast0(const Size& size)
- {
- return Size(AtLeast0(size.width), AtLeast0(size.height));
- }
-
- Size LinearLayout::OnMeasure(const Size& available_size)
- {
- const auto layout_params = GetLayoutParams();
-
- if (!layout_params->Validate())
- throw std::runtime_error("LayoutParams is not valid. Please check it.");
-
- auto&& get_available_length_for_child = [](const LayoutSideParams& layout_length, const float available_length) -> float
- {
- switch (layout_length.mode)
- {
- case MeasureMode::Exactly:
- {
- return std::min(layout_length.length, available_length);
- }
- case MeasureMode::Stretch:
- case MeasureMode::Content:
- {
- return available_length;
- }
- default:
- UnreachableCode();
- }
- };
-
- Size total_available_size_for_children(
- get_available_length_for_child(layout_params->width, available_size.width),
- get_available_length_for_child(layout_params->height, available_size.height)
- );
-
- auto rest_available_size_for_children = total_available_size_for_children;
-
- float secondary_side_child_max_length = 0;
-
- std::list<Control*> stretch_control_list;
-
- // First measure Content and Exactly and count Stretch.
- if (orientation_ == Orientation::Horizontal)
- ForeachChild([&](Control* const control)
- {
- const auto mode = control->GetLayoutParams()->width.mode;
- if (mode == MeasureMode::Content || mode == MeasureMode::Exactly)
- {
- control->Measure(AtLeast0(rest_available_size_for_children));
- const auto size = control->GetDesiredSize();
- rest_available_size_for_children.width -= size.width;
- secondary_side_child_max_length = std::max(size.height, secondary_side_child_max_length);
- }
- else
- stretch_control_list.push_back(control);
- });
- else
- ForeachChild([&](Control* const control)
- {
- const auto mode = control->GetLayoutParams()->height.mode;
- if (mode == MeasureMode::Content || mode == MeasureMode::Exactly)
- {
- control->Measure(AtLeast0(rest_available_size_for_children));
- const auto size = control->GetDesiredSize();
- rest_available_size_for_children.height -= size.height;
- secondary_side_child_max_length = std::max(size.width, secondary_side_child_max_length);
- }
- else
- stretch_control_list.push_back(control);
- });
-
- if (orientation_ == Orientation::Horizontal)
- {
- const auto available_width = rest_available_size_for_children.width / stretch_control_list.size();
- for (const auto control : stretch_control_list)
- {
- control->Measure(Size(AtLeast0(available_width), rest_available_size_for_children.height));
- const auto size = control->GetDesiredSize();
- rest_available_size_for_children.width -= size.width;
- secondary_side_child_max_length = std::max(size.height, secondary_side_child_max_length);
- }
- }
- else
- {
- const auto available_height = rest_available_size_for_children.height / stretch_control_list.size();
- for (const auto control : stretch_control_list)
- {
- control->Measure(Size(rest_available_size_for_children.width, AtLeast0(available_height)));
- const auto size = control->GetDesiredSize();
- rest_available_size_for_children.height -= size.height;
- secondary_side_child_max_length = std::max(size.width, secondary_side_child_max_length);
- }
- }
-
- auto actual_size_for_children = total_available_size_for_children;
- if (orientation_ == Orientation::Horizontal)
- {
- actual_size_for_children.width -= rest_available_size_for_children.width;
- actual_size_for_children.height = secondary_side_child_max_length;
- }
- else
- {
- actual_size_for_children.width = secondary_side_child_max_length;
- actual_size_for_children.height -= rest_available_size_for_children.height;
- }
-
- auto&& calculate_final_length = [](const LayoutSideParams& layout_length, const float length_for_children, const float max_child_length) -> float
- {
- switch (layout_length.mode)
- {
- case MeasureMode::Exactly:
- case MeasureMode::Stretch:
- return length_for_children;
- case MeasureMode::Content:
- return max_child_length;
- default:
- UnreachableCode();
- }
- };
-
- return Size(
- calculate_final_length(layout_params->width, total_available_size_for_children.width, actual_size_for_children.width),
- calculate_final_length(layout_params->height, total_available_size_for_children.height, actual_size_for_children.height)
- );
- }
-
- void LinearLayout::OnLayout(const Rect& rect)
- {
- float current_anchor_length = 0;
- ForeachChild([this, &current_anchor_length, rect](Control* control)
- {
- const auto layout_params = control->GetLayoutParams();
- const auto size = control->GetDesiredSize();
- const auto alignment = orientation_ == Orientation::Horizontal ? layout_params->height.alignment : layout_params->width.alignment;
-
- auto&& calculate_anchor = [alignment](const float layout_length, const float control_length) -> float
- {
- switch (alignment)
- {
- case Alignment::Center:
- return (layout_length - control_length) / 2;
- case Alignment::Start:
- return 0;
- case Alignment::End:
- return layout_length - control_length;
- default:
- UnreachableCode();
- }
- };
-
- if (orientation_ == Orientation::Horizontal)
- {
- control->Layout(Rect(Point(current_anchor_length, calculate_anchor(rect.height, size.height)), size));
- current_anchor_length += size.width;
- }
- else
- {
- control->Layout(Rect(Point(calculate_anchor(rect.width, size.width), current_anchor_length), size));
- current_anchor_length += size.height;
- }
- });
- }
-}
diff --git a/CruUI/ui/controls/linear_layout.h b/CruUI/ui/controls/linear_layout.h
deleted file mode 100644
index 369824d4..00000000
--- a/CruUI/ui/controls/linear_layout.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#pragma once
-
-#include "ui/control.h"
-
-namespace cru::ui::controls
-{
- class LinearLayout : public Control
- {
- public:
- enum class Orientation
- {
- Horizontal,
- Vertical
- };
-
- static LinearLayout* Create(const Orientation orientation = Orientation::Vertical, const std::initializer_list<Control*>& children = std::initializer_list<Control*>())
- {
- const auto linear_layout = new LinearLayout(orientation);
- for (const auto control : children)
- linear_layout->AddChild(control);
- return linear_layout;
- }
-
- protected:
- explicit LinearLayout(Orientation orientation = Orientation::Vertical);
-
- public:
- LinearLayout(const LinearLayout& other) = delete;
- LinearLayout(LinearLayout&& other) = delete;
- LinearLayout& operator=(const LinearLayout& other) = delete;
- LinearLayout& operator=(LinearLayout&& other) = delete;
- ~LinearLayout() override = default;
-
- protected:
- Size OnMeasure(const Size& available_size) override;
- void OnLayout(const Rect& rect) override;
-
- private:
- Orientation orientation_;
- };
-}
diff --git a/CruUI/ui/controls/margin_container.cpp b/CruUI/ui/controls/margin_container.cpp
deleted file mode 100644
index 8f9101b2..00000000
--- a/CruUI/ui/controls/margin_container.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "margin_container.h"
-
-namespace cru::ui::controls
-{
- inline float AtLeast0(const float value)
- {
- return value < 0 ? 0 : value;
- }
-
- inline Size AtLeast0(const Size& size)
- {
- return Size(AtLeast0(size.width), AtLeast0(size.height));
- }
-
- MarginContainer::MarginContainer(const Thickness& margin)
- : Control(true), margin_(margin)
- {
- }
-
- void MarginContainer::SetMargin(const Thickness& margin)
- {
- margin_ = margin;
- Relayout();
- }
-
- Size MarginContainer::OnMeasure(const Size& available_size)
- {
- const auto margin_size = Size(margin_.left + margin_.right, margin_.top + margin_.bottom);
- const auto coerced_available_size = AtLeast0(available_size - margin_size);
- return Control::OnMeasure(coerced_available_size) + margin_size;
- }
-
- void MarginContainer::OnLayout(const Rect& rect)
- {
- const auto anchor = Point(margin_.left, margin_.top);
- const auto margin_size = Size(margin_.left + margin_.right, margin_.top + margin_.bottom);
- ForeachChild([anchor, margin_size, rect](Control* control)
- {
- const auto layout_params = control->GetLayoutParams();
- const auto size = control->GetDesiredSize();
-
- auto&& calculate_anchor = [](const float anchor, const Alignment alignment, const float layout_length, const float control_length) -> float
- {
- switch (alignment)
- {
- case Alignment::Center:
- return anchor + (layout_length - control_length) / 2;
- case Alignment::Start:
- return anchor;
- case Alignment::End:
- return anchor + layout_length - control_length;
- default:
- UnreachableCode();
- }
- };
-
- control->Layout(Rect(Point(
- calculate_anchor(anchor.x, layout_params->width.alignment, rect.width - margin_size.width, size.width),
- calculate_anchor(anchor.y, layout_params->height.alignment, rect.height - margin_size.height, size.height)
- ), size));
- });
- }
-}
diff --git a/CruUI/ui/controls/margin_container.h b/CruUI/ui/controls/margin_container.h
deleted file mode 100644
index 0eafc40e..00000000
--- a/CruUI/ui/controls/margin_container.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#pragma once
-
-#include <initializer_list>
-
-#include "ui/control.h"
-
-namespace cru::ui::controls
-{
- class MarginContainer : public Control
- {
- public:
- static MarginContainer* Create(const Thickness& margin = Thickness::Zero(), const std::initializer_list<Control*>& children = std::initializer_list<Control*>())
- {
- const auto margin_container = new MarginContainer(margin);
- for (const auto control : children)
- margin_container->AddChild(control);
- return margin_container;
- }
-
- protected:
- explicit MarginContainer(const Thickness& margin);
-
- public:
- MarginContainer(const MarginContainer& other) = delete;
- MarginContainer(MarginContainer&& other) = delete;
- MarginContainer& operator=(const MarginContainer& other) = delete;
- MarginContainer& operator=(MarginContainer&& other) = delete;
- ~MarginContainer() override = default;
-
- Thickness GetMargin() const
- {
- return margin_;
- }
-
- void SetMargin(const Thickness& margin);
-
- protected:
- Size OnMeasure(const Size& available_size) override;
- void OnLayout(const Rect& rect) override;
-
- private:
- Thickness margin_;
- };
-}
diff --git a/CruUI/ui/controls/text_block.cpp b/CruUI/ui/controls/text_block.cpp
deleted file mode 100644
index 93d66ba6..00000000
--- a/CruUI/ui/controls/text_block.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-#include "text_block.h"
-
-#include "ui/window.h"
-#include "graph/graph.h"
-#include "exception.h"
-
-namespace cru
-{
- namespace ui
- {
- namespace controls
- {
- using graph::CreateSolidBrush;
-
- inline Microsoft::WRL::ComPtr<IDWriteFactory> GetDWriteFactory()
- {
- return graph::GraphManager::GetInstance()->GetDWriteFactory();
- }
-
- TextBlock::TextBlock(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format,
- const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush) : Control(false)
- {
- text_format_ = init_text_format == nullptr ? graph::CreateDefaultTextFormat() : init_text_format;
-
- RecreateTextLayout();
-
- brush_ = init_brush == nullptr ? CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black)) : init_brush;
-
- selection_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightSkyBlue));
- }
-
- TextBlock::~TextBlock() = default;
-
- void TextBlock::SetText(const String& text)
- {
- if (text_ != text)
- {
- const auto old_text = text_;
- text_ = text;
- OnTextChangedCore(old_text, text);
- }
- }
-
- void TextBlock::SetBrush(const Microsoft::WRL::ComPtr<ID2D1Brush>& brush)
- {
- brush_ = brush;
- Repaint();
- }
-
- void TextBlock::SetTextFormat(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& text_format)
- {
- text_format_ = text_format;
- RecreateTextLayout();
- Repaint();
- }
-
- void TextBlock::AddTextLayoutHandler(TextLayoutHandlerPtr handler)
- {
- text_layout_handlers_.push_back(std::move(handler));
- }
-
- void TextBlock::RemoveTextLayoutHandler(const TextLayoutHandlerPtr& handler)
- {
- const auto find_result = std::find(text_layout_handlers_.cbegin(), text_layout_handlers_.cend(),
- handler);
- if (find_result != text_layout_handlers_.cend())
- text_layout_handlers_.erase(find_result);
- }
-
- void TextBlock::SetSelectable(const bool is_selectable)
- {
- if (!is_selectable)
- {
- is_selecting_ = false;
- selected_range_ = std::nullopt;
- Repaint();
- }
- is_selectable_ = is_selectable;
- }
-
- void TextBlock::SetSelectedRange(std::optional<TextRange> text_range)
- {
- if (is_selectable_)
- {
- selected_range_ = text_range;
- Repaint();
- }
- }
-
- void TextBlock::OnSizeChangedCore(events::SizeChangedEventArgs& args)
- {
- Control::OnSizeChangedCore(args);
- text_layout_->SetMaxWidth(args.GetNewSize().width);
- text_layout_->SetMaxHeight(args.GetNewSize().height);
- Repaint();
- }
-
- void TextBlock::OnDraw(ID2D1DeviceContext* device_context)
- {
- Control::OnDraw(device_context);
- if (selected_range_.has_value())
- {
- DWRITE_TEXT_METRICS text_metrics{};
- ThrowIfFailed(text_layout_->GetMetrics(&text_metrics));
- const auto metrics_count = text_metrics.lineCount * text_metrics.maxBidiReorderingDepth;
-
- Vector<DWRITE_HIT_TEST_METRICS> hit_test_metrics(metrics_count);
- UINT32 actual_count;
- text_layout_->HitTestTextRange(
- selected_range_.value().position, selected_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), selection_brush_.Get());
- }
- }
- device_context->DrawTextLayout(D2D1::Point2F(), text_layout_.Get(), brush_.Get());
- }
-
- namespace
- {
- std::optional<unsigned> TextLayoutHitTest(IDWriteTextLayout* text_layout, const Point& point, const bool test_inside = true)
- {
- BOOL is_trailing, is_inside;
- DWRITE_HIT_TEST_METRICS metrics{};
- text_layout->HitTestPoint(point.x, point.y, &is_trailing, &is_inside, &metrics);
- if (!test_inside || is_inside)
- return is_trailing == 0 ? metrics.textPosition : metrics.textPosition + 1;
- else
- return std::nullopt;
- }
- }
-
- void TextBlock::OnMouseDownCore(events::MouseButtonEventArgs& args)
- {
- Control::OnMouseDownCore(args);
- if (is_selectable_ && args.GetMouseButton() == MouseButton::Left)
- {
- selected_range_ = std::nullopt;
- const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this), true);
- if (hit_test_result.has_value())
- {
- mouse_down_position_ = hit_test_result.value();
- is_selecting_ = true;
- GetWindow()->CaptureMouseFor(this);
- }
- Repaint();
- }
- }
-
- void TextBlock::OnMouseMoveCore(events::MouseEventArgs& args)
- {
- Control::OnMouseMoveCore(args);
- if (is_selecting_)
- {
- const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this), false).value();
- if (hit_test_result > mouse_down_position_)
- selected_range_ = TextRange(mouse_down_position_, hit_test_result - mouse_down_position_);
- else if (hit_test_result < mouse_down_position_)
- selected_range_ = TextRange(hit_test_result, mouse_down_position_ - hit_test_result);
- else
- selected_range_ = std::nullopt;
- Repaint();
- }
- }
-
- void TextBlock::OnMouseUpCore(events::MouseButtonEventArgs& args)
- {
- Control::OnMouseUpCore(args);
- if (args.GetMouseButton() == MouseButton::Left)
- {
- if (is_selecting_)
- {
- is_selecting_ = false;
- GetWindow()->ReleaseCurrentMouseCapture();
- }
- }
- }
-
- void TextBlock::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;
- Repaint();
- }
- }
-
- Size TextBlock::OnMeasure(const Size& available_size)
- {
- const auto layout_params = GetLayoutParams();
-
- if (layout_params->width.mode == MeasureMode::Stretch && layout_params->height.mode == MeasureMode::Stretch)
- return available_size;
-
- auto&& get_measure_length = [](const LayoutSideParams& layout_length, const float available_length) -> float
- {
- switch (layout_length.mode)
- {
- case MeasureMode::Exactly:
- {
- return std::min(layout_length.length, available_length);
- }
- case MeasureMode::Stretch:
- case MeasureMode::Content:
- {
- return available_length;
- }
- default:
- UnreachableCode();
- }
- };
-
- const Size measure_size(get_measure_length(layout_params->width, available_size.width),
- get_measure_length(layout_params->height, available_size.height));
-
- ThrowIfFailed(text_layout_->SetMaxWidth(measure_size.width));
- ThrowIfFailed(text_layout_->SetMaxHeight(measure_size.height));
-
- DWRITE_TEXT_METRICS metrics{};
-
- ThrowIfFailed(text_layout_->GetMetrics(&metrics));
-
- const Size measure_result(metrics.width, metrics.height);
-
- auto&& calculate_final_length = [](const LayoutSideParams& layout_length, const float measure_length, const float measure_result_length) -> float
- {
- if ((layout_length.mode == MeasureMode::Stretch ||
- layout_length.mode == MeasureMode::Exactly)
- && measure_result_length < measure_length)
- return measure_length;
- else
- return measure_result_length;
- };
-
- const Size result_size(
- calculate_final_length(layout_params->width, measure_size.width, measure_result.width),
- calculate_final_length(layout_params->height, measure_size.height, measure_result.height)
- );
-
- return result_size;
- }
-
- void TextBlock::OnTextChangedCore(const String& old_text, const String& new_text)
- {
- RecreateTextLayout();
- Repaint();
- }
-
- void TextBlock::RecreateTextLayout()
- {
- assert(text_format_ != nullptr);
-
- const auto dwrite_factory = GetDWriteFactory();
-
- const auto&& size = GetSize();
-
- ThrowIfFailed(dwrite_factory->CreateTextLayout(
- text_.c_str(), static_cast<UINT32>(text_.size()),
- text_format_.Get(),
- size.width, size.height,
- &text_layout_
- ));
-
- std::for_each(text_layout_handlers_.cbegin(), text_layout_handlers_.cend(), [this](const TextLayoutHandlerPtr& handler)
- {
- (*handler)(text_layout_);
- });
- }
- }
- }
-}
diff --git a/CruUI/ui/controls/text_block.h b/CruUI/ui/controls/text_block.h
deleted file mode 100644
index c87ffc51..00000000
--- a/CruUI/ui/controls/text_block.h
+++ /dev/null
@@ -1,116 +0,0 @@
-#pragma once
-
-#include <memory>
-#include <optional>
-
-#include "ui/control.h"
-
-namespace cru
-{
- namespace ui
- {
- namespace controls
- {
- class TextBlock : public Control
- {
- public:
- using TextLayoutHandlerPtr = FunctionPtr<void(Microsoft::WRL::ComPtr<IDWriteTextLayout>)>;
-
- static TextBlock* Create(
- const String& text = L"",
- const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format = nullptr,
- const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush = nullptr)
- {
- const auto text_block = new TextBlock(init_text_format, init_brush);
- text_block->SetText(text);
- return text_block;
- }
-
- protected:
- explicit TextBlock(
- const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format = nullptr,
- const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush = nullptr
- );
- public:
- TextBlock(const TextBlock& other) = delete;
- TextBlock(TextBlock&& other) = delete;
- TextBlock& operator=(const TextBlock& other) = delete;
- TextBlock& operator=(TextBlock&& other) = delete;
- ~TextBlock() override;
-
- String GetText() const
- {
- return text_;
- }
-
- void SetText(const String& text);
-
- Microsoft::WRL::ComPtr<ID2D1Brush> GetBrush() const
- {
- return brush_;
- }
-
- void SetBrush(const Microsoft::WRL::ComPtr<ID2D1Brush>& brush);
-
- Microsoft::WRL::ComPtr<IDWriteTextFormat> GetTextFormat() const
- {
- return text_format_;
- }
-
- void SetTextFormat(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& text_format);
-
-
- void AddTextLayoutHandler(TextLayoutHandlerPtr handler);
-
- void RemoveTextLayoutHandler(const TextLayoutHandlerPtr& handler);
-
- bool IsSelectable() const
- {
- return is_selectable_;
- }
-
- void SetSelectable(bool is_selectable);
-
- std::optional<TextRange> GetSelectedRange() const
- {
- return selected_range_;
- }
-
- void SetSelectedRange(std::optional<TextRange> text_range);
-
- protected:
- void OnSizeChangedCore(events::SizeChangedEventArgs& args) override final;
- void OnDraw(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 final;
-
- Size OnMeasure(const Size& available_size) override final;
-
- private:
- void OnTextChangedCore(const String& old_text, const String& new_text);
-
- void RecreateTextLayout();
-
- private:
- String text_;
-
- Microsoft::WRL::ComPtr<ID2D1Brush> brush_;
- Microsoft::WRL::ComPtr<ID2D1Brush> selection_brush_;
- Microsoft::WRL::ComPtr<IDWriteTextFormat> text_format_;
- Microsoft::WRL::ComPtr<IDWriteTextLayout> text_layout_;
-
- Vector<TextLayoutHandlerPtr> text_layout_handlers_;
-
- bool is_selectable_ = false;
-
- bool is_selecting_ = false;
- unsigned mouse_down_position_ = 0;
- std::optional<TextRange> selected_range_ = std::nullopt;
- };
- }
- }
-}
diff --git a/CruUI/ui/controls/text_box.cpp b/CruUI/ui/controls/text_box.cpp
deleted file mode 100644
index a8d78398..00000000
--- a/CruUI/ui/controls/text_box.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-#include "text_box.h"
-
-#include <cwctype>
-
-#include "graph/graph.h"
-#include "exception.h"
-
-namespace cru::ui::controls
-{
- using graph::CreateSolidBrush;
-
- inline Microsoft::WRL::ComPtr<IDWriteFactory> GetDWriteFactory()
- {
- return graph::GraphManager::GetInstance()->GetDWriteFactory();
- }
-
- TextBox::TextBox(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format,
- const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush) : Control(false)
- {
- text_format_ = init_text_format == nullptr ? graph::CreateDefaultTextFormat() : init_text_format;
-
- RecreateTextLayout();
-
- brush_ = init_brush == nullptr ? CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black)) : init_brush;
-
- caret_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black));
-
- caret_action_ = CreateActionPtr([this]
- {
- is_caret_show_ = !is_caret_show_;
- Repaint();
- });
-
- //selection_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightSkyBlue));
- }
-
- TextBox::~TextBox() = default;
-
- void TextBox::SetText(const String& text)
- {
- if (text_ != text)
- {
- const auto old_text = text_;
- text_ = text;
- OnTextChangedCore(old_text, text);
- }
- }
-
- void TextBox::SetBrush(const Microsoft::WRL::ComPtr<ID2D1Brush>& brush)
- {
- brush_ = brush;
- Repaint();
- }
-
- void TextBox::SetTextFormat(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& text_format)
- {
- text_format_ = text_format;
- RecreateTextLayout();
- Repaint();
- }
-
- void TextBox::OnSizeChangedCore(events::SizeChangedEventArgs& args)
- {
- Control::OnSizeChangedCore(args);
- text_layout_->SetMaxWidth(args.GetNewSize().width);
- text_layout_->SetMaxHeight(args.GetNewSize().height);
- Repaint();
- }
-
- void TextBox::OnDraw(ID2D1DeviceContext* device_context)
- {
- Control::OnDraw(device_context);
- if (text_layout_ != nullptr)
- {
- device_context->DrawTextLayout(D2D1::Point2F(), text_layout_.Get(), brush_.Get());
- if (is_caret_show_)
- {
- const auto caret_half_width = Application::GetInstance()->GetCaretInfo().half_caret_width;
- FLOAT x, y;
- DWRITE_HIT_TEST_METRICS metrics{};
- ThrowIfFailed(text_layout_->HitTestTextPosition(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());
- }
- }
- }
-
- namespace
- {
- std::optional<unsigned> TextLayoutHitTest(IDWriteTextLayout* text_layout, const Point& point, bool test_inside = true)
- {
- BOOL is_trailing, is_inside;
- DWRITE_HIT_TEST_METRICS metrics{};
- text_layout->HitTestPoint(point.x, point.y, &is_trailing, &is_inside, &metrics);
- if (!test_inside || is_inside)
- return is_trailing == 0 ? metrics.textPosition : metrics.textPosition + 1;
- else
- return std::nullopt;
- }
- }
-
- void TextBox::OnMouseDownCore(events::MouseButtonEventArgs& args)
- {
- Control::OnMouseDownCore(args);
- if (args.GetMouseButton() == MouseButton::Left)
- {
- position_ = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this), false).value();
-
- Repaint();
- }
- }
-
- void TextBox::OnGetFocusCore(events::FocusChangeEventArgs& args)
- {
- Control::OnGetFocusCore(args);
- assert(caret_timer_ == nullptr);
- is_caret_show_ = true;
- caret_timer_ = SetInterval(Application::GetInstance()->GetCaretInfo().caret_blink_duration, caret_action_);
- }
-
- void TextBox::OnLoseFocusCore(events::FocusChangeEventArgs& args)
- {
- Control::OnLoseFocusCore(args);
- assert(caret_timer_ != nullptr);
- caret_timer_->Cancel();
- is_caret_show_ = false;
- }
-
- void TextBox::OnKeyDownCore(events::KeyEventArgs& args)
- {
- Control::OnKeyDownCore(args);
- if (args.GetVirtualCode() == VK_LEFT && position_ > 0)
- {
- position_--;
- Repaint();
- }
-
- if (args.GetVirtualCode() == VK_RIGHT && position_ < GetText().size())
- {
- position_++;
- Repaint();
- }
- }
-
- void TextBox::OnCharCore(events::CharEventArgs& args)
- {
- Control::OnCharCore(args);
- if (args.GetChar() == L'\b')
- {
- auto text = GetText();
- if (!text.empty() && position_ > 0)
- {
- const auto position = --position_;
- text.erase(position);
- SetText(text);
- }
- return;
- }
-
- if (std::iswprint(args.GetChar()))
- {
- const auto position = position_++;
- auto text = GetText();
- text.insert(text.cbegin() + position, { args.GetChar() });
- SetText(text);
- }
- }
-
- Size TextBox::OnMeasure(const Size& available_size)
- {
- const auto layout_params = GetLayoutParams();
-
- if (layout_params->width.mode == MeasureMode::Stretch && layout_params->height.mode == MeasureMode::Stretch)
- return available_size;
-
- auto&& get_measure_length = [](const LayoutSideParams& layout_length, const float available_length) -> float
- {
- switch (layout_length.mode)
- {
- case MeasureMode::Exactly:
- {
- return std::min(layout_length.length, available_length);
- }
- case MeasureMode::Stretch:
- case MeasureMode::Content:
- {
- return available_length;
- }
- default:
- UnreachableCode();
- }
- };
-
- const Size measure_size(get_measure_length(layout_params->width, available_size.width),
- get_measure_length(layout_params->height, available_size.height));
-
- ThrowIfFailed(text_layout_->SetMaxWidth(measure_size.width));
- ThrowIfFailed(text_layout_->SetMaxHeight(measure_size.height));
-
- DWRITE_TEXT_METRICS metrics{};
-
- ThrowIfFailed(text_layout_->GetMetrics(&metrics));
-
- const Size measure_result(metrics.width, metrics.height);
-
- auto&& calculate_final_length = [](const LayoutSideParams& layout_length, const float measure_length, const float measure_result_length) -> float
- {
- if ((layout_length.mode == MeasureMode::Stretch ||
- layout_length.mode == MeasureMode::Exactly)
- && measure_result_length < measure_length)
- return measure_length;
- else
- return measure_result_length;
- };
-
- const Size result_size(
- calculate_final_length(layout_params->width, measure_size.width, measure_result.width),
- calculate_final_length(layout_params->height, measure_size.height, measure_result.height)
- );
-
- return result_size;
- }
-
- void TextBox::OnTextChangedCore(const String& old_text, const String& new_text)
- {
- RecreateTextLayout();
- Repaint();
- }
-
- void TextBox::RecreateTextLayout()
- {
- assert(text_format_ != nullptr);
-
- const auto dwrite_factory = GetDWriteFactory();
-
- const auto&& size = GetSize();
-
- ThrowIfFailed(dwrite_factory->CreateTextLayout(
- text_.c_str(), static_cast<UINT32>(text_.size()),
- text_format_.Get(),
- size.width, size.height,
- &text_layout_
- ));
- }
-}
diff --git a/CruUI/ui/controls/text_box.h b/CruUI/ui/controls/text_box.h
deleted file mode 100644
index b815ed1f..00000000
--- a/CruUI/ui/controls/text_box.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#pragma once
-
-#include "ui/control.h"
-#include "timer.h"
-
-namespace cru::ui::controls
-{
- class TextBox : public Control
- {
- public:
- static TextBox* Create(
- const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format = nullptr,
- const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush = nullptr)
- {
- return new TextBox(init_text_format, init_brush);
- }
-
- protected:
- explicit TextBox(
- const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format = nullptr,
- const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush = nullptr
- );
- public:
- TextBox(const TextBox& other) = delete;
- TextBox(TextBox&& other) = delete;
- TextBox& operator=(const TextBox& other) = delete;
- TextBox& operator=(TextBox&& other) = delete;
- ~TextBox() override;
-
- String GetText() const
- {
- return text_;
- }
-
- void SetText(const String& text);
-
- Microsoft::WRL::ComPtr<ID2D1Brush> GetBrush() const
- {
- return brush_;
- }
-
- void SetBrush(const Microsoft::WRL::ComPtr<ID2D1Brush>& brush);
-
- Microsoft::WRL::ComPtr<IDWriteTextFormat> GetTextFormat() const
- {
- return text_format_;
- }
-
- void SetTextFormat(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& text_format);
-
- protected:
- void OnSizeChangedCore(events::SizeChangedEventArgs& args) override final;
- void OnDraw(ID2D1DeviceContext* device_context) override;
-
- void OnMouseDownCore(events::MouseButtonEventArgs& args) override final;
-
- 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;
-
- Size OnMeasure(const Size& available_size) override final;
-
- private:
- void OnTextChangedCore(const String& old_text, const String& new_text);
-
- void RecreateTextLayout();
-
- private:
- String text_;
-
- Microsoft::WRL::ComPtr<ID2D1Brush> brush_;
- Microsoft::WRL::ComPtr<ID2D1Brush> caret_brush_;
- //Microsoft::WRL::ComPtr<ID2D1Brush> selection_brush_;
- Microsoft::WRL::ComPtr<IDWriteTextFormat> text_format_;
- Microsoft::WRL::ComPtr<IDWriteTextLayout> text_layout_;
-
- unsigned position_ = 0;
-
- TimerTask caret_timer_;
- ActionPtr caret_action_;
- bool is_caret_show_;
- };
-}
diff --git a/CruUI/ui/controls/toggle_button.cpp b/CruUI/ui/controls/toggle_button.cpp
deleted file mode 100644
index 68bd0fc9..00000000
--- a/CruUI/ui/controls/toggle_button.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-#include "toggle_button.h"
-
-#include <fmt/format.h>
-
-#include "graph/graph.h"
-#include "ui/animations/animation.h"
-
-namespace cru::ui::controls
-{
- using graph::CreateSolidBrush;
- using animations::AnimationBuilder;
-
- // ui length parameters of toggle button.
- constexpr float half_height = 15;
- constexpr float half_width = half_height * 2;
- constexpr float stroke_width = 3;
- constexpr float inner_circle_radius = half_height - stroke_width;
- constexpr float inner_circle_x = half_width - half_height;
-
- ToggleButton::ToggleButton() : current_circle_position_(-inner_circle_x)
- {
- graph::GraphManager::GetInstance()->GetD2D1Factory()->CreateRoundedRectangleGeometry(D2D1::RoundedRect(D2D1::RectF(-half_width, -half_height, half_width, half_height), half_height, half_height), &frame_path_);
-
- on_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::DeepSkyBlue));
- off_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightGray));
- }
-
- inline D2D1_POINT_2F ConvertPoint(const Point& point)
- {
- return D2D1::Point2F(point.x, point.y);
- }
-
- bool ToggleButton::IsPointInside(const Point& point)
- {
- 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);
- if (!contains)
- frame_path_->StrokeContainsPoint(ConvertPoint(point), stroke_width, nullptr, transform, &contains);
- return contains != 0;
- }
-
- void ToggleButton::SetState(const bool state)
- {
- if (state != state_)
- {
- state_ = state;
- float destination_x;
-
- if (state)
- destination_x = inner_circle_x;
- else
- destination_x = -inner_circle_x;
-
- const auto previous_position = current_circle_position_;
- const auto delta = destination_x - current_circle_position_;
-
- constexpr auto total_time = FloatSecond(0.2);
-
- const auto time = total_time * (std::abs(delta) / (inner_circle_x * 2));
-
- // ReSharper disable once CppExpressionWithoutSideEffects
- AnimationBuilder(fmt::format(L"ToggleButton {}", reinterpret_cast<size_t>(this)), time)
- .AddStepHandler(CreatePtr<animations::AnimationStepHandlerPtr>([=](animations::AnimationDelegatePtr, const double percentage)
- {
- current_circle_position_ = static_cast<float>(previous_position + delta * percentage);
- Repaint();
- })).Start();
-
- RaiseToggleEvent(state);
- Repaint();
- }
- }
-
- void ToggleButton::Toggle()
- {
- SetState(!GetState());
- }
-
- void ToggleButton::OnToggle(events::ToggleEventArgs& args)
- {
-
- }
-
- void ToggleButton::OnDraw(ID2D1DeviceContext* device_context)
- {
- Control::OnDraw(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::OnMeasure(const Size& available_size)
- {
- const auto layout_params = GetLayoutParams();
-
- auto&& get_measure_length = [](const LayoutSideParams& layout_length, const float available_length, const float fix_length) -> float
- {
- switch (layout_length.mode)
- {
- case MeasureMode::Exactly:
- {
- return std::max(std::min(layout_length.length, available_length), fix_length);
- }
- case MeasureMode::Stretch:
- {
- return std::max(available_length, fix_length);
- }
- case MeasureMode::Content:
- {
- return fix_length;
- }
- default:
- UnreachableCode();
- }
- };
-
- const Size result_size(
- get_measure_length(layout_params->width, available_size.width, half_width * 2 + stroke_width),
- get_measure_length(layout_params->height, available_size.height, half_height * 2 + stroke_width)
- );
-
- 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/CruUI/ui/controls/toggle_button.h b/CruUI/ui/controls/toggle_button.h
deleted file mode 100644
index d496f21a..00000000
--- a/CruUI/ui/controls/toggle_button.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#pragma once
-
-#include "ui/control.h"
-
-namespace cru::ui::controls
-{
- class ToggleButton : public Control
- {
- public:
- static ToggleButton* Create()
- {
- return new ToggleButton();
- }
-
- protected:
- ToggleButton();
-
- public:
- ToggleButton(const ToggleButton& other) = delete;
- ToggleButton(ToggleButton&& other) = delete;
- ToggleButton& operator=(const ToggleButton& other) = delete;
- ToggleButton& operator=(ToggleButton&& other) = delete;
- ~ToggleButton() override = default;
-
- bool IsPointInside(const Point& point) override;
-
- bool GetState() const
- {
- return state_;
- }
-
- void SetState(bool state);
-
- void Toggle();
-
- public:
- events::ToggleEvent toggle_event;
-
- protected:
- virtual void OnToggle(events::ToggleEventArgs& args);
-
- protected:
- void OnDraw(ID2D1DeviceContext* device_context) override;
-
- void OnMouseClickCore(events::MouseButtonEventArgs& args) override;
-
- Size OnMeasure(const Size& available_size) override;
-
- private:
- void RaiseToggleEvent(bool new_state);
-
- private:
- bool state_ = false;
-
- float current_circle_position_;
-
- Microsoft::WRL::ComPtr<ID2D1RoundedRectangleGeometry> frame_path_;
- Microsoft::WRL::ComPtr<ID2D1Brush> on_brush_;
- Microsoft::WRL::ComPtr<ID2D1Brush> off_brush_;
- };
-}