aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2018-09-10 00:09:52 +0800
committercrupest <crupest@outlook.com>2018-09-10 00:09:52 +0800
commitaa8ba64f4f580552ba14325dd3e04f38a3c9a1de (patch)
treecde762da1a0bfb24c28a8a3dfa5253ad95a5b809
parent74031db4b8c366531db5be8fa8d765483ab377b0 (diff)
downloadcru-aa8ba64f4f580552ba14325dd3e04f38a3c9a1de.tar.gz
cru-aa8ba64f4f580552ba14325dd3e04f38a3c9a1de.tar.bz2
cru-aa8ba64f4f580552ba14325dd3e04f38a3c9a1de.zip
...
-rw-r--r--CruUI/CruUI.vcxproj6
-rw-r--r--CruUI/main.cpp20
-rw-r--r--CruUI/ui/control.cpp47
-rw-r--r--CruUI/ui/control.h2
-rw-r--r--CruUI/ui/controls/linear_layout.cpp8
-rw-r--r--CruUI/ui/controls/linear_layout.h6
-rw-r--r--CruUI/ui/controls/text_block.cpp15
-rw-r--r--CruUI/ui/controls/text_block.h11
-rw-r--r--CruUI/ui/window.cpp12
-rw-r--r--CruUI/ui/window.h404
10 files changed, 294 insertions, 237 deletions
diff --git a/CruUI/CruUI.vcxproj b/CruUI/CruUI.vcxproj
index ba46d963..62b23165 100644
--- a/CruUI/CruUI.vcxproj
+++ b/CruUI/CruUI.vcxproj
@@ -134,14 +134,16 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
- <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
diff --git a/CruUI/main.cpp b/CruUI/main.cpp
index bd0d3247..99f9ded6 100644
--- a/CruUI/main.cpp
+++ b/CruUI/main.cpp
@@ -66,19 +66,13 @@ int APIENTRY wWinMain(
//test 2
- LinearLayout layout;
- TextBlock text_block_1;
- text_block_1.SetText(L"Hello World!!!");
- TextBlock text_block_2;
- text_block_2.SetText(L"This is a very very very very very long sentence!!!");
- TextBlock text_block_3;
- text_block_3.SetText(L"By crupest!!!");
-
- layout.AddChild(&text_block_1);
- layout.AddChild(&text_block_2);
- layout.AddChild(&text_block_3);
-
- window.AddChild(&layout);
+ const auto layout = LinearLayout::Create();
+
+ layout->AddChild(TextBlock::Create(L"Hello World!!!"));
+ layout->AddChild(TextBlock::Create(L"This is a very very very very very long sentence!!!"));
+ layout->AddChild(TextBlock::Create(L"By crupest!!!"));
+
+ window.AddChild(layout);
window.Show();
diff --git a/CruUI/ui/control.cpp b/CruUI/ui/control.cpp
index ee6db284..507beee8 100644
--- a/CruUI/ui/control.cpp
+++ b/CruUI/ui/control.cpp
@@ -1,6 +1,8 @@
#include "control.h"
+#include <string>
#include <algorithm>
+#include <chrono>
#include "window.h"
#include "timer.h"
@@ -25,19 +27,29 @@ namespace cru {
}
+ Control::~Control()
+ {
+ ForeachChild([](auto control)
+ {
+ delete control;
+ });
+ }
+
void Control::ForeachChild(Action<Control*>&& predicate) const
{
- for (const auto child : children_)
- predicate(child);
+ if (is_container_)
+ for (const auto child : children_)
+ predicate(child);
}
void Control::ForeachChild(FlowControlAction<Control*>&& predicate) const
{
- for (const auto child : children_)
- {
- if (predicate(child) == FlowControl::Break)
- break;
- }
+ if (is_container_)
+ for (const auto child : children_)
+ {
+ if (predicate(child) == FlowControl::Break)
+ break;
+ }
}
void AddChildCheck(Control* control)
@@ -128,7 +140,8 @@ namespace cru {
void Control::TraverseDescendants(Action<Control*>&& predicate)
{
- TraverseDescendantsInternal(this, predicate);
+ if (is_container_)
+ TraverseDescendantsInternal(this, predicate);
}
Point Control::GetPositionRelative()
@@ -138,13 +151,16 @@ namespace cru {
void Control::SetPositionRelative(const Point & position)
{
- if (old_position_ == position) // if cache has been refreshed and no pending notify
- old_position_ = position_;
- position_ = position;
- if (auto window = GetWindow())
+ if (position != position_)
{
- window->GetLayoutManager()->InvalidateControlPositionCache(this);
- window->Repaint();
+ if (old_position_ == position) // if cache has been refreshed and no pending notify
+ old_position_ = position_;
+ position_ = position;
+ if (auto window = GetWindow())
+ {
+ window->GetLayoutManager()->InvalidateControlPositionCache(this);
+ window->Repaint();
+ }
}
}
@@ -241,9 +257,12 @@ namespace cru {
void Control::Layout(const Rect& rect)
{
+ auto before = std::chrono::steady_clock::now();
SetPositionRelative(rect.GetLeftTop());
SetSize(rect.GetSize());
OnLayout(rect);
+ auto after = std::chrono::steady_clock::now();
+ OutputDebugStringW((L"Layout time duration:" + std::to_wstring(std::chrono::duration_cast<std::chrono::milliseconds>(after - before).count()) + L"\n").c_str());
}
Size Control::GetDesiredSize() const
diff --git a/CruUI/ui/control.h b/CruUI/ui/control.h
index f4302e80..41401008 100644
--- a/CruUI/ui/control.h
+++ b/CruUI/ui/control.h
@@ -36,7 +36,7 @@ namespace cru
Control(Control&& other) = delete;
Control& operator=(const Control& other) = delete;
Control& operator=(Control&& other) = delete;
- ~Control() override = default;
+ ~Control() override;
public:
diff --git a/CruUI/ui/controls/linear_layout.cpp b/CruUI/ui/controls/linear_layout.cpp
index f639720d..1d88a4e1 100644
--- a/CruUI/ui/controls/linear_layout.cpp
+++ b/CruUI/ui/controls/linear_layout.cpp
@@ -44,9 +44,17 @@ namespace cru::ui::controls
{
control->Measure(rest_available_size_for_children);
if (orientation_ == Orientation::Horizontal)
+ {
rest_available_size_for_children.width -= control->GetDesiredSize().width;
+ if (rest_available_size_for_children.width < 0)
+ rest_available_size_for_children.width = 0;
+ }
else
+ {
rest_available_size_for_children.height -= control->GetDesiredSize().height;
+ if (rest_available_size_for_children.height < 0)
+ rest_available_size_for_children.height = 0;
+ }
});
auto actual_size_for_children = total_available_size_for_children - rest_available_size_for_children;
diff --git a/CruUI/ui/controls/linear_layout.h b/CruUI/ui/controls/linear_layout.h
index b8722b6f..74c504cb 100644
--- a/CruUI/ui/controls/linear_layout.h
+++ b/CruUI/ui/controls/linear_layout.h
@@ -13,6 +13,12 @@ namespace cru::ui::controls
Vertical
};
+ static LinearLayout* Create(const Orientation orientation = Orientation::Vertical)
+ {
+ return new LinearLayout(orientation);
+ }
+
+ private:
explicit LinearLayout(Orientation orientation = Orientation::Vertical);
protected:
diff --git a/CruUI/ui/controls/text_block.cpp b/CruUI/ui/controls/text_block.cpp
index 3649aea6..d15bd681 100644
--- a/CruUI/ui/controls/text_block.cpp
+++ b/CruUI/ui/controls/text_block.cpp
@@ -1,5 +1,7 @@
#include "text_block.h"
+#include <chrono>
+
#include "ui/window.h"
#include "graph/graph.h"
#include "exception.h"
@@ -27,9 +29,12 @@ namespace cru
void TextBlock::SetText(const String& text)
{
- const auto old_text = text_;
- text_ = text;
- OnTextChangedCore(old_text, text);
+ if (text_ != text)
+ {
+ const auto old_text = text_;
+ text_ = text;
+ OnTextChangedCore(old_text, text);
+ }
}
void TextBlock::SetBrush(const Microsoft::WRL::ComPtr<ID2D1Brush>& brush)
@@ -47,8 +52,12 @@ namespace cru
void TextBlock::OnSizeChangedCore(events::SizeChangedEventArgs& args)
{
+ auto before = std::chrono::steady_clock::now();
RecreateTextLayout();
Repaint();
+ auto after = std::chrono::steady_clock::now();
+ OutputDebugStringW((L"TextBlock OnSizeChangedCore time duration:" + std::to_wstring(std::chrono::duration_cast<std::chrono::milliseconds>(after - before).count()) + L"\n").c_str());
+
}
void TextBlock::OnDraw(ID2D1DeviceContext* device_context)
diff --git a/CruUI/ui/controls/text_block.h b/CruUI/ui/controls/text_block.h
index abf77112..04347a0c 100644
--- a/CruUI/ui/controls/text_block.h
+++ b/CruUI/ui/controls/text_block.h
@@ -15,11 +15,22 @@ namespace cru
public:
using TextLayoutHandler = Action<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;
+ }
+ private:
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;
diff --git a/CruUI/ui/window.cpp b/CruUI/ui/window.cpp
index 2c731a1e..392bca87 100644
--- a/CruUI/ui/window.cpp
+++ b/CruUI/ui/window.cpp
@@ -97,9 +97,9 @@ namespace cru
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();
- });
+ {
+ control->CheckAndNotifyPositionChanged();
+ });
cache_invalid_controls_.clear(); // after update and notify, clear the set.
});
}
@@ -401,6 +401,12 @@ namespace cru
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;
diff --git a/CruUI/ui/window.h b/CruUI/ui/window.h
index 7ecea456..9ffa4dc6 100644
--- a/CruUI/ui/window.h
+++ b/CruUI/ui/window.h
@@ -9,265 +9,267 @@
#include "control.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
- {
+ 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);
+ //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);
+ //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);
+ //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);
- private:
- std::unique_ptr<WindowClass> general_window_class_;
- std::map<HWND, Window*> window_map_;
- };
+ private:
+ std::unique_ptr<WindowClass> general_window_class_;
+ std::map<HWND, Window*> window_map_;
+ };
- class WindowLayoutManager : public Object
- {
- public:
- WindowLayoutManager() = default;
- WindowLayoutManager(const WindowLayoutManager& other) = delete;
- WindowLayoutManager(WindowLayoutManager&& other) = delete;
- WindowLayoutManager& operator=(const WindowLayoutManager& other) = delete;
- WindowLayoutManager& operator=(WindowLayoutManager&& other) = delete;
- ~WindowLayoutManager() override = default;
+ class WindowLayoutManager : public Object
+ {
+ public:
+ WindowLayoutManager() = default;
+ WindowLayoutManager(const WindowLayoutManager& other) = delete;
+ WindowLayoutManager(WindowLayoutManager&& other) = delete;
+ WindowLayoutManager& operator=(const WindowLayoutManager& other) = delete;
+ WindowLayoutManager& operator=(WindowLayoutManager&& other) = delete;
+ ~WindowLayoutManager() 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);
+ //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 whose cache
+ //has been marked as invalid.
+ void RefreshInvalidControlPositionCache();
- //Refresh position cache of the control and its descendants immediately.
- static void RefreshControlPositionCache(Control* control);
+ //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:
+ static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute);
- private:
- std::set<Control*> cache_invalid_controls_;
- };
+ private:
+ std::set<Control*> cache_invalid_controls_;
+ };
- 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;
+ 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: managers ***************
- WindowLayoutManager* GetLayoutManager() const
- {
- return layout_manager_.get();
- }
+ public:
+ //*************** region: managers ***************
+ WindowLayoutManager* GetLayoutManager() const
+ {
+ return layout_manager_.get();
+ }
- //*************** region: handle ***************
+ //*************** region: handle ***************
- //Get the handle of the window. Return null if window is invalid.
- HWND GetWindowHandle() const
- {
- return hwnd_;
- }
+ //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;
- }
+ //Return if the window is still valid, that is, hasn't been closed or destroyed.
+ bool IsWindowValid() const
+ {
+ return hwnd_ != nullptr;
+ }
- //*************** region: window operations ***************
+ //*************** region: window operations ***************
- //Close and destroy the window if the window is valid.
- void Close();
+ //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;
+ //Send a repaint message to the window's message queue which may make the window repaint.
+ void Repaint() override;
- //Show the window.
- void Show();
+ //Show the window.
+ void Show();
- //Hide thw window.
- void Hide();
+ //Hide thw window.
+ void Hide();
- //Get the client size.
- Size GetClientSize();
+ //Get the client size.
+ Size GetClientSize();
- //Set the client size and repaint.
- void SetClientSize(const Size& size);
+ //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();
+ //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);
+ //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);
+ //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);
- //*************** region: position and size ***************
+ //*************** region: position and size ***************
- //Always return (0, 0) for a window.
- Point GetPositionRelative() override final;
+ //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;
+ //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;
+ //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;
+ //This method has no effect for a window. Use SetClientSize instead.
+ void SetSize(const Size& size) override final;
- //*************** region: features ***************
+ //*************** region: features ***************
- //Refresh control list.
- //It should be invoked every time a control is added or removed from the tree.
- void RefreshControlList();
+ //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);
+ //Get the most top control at "point".
+ Control* HitTest(const Point& point);
-
- //*************** region: focus ***************
- //Request focus for specified control.
- bool RequestFocusFor(Control* control);
+ //*************** region: focus ***************
- //Get the control that has focus.
- Control* GetFocusControl();
+ //Request focus for specified control.
+ bool RequestFocusFor(Control* control);
+ //Get the control that has focus.
+ Control* GetFocusControl();
- private:
- //*************** region: native operations ***************
- //Get the client rect in pixel.
- RECT GetClientRectPixel();
+ private:
+ //*************** region: native operations ***************
+ //Get the client rect in pixel.
+ RECT GetClientRectPixel();
- //*************** region: native messages ***************
+ bool IsMessageInQueue(UINT message);
- void OnDestroyInternal();
- void OnPaintInternal();
- void OnResizeInternal(int new_width, int new_height);
- void OnSetFocusInternal();
- void OnKillFocusInternal();
+ //*************** region: native messages ***************
- void OnMouseMoveInternal(POINT point);
- void OnMouseLeaveInternal();
- void OnMouseDownInternal(MouseButton button, POINT point);
- void OnMouseUpInternal(MouseButton button, POINT point);
+ 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);
- //*************** 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();
- }
- }
+ //*************** region: event dispatcher helper ***************
- private:
- std::unique_ptr<WindowLayoutManager> layout_manager_;
+ template<typename EventArgs>
+ using EventMethod = void (Control::*)(EventArgs&);
- HWND hwnd_ = nullptr;
- std::shared_ptr<graph::WindowRenderTarget> render_target_{};
+ // 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();
+ }
+ }
- std::list<Control*> control_list_{};
+ private:
+ std::unique_ptr<WindowLayoutManager> layout_manager_;
- Control* mouse_hover_control_ = nullptr;
+ HWND hwnd_ = nullptr;
+ std::shared_ptr<graph::WindowRenderTarget> render_target_{};
- bool window_focus_ = false;
- Control* focus_control_ = this; // "focus_control_" can't be nullptr
- };
- }
+ std::list<Control*> control_list_{};
+
+ Control* mouse_hover_control_ = nullptr;
+
+ bool window_focus_ = false;
+ Control* focus_control_ = this; // "focus_control_" can't be nullptr
+ };
+ }
}