aboutsummaryrefslogtreecommitdiff
path: root/CruUI/ui
diff options
context:
space:
mode:
Diffstat (limited to 'CruUI/ui')
-rw-r--r--CruUI/ui/animations/animation.cpp190
-rw-r--r--CruUI/ui/animations/animation.h107
-rw-r--r--CruUI/ui/control.cpp712
-rw-r--r--CruUI/ui/control.h380
-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
-rw-r--r--CruUI/ui/events/ui_event.cpp19
-rw-r--r--CruUI/ui/events/ui_event.h317
-rw-r--r--CruUI/ui/layout_base.cpp79
-rw-r--r--CruUI/ui/layout_base.h136
-rw-r--r--CruUI/ui/ui_base.cpp6
-rw-r--r--CruUI/ui/ui_base.h154
-rw-r--r--CruUI/ui/window.cpp606
-rw-r--r--CruUI/ui/window.h276
24 files changed, 0 insertions, 4321 deletions
diff --git a/CruUI/ui/animations/animation.cpp b/CruUI/ui/animations/animation.cpp
deleted file mode 100644
index 9d05860a..00000000
--- a/CruUI/ui/animations/animation.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-#include "animation.h"
-
-#include <cassert>
-#include <utility>
-
-namespace cru::ui::animations
-{
- namespace details
- {
- class AnimationDelegateImpl;
- constexpr double frame_rate = 60;
- constexpr AnimationTimeUnit frame_step_time = AnimationTimeUnit(1) / frame_rate;
-
-
- class AnimationDelegateImpl : public virtual IAnimationDelegate
- {
- public:
- explicit AnimationDelegateImpl(String tag)
- : tag_(std::move(tag))
- {
-
- }
- AnimationDelegateImpl(const AnimationDelegateImpl& other) = delete;
- AnimationDelegateImpl(AnimationDelegateImpl&& other) = delete;
- AnimationDelegateImpl& operator=(const AnimationDelegateImpl& other) = delete;
- AnimationDelegateImpl& operator=(AnimationDelegateImpl&& other) = delete;
- ~AnimationDelegateImpl() override = default;
-
- void Cancel() override
- {
- AnimationManager::GetInstance()->RemoveAnimation(tag_);
- }
-
- private:
- String tag_;
- };
-
-
- class Animation : public Object
- {
- public:
- Animation(
- String tag,
- AnimationTimeUnit duration,
- Vector<AnimationStepHandlerPtr> step_handlers,
- Vector<AnimationStartHandlerPtr> start_handlers,
- Vector<ActionPtr> finish_handlers,
- Vector<ActionPtr> cancel_handlers,
- AnimationDelegatePtr delegate
- );
- Animation(const Animation& other) = delete;
- Animation(Animation&& other) = delete;
- Animation& operator=(const Animation& other) = delete;
- Animation& operator=(Animation&& other) = delete;
- ~Animation() override;
-
-
- // If finish or invalid, return false.
- bool Step(AnimationTimeUnit time);
-
- String GetTag() const
- {
- return tag_;
- }
-
- private:
- const String tag_;
- const AnimationTimeUnit duration_;
- Vector<AnimationStepHandlerPtr> step_handlers_;
- Vector<AnimationStartHandlerPtr> start_handlers_;
- Vector<ActionPtr> finish_handlers_;
- Vector<ActionPtr> cancel_handlers_;
- AnimationDelegatePtr delegate_;
-
- AnimationTimeUnit current_time_ = AnimationTimeUnit::zero();
- };
-
- AnimationManager::AnimationManager()
- : timer_action_(CreateActionPtr([this]()
- {
- auto i = animations_.cbegin();
- while (i != animations_.cend())
- {
- auto current_i = i++;
- if (current_i->second->Step(frame_step_time))
- animations_.erase(current_i);
- }
-
- if (animations_.empty())
- KillTimer();
- }))
- {
-
- }
-
- AnimationManager::~AnimationManager()
- {
- KillTimer();
- }
-
- AnimationDelegatePtr AnimationManager::CreateAnimation(String tag, AnimationTimeUnit duration,
- Vector<AnimationStepHandlerPtr> step_handlers, Vector<AnimationStartHandlerPtr> start_handlers,
- Vector<ActionPtr> finish_handlers, Vector<ActionPtr> cancel_handlers)
- {
- if (animations_.empty())
- SetTimer();
-
- auto delegate = std::make_shared<AnimationDelegateImpl>(tag);
-
- animations_[tag] = std::make_unique<Animation>(tag, duration, std::move(step_handlers), std::move(start_handlers), std::move(finish_handlers), std::move(cancel_handlers), delegate);
-
- return delegate;
- }
-
- void AnimationManager::RemoveAnimation(const String& tag)
- {
- const auto find_result = animations_.find(tag);
- if (find_result != animations_.cend())
- animations_.erase(find_result);
-
- if (animations_.empty())
- KillTimer();
- }
-
- void AnimationManager::SetTimer()
- {
- if (timer_ == nullptr)
- timer_ = SetInterval(std::chrono::duration_cast<std::chrono::milliseconds>(frame_step_time), timer_action_);
- }
-
- void AnimationManager::KillTimer()
- {
- if (timer_ != nullptr)
- {
- timer_->Cancel();
- timer_ = nullptr;
- }
- }
-
- Animation::Animation(
- String tag,
- AnimationTimeUnit duration,
- Vector<AnimationStepHandlerPtr> step_handlers,
- Vector<AnimationStartHandlerPtr> start_handlers,
- Vector<ActionPtr> finish_handlers,
- Vector<ActionPtr> cancel_handlers,
- AnimationDelegatePtr delegate
- ) : tag_(std::move(tag)), duration_(duration),
- step_handlers_(std::move(step_handlers)),
- start_handlers_(std::move(start_handlers)),
- finish_handlers_(std::move(finish_handlers)),
- cancel_handlers_(std::move(cancel_handlers)),
- delegate_(std::move(delegate))
- {
-
- }
-
- Animation::~Animation()
- {
- if (current_time_ < duration_)
- for (auto& handler : cancel_handlers_)
- (*handler)();
- }
-
- bool Animation::Step(const AnimationTimeUnit time)
- {
- current_time_ += time;
- if (current_time_ > duration_)
- {
- for (auto& handler : step_handlers_)
- (*handler)(delegate_, 1);
- for (auto& handler : finish_handlers_)
- (*handler)();
- return true;
- }
- else
- {
- for (auto& handler : step_handlers_)
- (*handler)(delegate_, current_time_ / duration_);
- return false;
- }
- }
-
- }
-
- AnimationDelegatePtr AnimationBuilder::Start() const
- {
- return details::AnimationManager::GetInstance()->CreateAnimation(tag, duration, step_handlers_, start_handlers_, finish_handlers_, cancel_handlers_);
- }
-}
diff --git a/CruUI/ui/animations/animation.h b/CruUI/ui/animations/animation.h
deleted file mode 100644
index 69b08b0c..00000000
--- a/CruUI/ui/animations/animation.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#pragma once
-
-#include <unordered_map>
-
-#include "base.h"
-#include "application.h"
-#include "timer.h"
-
-namespace cru::ui::animations
-{
- using AnimationTimeUnit = FloatSecond;
-
-
- using IAnimationDelegate = ICancelable;
- using AnimationDelegatePtr = CancelablePtr;
-
- using AnimationStepHandlerPtr = FunctionPtr<void(AnimationDelegatePtr, double)>;
- using AnimationStartHandlerPtr = FunctionPtr<void(AnimationDelegatePtr)>;
-
-
- namespace details
- {
- class Animation;
- using AnimationPtr = std::unique_ptr<Animation>;
-
- class AnimationManager : public Object
- {
- public:
- static AnimationManager* GetInstance()
- {
- return Application::GetInstance()->GetAnimationManager();
- }
-
- public:
- AnimationManager();
- AnimationManager(const AnimationManager& other) = delete;
- AnimationManager(AnimationManager&& other) = delete;
- AnimationManager& operator=(const AnimationManager& other) = delete;
- AnimationManager& operator=(AnimationManager&& other) = delete;
- ~AnimationManager() override;
-
- AnimationDelegatePtr CreateAnimation(
- String tag,
- AnimationTimeUnit duration,
- Vector<AnimationStepHandlerPtr> step_handlers,
- Vector<AnimationStartHandlerPtr> start_handlers,
- Vector<ActionPtr> finish_handlers,
- Vector<ActionPtr> cancel_handlers
- );
- void RemoveAnimation(const String& tag);
-
- private:
- void SetTimer();
- void KillTimer();
-
- private:
- std::unordered_map<String, AnimationPtr> animations_;
- std::shared_ptr<ICancelable> timer_;
- ActionPtr timer_action_;
- };
- }
-
- class AnimationBuilder : public Object
- {
- public:
- AnimationBuilder(String tag, const AnimationTimeUnit duration)
- : tag(std::move(tag)), duration(duration)
- {
-
- }
-
- String tag;
- AnimationTimeUnit duration;
-
- AnimationBuilder& AddStepHandler(AnimationStepHandlerPtr handler)
- {
- step_handlers_.push_back(std::move(handler));
- return *this;
- }
-
- AnimationBuilder& AddStartHandler(AnimationStartHandlerPtr handler)
- {
- start_handlers_.push_back(std::move(handler));
- return *this;
- }
-
- AnimationBuilder& AddFinishHandler(ActionPtr handler)
- {
- finish_handlers_.push_back(std::move(handler));
- return *this;
- }
-
- AnimationBuilder& AddCancelHandler(ActionPtr handler)
- {
- cancel_handlers_.push_back(std::move(handler));
- return *this;
- }
-
- AnimationDelegatePtr Start() const;
-
- private:
- Vector<AnimationStepHandlerPtr> step_handlers_;
- Vector<AnimationStartHandlerPtr> start_handlers_;
- Vector<ActionPtr> finish_handlers_;
- Vector<ActionPtr> cancel_handlers_;
- };
-}
diff --git a/CruUI/ui/control.cpp b/CruUI/ui/control.cpp
deleted file mode 100644
index 8aec8640..00000000
--- a/CruUI/ui/control.cpp
+++ /dev/null
@@ -1,712 +0,0 @@
-#include "control.h"
-
-#include <string>
-#include <algorithm>
-#include <chrono>
-
-#include "window.h"
-#include "timer.h"
-#include "debug_base.h"
-
-namespace cru {
- namespace ui {
- using namespace events;
-
- Control::Control(const bool container) :
- is_container_(container)
- {
-
- }
-
- Control::Control(WindowConstructorTag, Window* window) : Control(true)
- {
- window_ = window;
- }
-
- Control::~Control()
- {
- ForeachChild([](auto control)
- {
- delete control;
- });
- }
-
- void Control::ForeachChild(Function<void(Control*)>&& predicate) const
- {
- if (is_container_)
- for (const auto child : children_)
- predicate(child);
- }
-
- void Control::ForeachChild(Function<FlowControl(Control*)>&& predicate) const
- {
- if (is_container_)
- for (const auto child : children_)
- {
- if (predicate(child) == FlowControl::Break)
- break;
- }
- }
-
- void AddChildCheck(Control* control)
- {
- if (control->GetParent() != nullptr)
- throw std::invalid_argument("The control already has a parent.");
-
- if (dynamic_cast<Window*>(control))
- throw std::invalid_argument("Can't add a window as child.");
- }
-
- void Control::AddChild(Control* control)
- {
- ThrowIfNotContainer();
- AddChildCheck(control);
-
- this->children_.push_back(control);
-
- control->parent_ = this;
-
- this->OnAddChild(control);
- }
-
- void Control::AddChild(Control* control, int position)
- {
- ThrowIfNotContainer();
- AddChildCheck(control);
-
- if (position < 0 || static_cast<decltype(this->children_.size())>(position) > this->children_.size())
- throw std::invalid_argument("The position is out of range.");
-
- this->children_.insert(this->children_.cbegin() + position, control);
-
- control->parent_ = this;
-
- this->OnAddChild(this);
- }
-
- void Control::RemoveChild(Control* child)
- {
- ThrowIfNotContainer();
- const auto i = std::find(this->children_.cbegin(), this->children_.cend(), child);
- if (i == this->children_.cend())
- throw std::invalid_argument("The argument child is not a child of this control.");
-
- this->children_.erase(i);
-
- child->parent_ = nullptr;
-
- this->OnRemoveChild(this);
- }
-
- void Control::RemoveChild(const int position)
- {
- ThrowIfNotContainer();
- if (position < 0 || static_cast<decltype(this->children_.size())>(position) >= this->children_.size())
- throw std::invalid_argument("The position is out of range.");
-
- const auto p = children_.cbegin() + position;
- const auto child = *p;
- children_.erase(p);
-
- child->parent_ = nullptr;
-
- this->OnRemoveChild(child);
- }
-
- Control* Control::GetAncestor()
- {
- // if attached to window, the window is the ancestor.
- if (window_)
- return window_;
-
- // otherwise find the ancestor
- auto ancestor = this;
- while (const auto parent = ancestor->GetParent())
- ancestor = parent;
- return ancestor;
- }
-
- void TraverseDescendantsInternal(Control* control, Function<void(Control*)>& predicate)
- {
- predicate(control);
- control->ForeachChild([&predicate](Control* c) {
- TraverseDescendantsInternal(c, predicate);
- });
- }
-
- void Control::TraverseDescendants(Function<void(Control*)>&& predicate)
- {
- if (is_container_)
- TraverseDescendantsInternal(this, predicate);
- else
- predicate(this);
- }
-
- Point Control::GetPositionRelative()
- {
- return position_;
- }
-
- void Control::SetPositionRelative(const Point & position)
- {
- if (position != position_)
- {
- if (old_position_ == position) // if cache has been refreshed and no pending notify
- old_position_ = position_;
- position_ = position;
- LayoutManager::GetInstance()->InvalidateControlPositionCache(this);
- if (auto window = GetWindow())
- {
- window->Repaint();
- }
- }
- }
-
- Size Control::GetSize()
- {
- return size_;
- }
-
- void Control::SetSize(const Size & size)
- {
- const auto old_size = size_;
- size_ = size;
- SizeChangedEventArgs args(this, this, old_size, size);
- RaiseSizeChangedEvent(args);
- if (auto window = GetWindow())
- window->Repaint();
- }
-
- Point Control::GetPositionAbsolute() const
- {
- return position_cache_.lefttop_position_absolute;
- }
-
- Point Control::LocalToAbsolute(const Point& point) const
- {
- return Point(point.x + position_cache_.lefttop_position_absolute.x,
- point.y + position_cache_.lefttop_position_absolute.y);
- }
-
- Point Control::AbsoluteToLocal(const Point & point) const
- {
- return Point(point.x - position_cache_.lefttop_position_absolute.x,
- point.y - position_cache_.lefttop_position_absolute.y);
- }
-
- bool Control::IsPointInside(const Point & point)
- {
- const auto size = GetSize();
- return point.x >= 0.0f && point.x < size.width && point.y >= 0.0f && point.y < size.height;
- }
-
- void Control::Draw(ID2D1DeviceContext* device_context)
- {
- D2D1::Matrix3x2F old_transform;
- device_context->GetTransform(&old_transform);
-
- const auto position = GetPositionRelative();
- device_context->SetTransform(old_transform * D2D1::Matrix3x2F::Translation(position.x, position.y));
-
- OnDraw(device_context);
- DrawEventArgs args(this, this, device_context);
- draw_event.Raise(args);
-
- for (auto child : GetChildren())
- child->Draw(device_context);
-
- device_context->SetTransform(old_transform);
- }
-
- void Control::Repaint()
- {
- if (window_ != nullptr)
- window_->Repaint();
- }
-
- bool Control::RequestFocus()
- {
- auto window = GetWindow();
- if (window == nullptr)
- return false;
-
- return window->RequestFocusFor(this);
- }
-
- bool Control::HasFocus()
- {
- auto window = GetWindow();
- if (window == nullptr)
- return false;
-
- return window->GetFocusControl() == this;
- }
-
- void Control::Relayout()
- {
- OnMeasure(GetSize());
- OnLayout(Rect(GetPositionRelative(), GetSize()));
- }
-
- void Control::Measure(const Size& available_size)
- {
- SetDesiredSize(OnMeasure(available_size));
- }
-
- void Control::Layout(const Rect& rect)
- {
- SetPositionRelative(rect.GetLeftTop());
- SetSize(rect.GetSize());
- OnLayout(rect);
- }
-
- Size Control::GetDesiredSize() const
- {
- return desired_size_;
- }
-
- void Control::SetDesiredSize(const Size& desired_size)
- {
- desired_size_ = desired_size;
- }
-
- void Control::OnAddChild(Control* child)
- {
- if (auto window = GetWindow())
- {
- child->TraverseDescendants([window](Control* control) {
- control->OnAttachToWindow(window);
- });
- window->RefreshControlList();
- }
- Relayout();
- }
-
- void Control::OnRemoveChild(Control* child)
- {
- if (auto window = GetWindow())
- {
- child->TraverseDescendants([window](Control* control) {
- control->OnDetachToWindow(window);
- });
- window->RefreshControlList();
- }
- Relayout();
- }
-
- void Control::OnAttachToWindow(Window* window)
- {
- window_ = window;
- }
-
- void Control::OnDetachToWindow(Window * window)
- {
- window_ = nullptr;
- }
-
- void Control::OnDraw(ID2D1DeviceContext * device_context)
- {
-#ifdef CRU_DEBUG_DRAW_CONTROL_BORDER
- if (GetWindow()->GetDebugDrawControlBorder())
- {
- auto brush = Application::GetInstance()->GetDebugBorderBrush();
- const auto size = GetSize();
- device_context->DrawRectangle(D2D1::RectF(0, 0, size.width, size.height), brush.Get());
- }
-#endif
- }
-
- void Control::OnPositionChanged(PositionChangedEventArgs & args)
- {
-
- }
-
- void Control::OnSizeChanged(SizeChangedEventArgs & args)
- {
- }
-
- void Control::OnPositionChangedCore(PositionChangedEventArgs & args)
- {
-
- }
-
- void Control::OnSizeChangedCore(SizeChangedEventArgs & args)
- {
-
- }
-
- void Control::RaisePositionChangedEvent(PositionChangedEventArgs& args)
- {
- OnPositionChangedCore(args);
- OnPositionChanged(args);
- position_changed_event.Raise(args);
- }
-
- void Control::RaiseSizeChangedEvent(SizeChangedEventArgs& args)
- {
- OnSizeChangedCore(args);
- OnSizeChanged(args);
- size_changed_event.Raise(args);
- }
-
- void Control::OnMouseEnter(MouseEventArgs & args)
- {
- }
-
- void Control::OnMouseLeave(MouseEventArgs & args)
- {
- }
-
- void Control::OnMouseMove(MouseEventArgs & args)
- {
- }
-
- void Control::OnMouseDown(MouseButtonEventArgs & args)
- {
- }
-
- void Control::OnMouseUp(MouseButtonEventArgs & args)
- {
- }
-
- void Control::OnMouseClick(MouseButtonEventArgs& args)
- {
-
- }
-
- void Control::OnMouseEnterCore(MouseEventArgs & args)
- {
- is_mouse_inside_ = true;
- }
-
- void Control::OnMouseLeaveCore(MouseEventArgs & args)
- {
- is_mouse_inside_ = false;
- for (auto& is_mouse_click_valid : is_mouse_click_valid_map_)
- {
- if (is_mouse_click_valid.second)
- {
- is_mouse_click_valid.second = false;
- OnMouseClickEnd(is_mouse_click_valid.first);
- }
- }
- }
-
- void Control::OnMouseMoveCore(MouseEventArgs & args)
- {
-
- }
-
- void Control::OnMouseDownCore(MouseButtonEventArgs & args)
- {
- if (is_focus_on_pressed_ && args.GetSender() == args.GetOriginalSender())
- RequestFocus();
- is_mouse_click_valid_map_[args.GetMouseButton()] = true;
- OnMouseClickBegin(args.GetMouseButton());
- }
-
- void Control::OnMouseUpCore(MouseButtonEventArgs & args)
- {
- if (is_mouse_click_valid_map_[args.GetMouseButton()])
- {
- is_mouse_click_valid_map_[args.GetMouseButton()] = false;
- RaiseMouseClickEvent(args);
- OnMouseClickEnd(args.GetMouseButton());
- }
- }
-
- void Control::OnMouseClickCore(MouseButtonEventArgs& args)
- {
-
- }
-
- void Control::RaiseMouseEnterEvent(MouseEventArgs& args)
- {
- OnMouseEnterCore(args);
- OnMouseEnter(args);
- mouse_enter_event.Raise(args);
- }
-
- void Control::RaiseMouseLeaveEvent(MouseEventArgs& args)
- {
- OnMouseLeaveCore(args);
- OnMouseLeave(args);
- mouse_leave_event.Raise(args);
- }
-
- void Control::RaiseMouseMoveEvent(MouseEventArgs& args)
- {
- OnMouseMoveCore(args);
- OnMouseMove(args);
- mouse_move_event.Raise(args);
- }
-
- void Control::RaiseMouseDownEvent(MouseButtonEventArgs& args)
- {
- OnMouseDownCore(args);
- OnMouseDown(args);
- mouse_down_event.Raise(args);
- }
-
- void Control::RaiseMouseUpEvent(MouseButtonEventArgs& args)
- {
- OnMouseUpCore(args);
- OnMouseUp(args);
- mouse_up_event.Raise(args);
- }
-
- void Control::RaiseMouseClickEvent(MouseButtonEventArgs& args)
- {
- OnMouseClickCore(args);
- OnMouseClick(args);
- mouse_click_event.Raise(args);
- }
-
- void Control::OnMouseClickBegin(MouseButton button)
- {
-
- }
-
- void Control::OnMouseClickEnd(MouseButton button)
- {
-
- }
-
- void Control::OnKeyDown(KeyEventArgs& args)
- {
- }
-
- void Control::OnKeyUp(KeyEventArgs& args)
- {
- }
-
- void Control::OnChar(CharEventArgs& args)
- {
- }
-
- void Control::OnKeyDownCore(KeyEventArgs& args)
- {
- }
-
- void Control::OnKeyUpCore(KeyEventArgs& args)
- {
- }
-
- void Control::OnCharCore(CharEventArgs& args)
- {
- }
-
- void Control::RaiseKeyDownEvent(KeyEventArgs& args)
- {
- OnKeyDownCore(args);
- OnKeyDown(args);
- key_down_event.Raise(args);
- }
-
- void Control::RaiseKeyUpEvent(KeyEventArgs& args)
- {
- OnKeyUpCore(args);
- OnKeyUp(args);
- key_up_event.Raise(args);
- }
-
- void Control::RaiseCharEvent(CharEventArgs& args)
- {
- OnCharCore(args);
- OnChar(args);
- char_event.Raise(args);
- }
-
- void Control::OnGetFocus(FocusChangeEventArgs& args)
- {
-
- }
-
- void Control::OnLoseFocus(FocusChangeEventArgs& args)
- {
-
- }
-
- void Control::OnGetFocusCore(FocusChangeEventArgs& args)
- {
-
- }
-
- void Control::OnLoseFocusCore(FocusChangeEventArgs& args)
- {
-
- }
-
- void Control::RaiseGetFocusEvent(FocusChangeEventArgs& args)
- {
- OnGetFocusCore(args);
- OnGetFocus(args);
- get_focus_event.Raise(args);
- }
-
- void Control::RaiseLoseFocusEvent(FocusChangeEventArgs& args)
- {
- OnLoseFocusCore(args);
- OnLoseFocus(args);
- lose_focus_event.Raise(args);
- }
-
- Size Control::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();
- }
- };
-
- const Size 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 max_child_size = Size::Zero();
- ForeachChild([&](Control* control)
- {
- control->Measure(size_for_children);
- const auto&& size = control->GetDesiredSize();
- if (max_child_size.width < size.width)
- max_child_size.width = size.width;
- if (max_child_size.height < size.height)
- max_child_size.height = size.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, size_for_children.width, max_child_size.width),
- calculate_final_length(layout_params->height, size_for_children.height, max_child_size.height)
- );
- }
-
- void Control::OnLayout(const Rect& rect)
- {
- ForeachChild([rect](Control* control)
- {
- const auto layout_params = control->GetLayoutParams();
- const auto size = control->GetDesiredSize();
-
- auto&& calculate_anchor = [](const Alignment 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();
- }
- };
-
- control->Layout(Rect(Point(
- calculate_anchor(layout_params->width.alignment, rect.width, size.width),
- calculate_anchor(layout_params->height.alignment, rect.height, size.height)
- ), size));
- });
- }
-
- void Control::CheckAndNotifyPositionChanged()
- {
- if (this->old_position_ != this->position_)
- {
- PositionChangedEventArgs args(this, this, this->old_position_, this->position_);
- this->RaisePositionChangedEvent(args);
- this->old_position_ = this->position_;
- }
- }
-
- std::list<Control*> GetAncestorList(Control* control)
- {
- std::list<Control*> l;
- while (control != nullptr)
- {
- l.push_front(control);
- control = control->GetParent();
- }
- return l;
- }
-
- Control* FindLowestCommonAncestor(Control * left, Control * right)
- {
- if (left == nullptr || right == nullptr)
- return nullptr;
-
- auto&& left_list = GetAncestorList(left);
- auto&& right_list = GetAncestorList(right);
-
- // the root is different
- if (left_list.front() != right_list.front())
- return nullptr;
-
- // find the last same control or the last control (one is ancestor of the other)
- auto left_i = left_list.cbegin();
- auto right_i = right_list.cbegin();
- while (true)
- {
- if (left_i == left_list.cend())
- return *(--left_i);
- if (right_i == right_list.cend())
- return *(--right_i);
- if (*left_i != *right_i)
- return *(--left_i);
- ++left_i;
- ++right_i;
- }
- }
-
- Control * IsAncestorOrDescendant(Control * left, Control * right)
- {
- //Search up along the trunk from "left". Return if find "right".
- auto control = left;
- while (control != nullptr)
- {
- if (control == right)
- return control;
- control = control->GetParent();
- }
- //Search up along the trunk from "right". Return if find "left".
- control = right;
- while (control != nullptr)
- {
- if (control == left)
- return control;
- control = control->GetParent();
- }
- return nullptr;
- }
- }
-}
diff --git a/CruUI/ui/control.h b/CruUI/ui/control.h
deleted file mode 100644
index d6cbae40..00000000
--- a/CruUI/ui/control.h
+++ /dev/null
@@ -1,380 +0,0 @@
-#pragma once
-
-#include "system_headers.h"
-#include <unordered_map>
-#include <any>
-#include <typeinfo>
-#include <utility>
-#include <fmt/format.h>
-
-#include "base.h"
-#include "ui_base.h"
-#include "layout_base.h"
-#include "events/ui_event.h"
-
-namespace cru
-{
- namespace ui
- {
- class Control;
- class Window;
-
-
- //the position cache
- struct ControlPositionCache
- {
- //The lefttop relative to the ancestor.
- Point lefttop_position_absolute;
- };
-
-
- class Control : public Object
- {
- friend class Window;
- friend class LayoutManager;
-
- protected:
- struct WindowConstructorTag {}; //Used for constructor for class Window.
-
- explicit Control(bool container = false);
-
- // Used only for creating Window. It will set window_ as window.
- Control(WindowConstructorTag, Window* window);
-
- public:
- Control(const Control& other) = delete;
- Control(Control&& other) = delete;
- Control& operator=(const Control& other) = delete;
- Control& operator=(Control&& other) = delete;
- ~Control() override;
-
- public:
-
- //*************** region: tree ***************
-
- bool IsContainer() const
- {
- return is_container_;
- }
-
- //Get parent of control, return nullptr if it has no parent.
- Control* GetParent() const
- {
- return parent_;
- }
-
- //Traverse the children
- void ForeachChild(Function<void(Control*)>&& predicate) const;
- void ForeachChild(Function<FlowControl(Control*)>&& predicate) const;
-
- //Return a vector of all children. This function will create a
- //temporary copy of vector of children. If you just want to
- //traverse all children, just call ForeachChild.
- Vector<Control*> GetChildren() const
- {
- return children_;
- }
-
- //Add a child at tail.
- void AddChild(Control* control);
-
- //Add a child before the position.
- void AddChild(Control* control, int position);
-
- //Remove a child.
- void RemoveChild(Control* child);
-
- //Remove a child at specified position.
- void RemoveChild(int position);
-
- //Get the ancestor of the control.
- Control* GetAncestor();
-
- //Get the window if attached, otherwise, return nullptr.
- Window* GetWindow() const
- {
- return window_;
- }
-
- //Traverse the tree rooted the control including itself.
- void TraverseDescendants(Function<void(Control*)>&& predicate);
-
- //*************** region: position and size ***************
- // Position and size part must be isolated from layout part.
- // All the operations in this part must be done independently.
- // And layout part must use api of this part.
-
- //Get the lefttop relative to its parent.
- virtual Point GetPositionRelative();
-
- //Set the lefttop relative to its parent.
- virtual void SetPositionRelative(const Point& position);
-
- //Get the actual size.
- virtual Size GetSize();
-
- //Set the actual size directly without re-layout.
- virtual void SetSize(const Size& size);
-
- //Get lefttop relative to ancestor. This is only valid when
- //attached to window. Notice that the value is cached.
- //You can invalidate and recalculate it by calling "InvalidatePositionCache".
- Point GetPositionAbsolute() const;
-
- //Local point to absolute point.
- Point LocalToAbsolute(const Point& point) const;
-
- //Absolute point to local point.
- Point AbsoluteToLocal(const Point& point) const;
-
- virtual bool IsPointInside(const Point& point);
-
-
- //*************** region: graphic ***************
-
- //Draw this control and its child controls.
- void Draw(ID2D1DeviceContext* device_context);
-
- virtual void Repaint();
-
- //*************** region: focus ***************
-
- bool RequestFocus();
-
- bool HasFocus();
-
- bool IsFocusOnPressed() const
- {
- return is_focus_on_pressed_;
- }
-
- void SetFocusOnPressed(const bool value)
- {
- is_focus_on_pressed_ = value;
- }
-
- //*************** region: layout ***************
-
- void Relayout();
-
- void Measure(const Size& available_size);
-
- void Layout(const Rect& rect);
-
- Size GetDesiredSize() const;
-
- void SetDesiredSize(const Size& desired_size);
-
- BasicLayoutParams* GetLayoutParams()
- {
- return &layout_params_;
- }
-
- //*************** region: additional properties ***************
- template <typename T>
- std::optional<T> GetAdditionalProperty(const String& key)
- {
- try
- {
- const auto find_result = additional_properties_.find(key);
- if (find_result != additional_properties_.cend())
- return std::any_cast<T>(find_result->second);
- else
- return std::nullopt;
- }
- catch (const std::bad_any_cast&)
- {
- throw std::runtime_error(fmt::format("Key \"{}\" is not of the type {}.", ToUtf8String(key), typeid(T).name()));
- }
- }
-
- template <typename T>
- void SetAdditionalProperty(const String& key, const T& value)
- {
- additional_properties_[key] = std::make_any<T>(value);
- }
-
- template <typename T>
- void SetAdditionalProperty(const String& key, T&& value)
- {
- additional_properties_[key] = std::make_any<T>(std::move(value));
- }
-
- //*************** region: events ***************
- //Raised when mouse enter the control.
- events::MouseEvent mouse_enter_event;
- //Raised when mouse is leave the control.
- events::MouseEvent mouse_leave_event;
- //Raised when mouse is move in the control.
- events::MouseEvent mouse_move_event;
- //Raised when a mouse button is pressed in the control.
- events::MouseButtonEvent mouse_down_event;
- //Raised when a mouse button is released in the control.
- events::MouseButtonEvent mouse_up_event;
- //Raised when a mouse button is pressed in the control and released in the control with mouse not leaving it between two operations.
- events::MouseButtonEvent mouse_click_event;
-
- events::KeyEvent key_down_event;
- events::KeyEvent key_up_event;
- events::CharEvent char_event;
-
- events::FocusChangeEvent get_focus_event;
- events::FocusChangeEvent lose_focus_event;
-
- events::DrawEvent draw_event;
-
- events::PositionChangedEvent position_changed_event;
- events::SizeChangedEvent size_changed_event;
-
- protected:
- //Invoked when a child is added. Overrides should invoke base.
- virtual void OnAddChild(Control* child);
- //Invoked when a child is removed. Overrides should invoke base.
- virtual void OnRemoveChild(Control* child);
-
- //Invoked when the control is attached to a window. Overrides should invoke base.
- virtual void OnAttachToWindow(Window* window);
- //Invoked when the control is detached to a window. Overrides should invoke base.
- virtual void OnDetachToWindow(Window* window);
-
- virtual void OnDraw(ID2D1DeviceContext* device_context);
-
-
- // For a event, the window event system will first dispatch event to core functions.
- // Therefore for particular controls, you should do essential actions in core functions,
- // and override version should invoke base version. The base core function
- // in "Control" class will call corresponding non-core function and call "Raise" on
- // event objects. So user custom actions should be done by overriding non-core function
- // and calling the base version is optional.
-
- //*************** region: position and size event ***************
- virtual void OnPositionChanged(events::PositionChangedEventArgs& args);
- virtual void OnSizeChanged(events::SizeChangedEventArgs& args);
-
- virtual void OnPositionChangedCore(events::PositionChangedEventArgs& args);
- virtual void OnSizeChangedCore(events::SizeChangedEventArgs& args);
-
- void RaisePositionChangedEvent(events::PositionChangedEventArgs& args);
- void RaiseSizeChangedEvent(events::SizeChangedEventArgs& args);
-
- //*************** region: mouse event ***************
- virtual void OnMouseEnter(events::MouseEventArgs& args);
- virtual void OnMouseLeave(events::MouseEventArgs& args);
- virtual void OnMouseMove(events::MouseEventArgs& args);
- virtual void OnMouseDown(events::MouseButtonEventArgs& args);
- virtual void OnMouseUp(events::MouseButtonEventArgs& args);
- virtual void OnMouseClick(events::MouseButtonEventArgs& args);
-
- virtual void OnMouseEnterCore(events::MouseEventArgs& args);
- virtual void OnMouseLeaveCore(events::MouseEventArgs& args);
- virtual void OnMouseMoveCore(events::MouseEventArgs& args);
- virtual void OnMouseDownCore(events::MouseButtonEventArgs& args);
- virtual void OnMouseUpCore(events::MouseButtonEventArgs& args);
- virtual void OnMouseClickCore(events::MouseButtonEventArgs& args);
-
- void RaiseMouseEnterEvent(events::MouseEventArgs& args);
- void RaiseMouseLeaveEvent(events::MouseEventArgs& args);
- void RaiseMouseMoveEvent(events::MouseEventArgs& args);
- void RaiseMouseDownEvent(events::MouseButtonEventArgs& args);
- void RaiseMouseUpEvent(events::MouseButtonEventArgs& args);
- void RaiseMouseClickEvent(events::MouseButtonEventArgs& args);
-
- virtual void OnMouseClickBegin(MouseButton button);
- virtual void OnMouseClickEnd(MouseButton button);
-
- //*************** region: keyboard event ***************
- virtual void OnKeyDown(events::KeyEventArgs& args);
- virtual void OnKeyUp(events::KeyEventArgs& args);
- virtual void OnChar(events::CharEventArgs& args);
-
- virtual void OnKeyDownCore(events::KeyEventArgs& args);
- virtual void OnKeyUpCore(events::KeyEventArgs& args);
- virtual void OnCharCore(events::CharEventArgs& args);
-
- void RaiseKeyDownEvent(events::KeyEventArgs& args);
- void RaiseKeyUpEvent(events::KeyEventArgs& args);
- void RaiseCharEvent(events::CharEventArgs& args);
-
- //*************** region: focus event ***************
- virtual void OnGetFocus(events::FocusChangeEventArgs& args);
- virtual void OnLoseFocus(events::FocusChangeEventArgs& args);
-
- virtual void OnGetFocusCore(events::FocusChangeEventArgs& args);
- virtual void OnLoseFocusCore(events::FocusChangeEventArgs& args);
-
- void RaiseGetFocusEvent(events::FocusChangeEventArgs& args);
- void RaiseLoseFocusEvent(events::FocusChangeEventArgs& args);
-
- //*************** region: layout ***************
- virtual Size OnMeasure(const Size& available_size);
- virtual void OnLayout(const Rect& rect);
-
- private:
- // Only for layout manager to use.
- // Check if the old position is updated to current position.
- // If not, then a notify of position change and update will
- // be done.
- void CheckAndNotifyPositionChanged();
-
- void ThrowIfNotContainer() const
- {
- if (!is_container_)
- throw std::runtime_error("You can't perform such operation on a non-container control.");
- }
-
- private:
- bool is_container_;
-
- protected:
- Window * window_ = nullptr; // protected for Window class to write it as itself in constructor.
-
- private:
- Control * parent_ = nullptr;
- Vector<Control*> children_{};
-
- // When position is changed and notification hasn't been
- // sent, it will be the old position. When position is changed
- // more than once, it will be the oldest position since last
- // notification. If notification has been sent, it will be updated
- // to position_.
- Point old_position_ = Point::Zero();
- Point position_ = Point::Zero();
- Size size_ = Size::Zero();
-
- ControlPositionCache position_cache_{};
-
- bool is_mouse_inside_ = false;
-
- std::unordered_map<MouseButton, bool> is_mouse_click_valid_map_
- {
- { MouseButton::Left, true },
- { MouseButton::Middle, true },
- { MouseButton::Right, true }
- }; // used for clicking determination
-
- BasicLayoutParams layout_params_{};
- Size desired_size_ = Size::Zero();
-
- std::unordered_map<String, std::any> additional_properties_{};
-
- bool is_focus_on_pressed_ = true;
- };
-
- // Find the lowest common ancestor.
- // Return nullptr if "left" and "right" are not in the same tree.
- Control* FindLowestCommonAncestor(Control* left, Control* right);
-
- // Return the ancestor if one control is the ancestor of the other one, otherwise nullptr.
- Control* IsAncestorOrDescendant(Control* left, Control* right);
-
- template <typename TControl, typename... Args>
- TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, Args&&... args)
- {
- static_assert(std::is_base_of_v<Control, TControl>, "TControl is not a control class.");
- TControl* control = TControl::Create(std::forward<Args>(args)...);
- control->GetLayoutParams()->width = width;
- control->GetLayoutParams()->height = height;
- return control;
- }
- }
-}
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_;
- };
-}
diff --git a/CruUI/ui/events/ui_event.cpp b/CruUI/ui/events/ui_event.cpp
deleted file mode 100644
index 59623bab..00000000
--- a/CruUI/ui/events/ui_event.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "ui_event.h"
-
-#include "ui/control.h"
-
-namespace cru
-{
- namespace ui
- {
- namespace events
- {
- Point MouseEventArgs::GetPoint(Control* control) const
- {
- if (point_.has_value())
- return control->AbsoluteToLocal(point_.value());
- return Point();
- }
- }
- }
-}
diff --git a/CruUI/ui/events/ui_event.h b/CruUI/ui/events/ui_event.h
deleted file mode 100644
index b042b706..00000000
--- a/CruUI/ui/events/ui_event.h
+++ /dev/null
@@ -1,317 +0,0 @@
-#pragma once
-
-#include "system_headers.h"
-#include <optional>
-
-#include "base.h"
-#include "cru_event.h"
-#include "ui/ui_base.h"
-
-namespace cru
-{
- namespace ui
- {
- class Control;
-
- namespace events
- {
- class UiEventArgs : public BasicEventArgs
- {
- public:
- UiEventArgs(Object* sender, Object* original_sender)
- : BasicEventArgs(sender), original_sender_(original_sender)
- {
-
- }
-
- UiEventArgs(const UiEventArgs& other) = default;
- UiEventArgs(UiEventArgs&& other) = default;
- UiEventArgs& operator=(const UiEventArgs& other) = default;
- UiEventArgs& operator=(UiEventArgs&& other) = default;
- ~UiEventArgs() override = default;
-
- Object* GetOriginalSender() const
- {
- return original_sender_;
- }
-
- private:
- Object* original_sender_;
- };
-
-
- class MouseEventArgs : public UiEventArgs
- {
- public:
- MouseEventArgs(Object* sender, Object* original_sender, const std::optional<Point>& point = std::nullopt)
- : UiEventArgs(sender, original_sender), point_(point)
- {
-
- }
- MouseEventArgs(const MouseEventArgs& other) = default;
- MouseEventArgs(MouseEventArgs&& other) = default;
- MouseEventArgs& operator=(const MouseEventArgs& other) = default;
- MouseEventArgs& operator=(MouseEventArgs&& other) = default;
- ~MouseEventArgs() override = default;
-
- Point GetPoint(Control* control) const;
-
- private:
- std::optional<Point> point_;
- };
-
-
- class MouseButtonEventArgs : public MouseEventArgs
- {
- public:
- MouseButtonEventArgs(Object* sender, Object* original_sender, const Point& point, const MouseButton button)
- : MouseEventArgs(sender, original_sender, point), button_(button)
- {
-
- }
- MouseButtonEventArgs(const MouseButtonEventArgs& other) = default;
- MouseButtonEventArgs(MouseButtonEventArgs&& other) = default;
- MouseButtonEventArgs& operator=(const MouseButtonEventArgs& other) = default;
- MouseButtonEventArgs& operator=(MouseButtonEventArgs&& other) = default;
- ~MouseButtonEventArgs() override = default;
-
- MouseButton GetMouseButton() const
- {
- return button_;
- }
-
- private:
- MouseButton button_;
- };
-
-
- class DrawEventArgs : public UiEventArgs
- {
- public:
- DrawEventArgs(Object* sender, Object* original_sender, ID2D1DeviceContext* device_context)
- : UiEventArgs(sender, original_sender), device_context_(device_context)
- {
-
- }
- DrawEventArgs(const DrawEventArgs& other) = default;
- DrawEventArgs(DrawEventArgs&& other) = default;
- DrawEventArgs& operator=(const DrawEventArgs& other) = default;
- DrawEventArgs& operator=(DrawEventArgs&& other) = default;
- ~DrawEventArgs() = default;
-
- ID2D1DeviceContext* GetDeviceContext() const
- {
- return device_context_;
- }
-
- private:
- ID2D1DeviceContext * device_context_;
- };
-
-
- class PositionChangedEventArgs : public UiEventArgs
- {
- public:
- PositionChangedEventArgs(Object* sender, Object* original_sender, const Point& old_position, const Point& new_position)
- : UiEventArgs(sender, original_sender), old_position_(old_position), new_position_(new_position)
- {
-
- }
- PositionChangedEventArgs(const PositionChangedEventArgs& other) = default;
- PositionChangedEventArgs(PositionChangedEventArgs&& other) = default;
- PositionChangedEventArgs& operator=(const PositionChangedEventArgs& other) = default;
- PositionChangedEventArgs& operator=(PositionChangedEventArgs&& other) = default;
- ~PositionChangedEventArgs() override = default;
-
- Point GetOldPosition() const
- {
- return old_position_;
- }
-
- Point GetNewPosition() const
- {
- return new_position_;
- }
-
- private:
- Point old_position_;
- Point new_position_;
- };
-
-
- class SizeChangedEventArgs : public UiEventArgs
- {
- public:
- SizeChangedEventArgs(Object* sender, Object* original_sender, const Size& old_size, const Size& new_size)
- : UiEventArgs(sender, original_sender), old_size_(old_size), new_size_(new_size)
- {
-
- }
- SizeChangedEventArgs(const SizeChangedEventArgs& other) = default;
- SizeChangedEventArgs(SizeChangedEventArgs&& other) = default;
- SizeChangedEventArgs& operator=(const SizeChangedEventArgs& other) = default;
- SizeChangedEventArgs& operator=(SizeChangedEventArgs&& other) = default;
- ~SizeChangedEventArgs() override = default;
-
- Size GetOldSize() const
- {
- return old_size_;
- }
-
- Size GetNewSize() const
- {
- return new_size_;
- }
-
- private:
- Size old_size_;
- Size new_size_;
- };
-
- class FocusChangeEventArgs : public UiEventArgs
- {
- public:
- FocusChangeEventArgs(Object* sender, Object* original_sender, const bool is_window = false)
- : UiEventArgs(sender, original_sender), is_window_(is_window)
- {
-
- }
- FocusChangeEventArgs(const FocusChangeEventArgs& other) = default;
- FocusChangeEventArgs(FocusChangeEventArgs&& other) = default;
- FocusChangeEventArgs& operator=(const FocusChangeEventArgs& other) = default;
- FocusChangeEventArgs& operator=(FocusChangeEventArgs&& other) = default;
- ~FocusChangeEventArgs() override = default;
-
- // Return whether the focus change is caused by the window-wide focus change.
- bool IsWindow() const
- {
- return is_window_;
- }
-
- private:
- bool is_window_;
- };
-
- class ToggleEventArgs : public UiEventArgs
- {
- public:
- ToggleEventArgs(Object* sender, Object* original_sender, bool new_state)
- : UiEventArgs(sender, original_sender), new_state_(new_state)
- {
-
- }
- ToggleEventArgs(const ToggleEventArgs& other) = default;
- ToggleEventArgs(ToggleEventArgs&& other) = default;
- ToggleEventArgs& operator=(const ToggleEventArgs& other) = default;
- ToggleEventArgs& operator=(ToggleEventArgs&& other) = default;
- ~ToggleEventArgs() override = default;
-
- bool GetNewState() const
- {
- return new_state_;
- }
-
- private:
- bool new_state_;
- };
-
- struct WindowNativeMessage
- {
- HWND hwnd;
- int msg;
- WPARAM w_param;
- LPARAM l_param;
- };
-
- class WindowNativeMessageEventArgs : public UiEventArgs
- {
- public:
- WindowNativeMessageEventArgs(Object* sender, Object* original_sender, const WindowNativeMessage& message)
- : UiEventArgs(sender, original_sender), message_(message), result_(std::nullopt)
- {
-
- }
- WindowNativeMessageEventArgs(const WindowNativeMessageEventArgs& other) = default;
- WindowNativeMessageEventArgs(WindowNativeMessageEventArgs&& other) = default;
- WindowNativeMessageEventArgs& operator=(const WindowNativeMessageEventArgs& other) = default;
- WindowNativeMessageEventArgs& operator=(WindowNativeMessageEventArgs&& other) = default;
- ~WindowNativeMessageEventArgs() override = default;
-
- WindowNativeMessage GetWindowMessage() const
- {
- return message_;
- }
-
- std::optional<LRESULT> GetResult() const
- {
- return result_;
- }
-
- void SetResult(const std::optional<LRESULT> result)
- {
- result_ = result;
- }
-
- private:
- WindowNativeMessage message_;
- std::optional<LRESULT> result_;
- };
-
- class KeyEventArgs : public UiEventArgs
- {
- public:
- KeyEventArgs(Object* sender, Object* original_sender, int virtual_code)
- : UiEventArgs(sender, original_sender), virtual_code_(virtual_code)
- {
- }
- KeyEventArgs(const KeyEventArgs& other) = default;
- KeyEventArgs(KeyEventArgs&& other) = default;
- KeyEventArgs& operator=(const KeyEventArgs& other) = default;
- KeyEventArgs& operator=(KeyEventArgs&& other) = default;
- ~KeyEventArgs() override = default;
-
- int GetVirtualCode() const
- {
- return virtual_code_;
- }
-
- private:
- int virtual_code_;
- };
-
- class CharEventArgs : public UiEventArgs
- {
- public:
- CharEventArgs(Object* sender, Object* original_sender, wchar_t c)
- : UiEventArgs(sender, original_sender), c_(c)
- {
- }
- CharEventArgs(const CharEventArgs& other) = default;
- CharEventArgs(CharEventArgs&& other) = default;
- CharEventArgs& operator=(const CharEventArgs& other) = default;
- CharEventArgs& operator=(CharEventArgs&& other) = default;
- ~CharEventArgs() override = default;
-
- wchar_t GetChar() const
- {
- return c_;
- }
-
- private:
- wchar_t c_;
- };
-
- using UiEvent = Event<UiEventArgs>;
- using MouseEvent = Event<MouseEventArgs>;
- using MouseButtonEvent = Event<MouseButtonEventArgs>;
- using DrawEvent = Event<DrawEventArgs>;
- using PositionChangedEvent = Event<PositionChangedEventArgs>;
- using SizeChangedEvent = Event<SizeChangedEventArgs>;
- using FocusChangeEvent = Event<FocusChangeEventArgs>;
- using ToggleEvent = Event<ToggleEventArgs>;
- using WindowNativeMessageEvent = Event<WindowNativeMessageEventArgs>;
- using KeyEvent = Event<KeyEventArgs>;
- using CharEvent = Event<CharEventArgs>;
- }
- }
-} \ No newline at end of file
diff --git a/CruUI/ui/layout_base.cpp b/CruUI/ui/layout_base.cpp
deleted file mode 100644
index a26379a0..00000000
--- a/CruUI/ui/layout_base.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "layout_base.h"
-
-#include "application.h"
-#include "control.h"
-
-namespace cru::ui
-{
- LayoutManager* LayoutManager::GetInstance()
- {
- static LayoutManager layout_manager;
- return &layout_manager;
- }
-
- void LayoutManager::InvalidateControlPositionCache(Control * control)
- {
- if (cache_invalid_controls_.count(control) == 1)
- return;
-
- // find descendant then erase it; find ancestor then just return.
- auto i = cache_invalid_controls_.cbegin();
- while (i != cache_invalid_controls_.cend())
- {
- auto current_i = i++;
- const auto result = IsAncestorOrDescendant(*current_i, control);
- if (result == control)
- cache_invalid_controls_.erase(current_i);
- else if (result != nullptr)
- return; // find a ancestor of "control", just return
- }
-
- cache_invalid_controls_.insert(control);
-
- if (cache_invalid_controls_.size() == 1) // when insert just now and not repeat to "InvokeLater".
- {
- InvokeLater([this] {
-
- RefreshInvalidControlPositionCache(); // first refresh position cache.
- for (const auto i : cache_invalid_controls_) // traverse all descendants of position-invalid controls and notify position change event
- i->TraverseDescendants([](Control* control)
- {
- control->CheckAndNotifyPositionChanged();
- });
- cache_invalid_controls_.clear(); // after update and notify, clear the set.
-
- });
- }
- }
-
- void LayoutManager::RefreshInvalidControlPositionCache()
- {
- for (const auto i : cache_invalid_controls_)
- RefreshControlPositionCache(i);
- }
-
- void LayoutManager::RefreshControlPositionCache(Control * control)
- {
- auto point = Point::Zero();
- auto parent = control;
- while ((parent = parent->GetParent())) {
- const auto p = parent->GetPositionRelative();
- point.x += p.x;
- point.y += p.y;
- }
- RefreshControlPositionCacheInternal(control, point);
- }
-
- void LayoutManager::RefreshControlPositionCacheInternal(Control * control, const Point & parent_lefttop_absolute)
- {
- const auto position = control->GetPositionRelative();
- Point lefttop(
- parent_lefttop_absolute.x + position.x,
- parent_lefttop_absolute.y + position.y
- );
- control->position_cache_.lefttop_position_absolute = lefttop;
- control->ForeachChild([lefttop](Control* c) {
- RefreshControlPositionCacheInternal(c, lefttop);
- });
- }
-}
diff --git a/CruUI/ui/layout_base.h b/CruUI/ui/layout_base.h
deleted file mode 100644
index 163b99b2..00000000
--- a/CruUI/ui/layout_base.h
+++ /dev/null
@@ -1,136 +0,0 @@
-#pragma once
-
-#include "system_headers.h"
-#include <unordered_set>
-
-#include "base.h"
-#include "ui_base.h"
-
-namespace cru
-{
- namespace ui
- {
- class Control;
-
- enum class Alignment
- {
- Center,
- Start,
- End
- };
-
- enum class MeasureMode
- {
- Exactly,
- Content,
- Stretch
- };
-
- struct LayoutSideParams final
- {
- constexpr static LayoutSideParams Exactly(const float length, const Alignment alignment = Alignment::Center)
- {
- return LayoutSideParams(MeasureMode::Exactly, length, alignment);
- }
-
- constexpr static LayoutSideParams Content(const Alignment alignment = Alignment::Center)
- {
- return LayoutSideParams(MeasureMode::Content, 0, alignment);
- }
-
- constexpr static LayoutSideParams Stretch(const Alignment alignment = Alignment::Center)
- {
- return LayoutSideParams(MeasureMode::Stretch, 0, alignment);
- }
-
- constexpr LayoutSideParams() = default;
-
- constexpr explicit LayoutSideParams(const MeasureMode mode, const float length, const Alignment alignment)
- : length(length), mode(mode), alignment(alignment)
- {
-
- }
-
- constexpr bool Validate() const
- {
- if (mode == MeasureMode::Exactly && length < 0.0)
- {
-#ifdef CRU_DEBUG
- ::OutputDebugStringW(L"LayoutSideParams validation error: mode is Exactly but length is less than 0.\n");
-#endif
- return false;
- }
- return true;
- }
-
- float length = 0.0;
- MeasureMode mode = MeasureMode::Content;
- Alignment alignment = Alignment::Center;
- };
-
- struct BasicLayoutParams final
- {
- BasicLayoutParams() = default;
- BasicLayoutParams(const BasicLayoutParams&) = default;
- BasicLayoutParams(BasicLayoutParams&&) = default;
- BasicLayoutParams& operator = (const BasicLayoutParams&) = default;
- BasicLayoutParams& operator = (BasicLayoutParams&&) = default;
- ~BasicLayoutParams() = default;
-
- bool Validate() const
- {
- if (!width.Validate())
- {
-#ifdef CRU_DEBUG
- ::OutputDebugStringW(L"Width(LayoutSideParams) is not valid.");
-#endif
- return false;
- }
- if (!height.Validate())
- {
-#ifdef CRU_DEBUG
- ::OutputDebugStringW(L"Height(LayoutSideParams) is not valid.");
-#endif
- return false;
- }
- return true;
- }
-
- LayoutSideParams width;
- LayoutSideParams height;
- };
-
-
- class LayoutManager : public Object
- {
- public:
- static LayoutManager* GetInstance();
-
- public:
- LayoutManager() = default;
- LayoutManager(const LayoutManager& other) = delete;
- LayoutManager(LayoutManager&& other) = delete;
- LayoutManager& operator=(const LayoutManager& other) = delete;
- LayoutManager& operator=(LayoutManager&& other) = delete;
- ~LayoutManager() override = default;
-
- //Mark position cache of the control and its descendants invalid,
- //(which is saved as an auto-managed list internal)
- //and send a message to refresh them.
- void InvalidateControlPositionCache(Control* control);
-
- //Refresh position cache of the control and its descendants whose cache
- //has been marked as invalid.
- void RefreshInvalidControlPositionCache();
-
- //Refresh position cache of the control and its descendants immediately.
- static void RefreshControlPositionCache(Control* control);
-
- private:
- static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute);
-
- private:
- std::unordered_set<Control*> cache_invalid_controls_;
- };
- }
-}
diff --git a/CruUI/ui/ui_base.cpp b/CruUI/ui/ui_base.cpp
deleted file mode 100644
index 550432e4..00000000
--- a/CruUI/ui/ui_base.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "ui_base.h"
-
-namespace cru {
- namespace ui {
- }
-}
diff --git a/CruUI/ui/ui_base.h b/CruUI/ui/ui_base.h
deleted file mode 100644
index 43f3c498..00000000
--- a/CruUI/ui/ui_base.h
+++ /dev/null
@@ -1,154 +0,0 @@
-#pragma once
-
-
-namespace cru
-{
- namespace ui
- {
- struct Point
- {
- constexpr static Point Zero()
- {
- return Point(0, 0);
- }
-
- constexpr Point() = default;
- constexpr Point(const float x, const float y) : x(x), y(y) { }
-
- float x = 0;
- float y = 0;
- };
-
- constexpr bool operator==(const Point& left, const Point& right)
- {
- return left.x == right.x && left.y == right.y;
- }
-
- constexpr bool operator!=(const Point& left, const Point& right)
- {
- return !(left == right);
- }
-
- struct Size
- {
- constexpr static Size Zero()
- {
- return Size(0, 0);
- }
-
- constexpr Size() = default;
- constexpr Size(const float width, const float height) : width(width), height(height) { }
-
- float width = 0;
- float height = 0;
- };
-
- constexpr Size operator + (const Size& left, const Size& right)
- {
- return Size(left.width + right.width, left.height + right.height);
- }
-
- constexpr Size operator - (const Size& left, const Size& right)
- {
- return Size(left.width - right.width, left.height - right.height);
- }
-
- struct Rect
- {
- constexpr Rect() = default;
- constexpr Rect(const float left, const float top, const float width, const float height)
- : left(left), top(top), width(width), height(height) { }
- constexpr Rect(const Point& lefttop, const Size& size)
- : left(lefttop.x), top(lefttop.y), width(size.width), height(size.height) { }
-
- constexpr static Rect FromVertices(const float left, const float top, const float right, const float bottom)
- {
- return Rect(left, top, right - left, bottom - top);
- }
-
- constexpr float GetRight() const
- {
- return left + width;
- }
-
- constexpr float GetBottom() const
- {
- return top + height;
- }
-
- constexpr Point GetLeftTop() const
- {
- return Point(left, top);
- }
-
- constexpr Point GetRightBottom() const
- {
- return Point(left + width, top + height);
- }
-
- constexpr Size GetSize() const
- {
- return Size(width, height);
- }
-
- constexpr bool IsPointInside(const Point& point) const
- {
- return
- point.x >= left &&
- point.x < GetRight() &&
- point.y >= top &&
- point.y < GetBottom();
- }
-
- float left = 0.0f;
- float top = 0.0f;
- float width = 0.0f;
- float height = 0.0f;
- };
-
- struct Thickness
- {
- constexpr static Thickness Zero()
- {
- return Thickness(0);
- }
-
- constexpr Thickness() : Thickness(0) { }
-
- constexpr explicit Thickness(const float width)
- : left(width), top(width), right(width), bottom(width) { }
-
- constexpr explicit Thickness(const float horizontal, const float vertical)
- : left(horizontal), top(vertical), right(horizontal), bottom(vertical) { }
-
- constexpr Thickness(const float left, const float top, const float right, const float bottom)
- : left(left), top(top), right(right), bottom(bottom) { }
-
-
- float left;
- float top;
- float right;
- float bottom;
- };
-
- enum class MouseButton
- {
- Left,
- Right,
- Middle
- };
-
- struct TextRange
- {
- constexpr TextRange() = default;
- constexpr TextRange(const int position, const int count)
- : position(position), count(count)
- {
-
- }
-
- unsigned position = 0;
- unsigned count = 0;
- };
- }
-}
diff --git a/CruUI/ui/window.cpp b/CruUI/ui/window.cpp
deleted file mode 100644
index 34a54512..00000000
--- a/CruUI/ui/window.cpp
+++ /dev/null
@@ -1,606 +0,0 @@
-#include "window.h"
-
-#include <fmt/format.h>
-
-#include "application.h"
-#include "graph/graph.h"
-#include "exception.h"
-
-namespace cru
-{
- namespace ui
- {
- WindowClass::WindowClass(const String& name, WNDPROC window_proc, HINSTANCE h_instance)
- : name_(name)
- {
- WNDCLASSEX window_class;
- window_class.cbSize = sizeof(WNDCLASSEX);
-
- window_class.style = CS_HREDRAW | CS_VREDRAW;
- window_class.lpfnWndProc = window_proc;
- window_class.cbClsExtra = 0;
- window_class.cbWndExtra = 0;
- window_class.hInstance = h_instance;
- window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
- window_class.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
- window_class.lpszMenuName = NULL;
- window_class.lpszClassName = name.c_str();
- window_class.hIconSm = NULL;
-
- atom_ = RegisterClassEx(&window_class);
- if (atom_ == 0)
- throw std::runtime_error("Failed to create window class.");
- }
-
- LRESULT __stdcall GeneralWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
- auto window = Application::GetInstance()->GetWindowManager()->FromHandle(hWnd);
-
- LRESULT result;
- if (window != nullptr && window->HandleWindowMessage(hWnd, Msg, wParam, lParam, result))
- return result;
-
- return DefWindowProc(hWnd, Msg, wParam, lParam);
- }
-
- WindowManager::WindowManager() {
- general_window_class_ = std::make_unique<WindowClass>(
- L"CruUIWindowClass",
- GeneralWndProc,
- Application::GetInstance()->GetInstanceHandle()
- );
- }
-
- void WindowManager::RegisterWindow(HWND hwnd, Window * window) {
- const auto find_result = window_map_.find(hwnd);
- if (find_result != window_map_.end())
- throw std::runtime_error("The hwnd is already in the map.");
-
- window_map_.emplace(hwnd, window);
- }
-
- void WindowManager::UnregisterWindow(HWND hwnd) {
- const auto find_result = window_map_.find(hwnd);
- if (find_result == window_map_.end())
- throw std::runtime_error("The hwnd is not in the map.");
- window_map_.erase(find_result);
-
- if (window_map_.empty())
- Application::GetInstance()->Quit(0);
- }
-
- Window* WindowManager::FromHandle(HWND hwnd) {
- const auto find_result = window_map_.find(hwnd);
- if (find_result == window_map_.end())
- return nullptr;
- else
- return find_result->second;
- }
-
- Vector<Window*> WindowManager::GetAllWindows() const
- {
- Vector<Window*> windows;
- for (auto [key, value] : window_map_)
- windows.push_back(value);
- return windows;
- }
-
- inline Point PiToDip(const POINT& pi_point)
- {
- return Point(
- graph::PixelToDipX(pi_point.x),
- graph::PixelToDipY(pi_point.y)
- );
- }
-
- Window::Window() : Control(WindowConstructorTag{}, this), control_list_({ this }) {
- const auto app = Application::GetInstance();
- hwnd_ = CreateWindowEx(0,
- app->GetWindowManager()->GetGeneralWindowClass()->GetName(),
- L"", WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- nullptr, nullptr, app->GetInstanceHandle(), nullptr
- );
-
- if (hwnd_ == nullptr)
- throw std::runtime_error("Failed to create window.");
-
- app->GetWindowManager()->RegisterWindow(hwnd_, this);
-
- render_target_ = app->GetGraphManager()->CreateWindowRenderTarget(hwnd_);
- }
-
- Window::~Window() {
- Close();
- TraverseDescendants([this](Control* control) {
- control->OnDetachToWindow(this);
- });
- }
-
- void Window::Close() {
- if (IsWindowValid())
- DestroyWindow(hwnd_);
- }
-
- void Window::Repaint() {
- if (IsWindowValid()) {
- InvalidateRect(hwnd_, nullptr, false);
- }
- }
-
- void Window::Show() {
- if (IsWindowValid()) {
- ShowWindow(hwnd_, SW_SHOWNORMAL);
- }
- }
-
- void Window::Hide() {
- if (IsWindowValid()) {
- ShowWindow(hwnd_, SW_HIDE);
- }
- }
-
- Size Window::GetClientSize() {
- if (!IsWindowValid())
- return Size();
-
- const auto pixel_rect = GetClientRectPixel();
- return Size(
- graph::PixelToDipX(pixel_rect.right),
- graph::PixelToDipY(pixel_rect.bottom)
- );
- }
-
- void Window::SetClientSize(const Size & size) {
- if (IsWindowValid()) {
- const auto window_style = static_cast<DWORD>(GetWindowLongPtr(hwnd_, GWL_STYLE));
- const auto window_ex_style = static_cast<DWORD>(GetWindowLongPtr(hwnd_, GWL_EXSTYLE));
-
- RECT rect;
- rect.left = 0;
- rect.top = 0;
- rect.right = graph::DipToPixelX(size.width);
- rect.bottom = graph::DipToPixelY(size.height);
- AdjustWindowRectEx(&rect, window_style, FALSE, window_ex_style);
-
- SetWindowPos(
- hwnd_, nullptr, 0, 0,
- rect.right - rect.left,
- rect.bottom - rect.top,
- SWP_NOZORDER | SWP_NOMOVE
- );
- }
- }
-
- Rect Window::GetWindowRect() {
- if (!IsWindowValid())
- return Rect();
-
- RECT rect;
- ::GetWindowRect(hwnd_, &rect);
-
- return Rect::FromVertices(
- graph::PixelToDipX(rect.left),
- graph::PixelToDipY(rect.top),
- graph::PixelToDipX(rect.right),
- graph::PixelToDipY(rect.bottom)
- );
- }
-
- void Window::SetWindowRect(const Rect & rect) {
- if (IsWindowValid()) {
- SetWindowPos(
- hwnd_, nullptr,
- graph::DipToPixelX(rect.left),
- graph::DipToPixelY(rect.top),
- graph::DipToPixelX(rect.GetRight()),
- graph::DipToPixelY(rect.GetBottom()),
- SWP_NOZORDER
- );
- }
- }
-
- bool Window::HandleWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param, LRESULT & result) {
-
- if (!native_message_event.IsNoHandler())
- {
- events::WindowNativeMessageEventArgs args(this, this, {hwnd, msg, w_param, l_param});
- native_message_event.Raise(args);
- if (args.GetResult().has_value())
- {
- result = args.GetResult().value();
- return true;
- }
- }
-
- switch (msg) {
- case WM_PAINT:
- OnPaintInternal();
- result = 0;
- return true;
- case WM_ERASEBKGND:
- result = 1;
- return true;
- case WM_SETFOCUS:
- OnSetFocusInternal();
- result = 0;
- return true;
- case WM_KILLFOCUS:
- OnKillFocusInternal();
- result = 0;
- return true;
- case WM_MOUSEMOVE:
- {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseMoveInternal(point);
- result = 0;
- return true;
- }
- case WM_LBUTTONDOWN:
- {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseDownInternal(MouseButton::Left, point);
- result = 0;
- return true;
- }
- case WM_LBUTTONUP:
- {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseUpInternal(MouseButton::Left, point);
- result = 0;
- return true;
- }
- case WM_RBUTTONDOWN:
- {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseDownInternal(MouseButton::Right, point);
- result = 0;
- return true;
- }
- case WM_RBUTTONUP:
- {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseUpInternal(MouseButton::Right, point);
- result = 0;
- return true;
- }
- case WM_MBUTTONDOWN:
- {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseDownInternal(MouseButton::Middle, point);
- result = 0;
- return true;
- }
- case WM_MBUTTONUP:
- {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseUpInternal(MouseButton::Middle, point);
- result = 0;
- return true;
- }
- case WM_KEYDOWN:
- OnKeyDownInternal(static_cast<int>(w_param));
- result = 0;
- return true;
- case WM_KEYUP:
- OnKeyUpInternal(static_cast<int>(w_param));
- result = 0;
- return true;
- case WM_CHAR:
- OnCharInternal(static_cast<wchar_t>(w_param));
- result = 0;
- return true;
- case WM_SIZE:
- OnResizeInternal(LOWORD(l_param), HIWORD(l_param));
- result = 0;
- return true;
- case WM_ACTIVATE:
- if (w_param == WA_ACTIVE || w_param == WA_CLICKACTIVE)
- OnActivatedInternal();
- else if (w_param == WA_INACTIVE)
- OnDeactivatedInternal();
- result = 0;
- return true;
- case WM_DESTROY:
- OnDestroyInternal();
- result = 0;
- return true;
- default:
- return false;
- }
- }
-
- Point Window::GetMousePosition()
- {
- POINT point;
- ::GetCursorPos(&point);
- ::ScreenToClient(hwnd_, &point);
- return PiToDip(point);
- }
-
- Point Window::GetPositionRelative()
- {
- return Point();
- }
-
- void Window::SetPositionRelative(const Point & position)
- {
-
- }
-
- Size Window::GetSize()
- {
- return GetClientSize();
- }
-
- void Window::SetSize(const Size & size)
- {
-
- }
-
- void Window::RefreshControlList() {
- control_list_.clear();
- TraverseDescendants([this](Control* control) {
- this->control_list_.push_back(control);
- });
- }
-
- Control * Window::HitTest(const Point & point)
- {
- for (auto i = control_list_.crbegin(); i != control_list_.crend(); ++i) {
- auto control = *i;
- if (control->IsPointInside(control->AbsoluteToLocal(point))) {
- return control;
- }
- }
- return nullptr;
- }
-
- bool Window::RequestFocusFor(Control * control)
- {
- if (control == nullptr)
- throw std::invalid_argument("The control to request focus can't be null. You can set it as the window.");
-
- if (!IsWindowValid())
- return false;
-
- if (!window_focus_)
- {
- focus_control_ = control;
- ::SetFocus(hwnd_);
- return true; // event dispatch will be done in window message handling function "OnSetFocusInternal".
- }
-
- if (focus_control_ == control)
- return true;
-
- DispatchEvent(focus_control_, &Control::RaiseLoseFocusEvent, nullptr, false);
-
- focus_control_ = control;
-
- DispatchEvent(control, &Control::RaiseGetFocusEvent, nullptr, false);
-
- return true;
- }
-
- Control* Window::GetFocusControl()
- {
- return focus_control_;
- }
-
- Control* Window::CaptureMouseFor(Control* control)
- {
- if (control != nullptr)
- {
- ::SetCapture(hwnd_);
- std::swap(mouse_capture_control_, control);
- DispatchMouseHoverControlChangeEvent(control ? control : mouse_hover_control_, mouse_capture_control_, GetMousePosition());
- return control;
- }
- else
- {
- return ReleaseCurrentMouseCapture();
- }
- }
-
- Control* Window::ReleaseCurrentMouseCapture()
- {
- if (mouse_capture_control_)
- {
- const auto previous = mouse_capture_control_;
- mouse_capture_control_ = nullptr;
- ::ReleaseCapture();
- DispatchMouseHoverControlChangeEvent(previous, mouse_hover_control_, GetMousePosition());
- return previous;
- }
- else
- {
- return nullptr;
- }
- }
-
-#ifdef CRU_DEBUG_DRAW_CONTROL_BORDER
- void Window::SetDebugDrawControlBorder(const bool value)
- {
- if (debug_draw_control_border_ != value)
- {
- debug_draw_control_border_ = value;
- Repaint();
- }
- }
-#endif
-
- RECT Window::GetClientRectPixel() {
- RECT rect{ };
- GetClientRect(hwnd_, &rect);
- return rect;
- }
-
- bool Window::IsMessageInQueue(UINT message)
- {
- MSG msg;
- return ::PeekMessageW(&msg, hwnd_, message, message, PM_NOREMOVE) != 0;
- }
-
- void Window::OnDestroyInternal() {
- Application::GetInstance()->GetWindowManager()->UnregisterWindow(hwnd_);
- hwnd_ = nullptr;
- }
-
- void Window::OnPaintInternal() {
- render_target_->SetAsTarget();
-
- auto device_context = render_target_->GetD2DDeviceContext();
-
- device_context->BeginDraw();
-
- //Clear the background.
- device_context->Clear(D2D1::ColorF(D2D1::ColorF::White));
-
- Draw(device_context.Get());
-
- ThrowIfFailed(
- device_context->EndDraw(), "Failed to draw window."
- );
-
- render_target_->Present();
-
- ValidateRect(hwnd_, nullptr);
- }
-
- void Window::OnResizeInternal(int new_width, int new_height) {
- render_target_->ResizeBuffer(new_width, new_height);
- Relayout();
- }
-
- void Window::OnSetFocusInternal()
- {
- window_focus_ = true;
- DispatchEvent(focus_control_, &Control::RaiseGetFocusEvent, nullptr, true);
- }
-
- void Window::OnKillFocusInternal()
- {
- window_focus_ = false;
- DispatchEvent(focus_control_, &Control::RaiseLoseFocusEvent, nullptr, true);
- }
-
- void Window::OnMouseMoveInternal(const POINT point)
- {
- const auto dip_point = PiToDip(point);
-
- //when mouse was previous outside the window
- if (mouse_hover_control_ == nullptr) {
- //invoke TrackMouseEvent to have WM_MOUSELEAVE sent.
- TRACKMOUSEEVENT tme;
- tme.cbSize = sizeof tme;
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = hwnd_;
-
- TrackMouseEvent(&tme);
- }
-
- //Find the first control that hit test succeed.
- const auto new_control_mouse_hover = HitTest(dip_point);
- const auto old_control_mouse_hover = mouse_hover_control_;
- mouse_hover_control_ = new_control_mouse_hover;
-
- if (mouse_capture_control_) // if mouse is captured
- {
- DispatchEvent(mouse_capture_control_, &Control::RaiseMouseMoveEvent, nullptr, dip_point);
- }
- else
- {
- DispatchMouseHoverControlChangeEvent(old_control_mouse_hover, new_control_mouse_hover, dip_point);
- DispatchEvent(new_control_mouse_hover, &Control::RaiseMouseMoveEvent, nullptr, dip_point);
- }
- }
-
- void Window::OnMouseLeaveInternal()
- {
- DispatchEvent(mouse_hover_control_, &Control::RaiseMouseLeaveEvent, nullptr);
- mouse_hover_control_ = nullptr;
- }
-
- void Window::OnMouseDownInternal(MouseButton button, POINT point)
- {
- const auto dip_point = PiToDip(point);
-
- Control* control;
-
- if (mouse_capture_control_)
- control = mouse_capture_control_;
- else
- control = HitTest(dip_point);
-
- DispatchEvent(control, &Control::RaiseMouseDownEvent, nullptr, dip_point, button);
- }
-
- void Window::OnMouseUpInternal(MouseButton button, POINT point)
- {
- const auto dip_point = PiToDip(point);
-
- Control* control;
-
- if (mouse_capture_control_)
- control = mouse_capture_control_;
- else
- control = HitTest(dip_point);
-
- DispatchEvent(control, &Control::RaiseMouseUpEvent, nullptr, dip_point, button);
- }
-
- void Window::OnKeyDownInternal(int virtual_code)
- {
- DispatchEvent(focus_control_, &Control::RaiseKeyDownEvent, nullptr, virtual_code);
- }
-
- void Window::OnKeyUpInternal(int virtual_code)
- {
- DispatchEvent(focus_control_, &Control::RaiseKeyUpEvent, nullptr, virtual_code);
- }
-
- void Window::OnCharInternal(wchar_t c)
- {
- DispatchEvent(focus_control_, &Control::RaiseCharEvent, nullptr, c);
- }
-
- void Window::OnActivatedInternal()
- {
- events::UiEventArgs args(this, this);
- activated_event.Raise(args);
- }
-
- void Window::OnDeactivatedInternal()
- {
- events::UiEventArgs args(this, this);
- deactivated_event.Raise(args);
- }
-
- void Window::DispatchMouseHoverControlChangeEvent(Control* old_control, Control* new_control, const Point& point)
- {
- if (new_control != old_control) //if the mouse-hover-on control changed
- {
- const auto lowest_common_ancestor = FindLowestCommonAncestor(old_control, new_control);
- if (old_control != nullptr) // if last mouse-hover-on control exists
- DispatchEvent(old_control, &Control::RaiseMouseLeaveEvent, lowest_common_ancestor); // dispatch mouse leave event.
- if (new_control != nullptr)
- DispatchEvent(new_control, &Control::RaiseMouseEnterEvent, lowest_common_ancestor, point); // dispatch mouse enter event.
- }
- }
- }
-}
diff --git a/CruUI/ui/window.h b/CruUI/ui/window.h
deleted file mode 100644
index 40d81a06..00000000
--- a/CruUI/ui/window.h
+++ /dev/null
@@ -1,276 +0,0 @@
-#pragma once
-
-#include "system_headers.h"
-#include <map>
-#include <list>
-#include <memory>
-
-#include "control.h"
-#include "events/ui_event.h"
-
-namespace cru {
- namespace graph {
- class WindowRenderTarget;
- }
-
- namespace ui {
- class WindowClass : public Object
- {
- public:
- WindowClass(const String& name, WNDPROC window_proc, HINSTANCE h_instance);
- WindowClass(const WindowClass& other) = delete;
- WindowClass(WindowClass&& other) = delete;
- WindowClass& operator=(const WindowClass& other) = delete;
- WindowClass& operator=(WindowClass&& other) = delete;
- ~WindowClass() override = default;
-
-
- const wchar_t* GetName() const
- {
- return name_.c_str();
- }
-
- ATOM GetAtom() const
- {
- return atom_;
- }
-
- private:
- String name_;
- ATOM atom_;
- };
-
- class WindowManager : public Object
- {
- public:
- WindowManager();
- WindowManager(const WindowManager& other) = delete;
- WindowManager(WindowManager&& other) = delete;
- WindowManager& operator=(const WindowManager& other) = delete;
- WindowManager& operator=(WindowManager&& other) = delete;
- ~WindowManager() override = default;
-
-
- //Get the general window class for creating ordinary window.
- WindowClass* GetGeneralWindowClass() const
- {
- return general_window_class_.get();
- }
-
- //Register a window newly created.
- //This function adds the hwnd to hwnd-window map.
- //It should be called immediately after a window was created.
- void RegisterWindow(HWND hwnd, Window* window);
-
- //Unregister a window that is going to be destroyed.
- //This function removes the hwnd from the hwnd-window map.
- //It should be called immediately before a window is going to be destroyed,
- void UnregisterWindow(HWND hwnd);
-
- //Return a pointer to the Window object related to the HWND or nullptr if the hwnd is not in the map.
- Window* FromHandle(HWND hwnd);
-
- Vector<Window*> GetAllWindows() const;
-
- private:
- std::unique_ptr<WindowClass> general_window_class_;
- std::map<HWND, Window*> window_map_;
- };
-
-
-
- class Window : public Control
- {
- friend class WindowManager;
- public:
- Window();
- Window(const Window& other) = delete;
- Window(Window&& other) = delete;
- Window& operator=(const Window& other) = delete;
- Window& operator=(Window&& other) = delete;
- ~Window() override;
-
- public:
- //*************** region: handle ***************
-
- //Get the handle of the window. Return null if window is invalid.
- HWND GetWindowHandle() const
- {
- return hwnd_;
- }
-
- //Return if the window is still valid, that is, hasn't been closed or destroyed.
- bool IsWindowValid() const
- {
- return hwnd_ != nullptr;
- }
-
-
- //*************** region: window operations ***************
-
- //Close and destroy the window if the window is valid.
- void Close();
-
- //Send a repaint message to the window's message queue which may make the window repaint.
- void Repaint() override;
-
- //Show the window.
- void Show();
-
- //Hide thw window.
- void Hide();
-
- //Get the client size.
- Size GetClientSize();
-
- //Set the client size and repaint.
- void SetClientSize(const Size& size);
-
- //Get the rect of the window containing frame.
- //The lefttop of the rect is relative to screen lefttop.
- Rect GetWindowRect();
-
- //Set the rect of the window containing frame.
- //The lefttop of the rect is relative to screen lefttop.
- void SetWindowRect(const Rect& rect);
-
- //Handle the raw window message.
- //Return true if the message is handled and get the result through "result" argument.
- //Return false if the message is not handled.
- bool HandleWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param, LRESULT& result);
-
- Point GetMousePosition();
-
- //*************** region: position and size ***************
-
- //Always return (0, 0) for a window.
- Point GetPositionRelative() override final;
-
- //This method has no effect for a window.
- void SetPositionRelative(const Point& position) override final;
-
- //Get the size of client area for a window.
- Size GetSize() override final;
-
- //This method has no effect for a window. Use SetClientSize instead.
- void SetSize(const Size& size) override final;
-
-
- //*************** region: features ***************
-
- //Refresh control list.
- //It should be invoked every time a control is added or removed from the tree.
- void RefreshControlList();
-
- //Get the most top control at "point".
- Control* HitTest(const Point& point);
-
-
- //*************** region: focus ***************
-
- //Request focus for specified control.
- bool RequestFocusFor(Control* control);
-
- //Get the control that has focus.
- Control* GetFocusControl();
-
-
- //*************** region: mouse capture ***************
-
- Control* CaptureMouseFor(Control* control);
- Control* ReleaseCurrentMouseCapture();
-
- //*************** region: debug ***************
-#ifdef CRU_DEBUG_DRAW_CONTROL_BORDER
- bool GetDebugDrawControlBorder() const
- {
- return debug_draw_control_border_;
- }
-
- void SetDebugDrawControlBorder(bool value);
-#endif
-
- public:
- //*************** region: events ***************
- events::UiEvent activated_event;
- events::UiEvent deactivated_event;
-
- events::WindowNativeMessageEvent native_message_event;
-
- private:
- //*************** region: native operations ***************
-
- //Get the client rect in pixel.
- RECT GetClientRectPixel();
-
- bool IsMessageInQueue(UINT message);
-
-
- //*************** region: native messages ***************
-
- void OnDestroyInternal();
- void OnPaintInternal();
- void OnResizeInternal(int new_width, int new_height);
-
- void OnSetFocusInternal();
- void OnKillFocusInternal();
-
- void OnMouseMoveInternal(POINT point);
- void OnMouseLeaveInternal();
- void OnMouseDownInternal(MouseButton button, POINT point);
- void OnMouseUpInternal(MouseButton button, POINT point);
-
- void OnKeyDownInternal(int virtual_code);
- void OnKeyUpInternal(int virtual_code);
- void OnCharInternal(wchar_t c);
-
- void OnActivatedInternal();
- void OnDeactivatedInternal();
-
- //*************** region: event dispatcher helper ***************
-
- template<typename EventArgs>
- using EventMethod = void (Control::*)(EventArgs&);
-
- // Dispatch the event.
- //
- // This will invoke the "event_method" of the control and its parent and parent's
- // parent ... (until "last_receiver" if it's not nullptr) with appropriate args.
- //
- // 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* original_sender, EventMethod<EventArgs> event_method, Control* last_receiver, Args&&... args)
- {
- auto control = original_sender;
- while (control != nullptr && control != last_receiver)
- {
- EventArgs event_args(control, original_sender, std::forward<Args>(args)...);
- (control->*event_method)(event_args);
- control = control->GetParent();
- }
- }
-
- void DispatchMouseHoverControlChangeEvent(Control* old_control, Control * new_control, const Point& point);
-
- private:
- HWND hwnd_ = nullptr;
- std::shared_ptr<graph::WindowRenderTarget> render_target_{};
-
- std::list<Control*> control_list_{};
-
- Control* mouse_hover_control_ = nullptr;
-
- bool window_focus_ = false;
- Control* focus_control_ = this; // "focus_control_" can't be nullptr
-
- Control* mouse_capture_control_ = nullptr;
-
-#ifdef CRU_DEBUG_DRAW_CONTROL_BORDER
- bool debug_draw_control_border_ = false;
-#endif
- };
- }
-}