aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2018-11-07 20:20:26 +0800
committercrupest <crupest@outlook.com>2018-11-07 20:20:26 +0800
commite2efeb22595b263f6eac5563b163a2574aa2f0dc (patch)
treee371ab858ce124c0d2070096e41314e44af87ca2 /src
parent2b5b89e9483063f3af05fb5485043868d447994b (diff)
downloadcru-e2efeb22595b263f6eac5563b163a2574aa2f0dc.tar.gz
cru-e2efeb22595b263f6eac5563b163a2574aa2f0dc.tar.bz2
cru-e2efeb22595b263f6eac5563b163a2574aa2f0dc.zip
Reformat codes.
Diffstat (limited to 'src')
-rw-r--r--src/graph/graph.cpp416
-rw-r--r--src/graph/graph.h283
-rw-r--r--src/ui/control.cpp1535
-rw-r--r--src/ui/control.h691
-rw-r--r--src/ui/controls/text_block.cpp20
-rw-r--r--src/ui/cursor.h1
-rw-r--r--src/ui/events/ui_event.cpp16
-rw-r--r--src/ui/events/ui_event.h603
-rw-r--r--src/ui/layout_base.h301
-rw-r--r--src/ui/ui_base.cpp23
-rw-r--r--src/ui/ui_base.h243
-rw-r--r--src/ui/window.cpp1037
-rw-r--r--src/ui/window.h465
13 files changed, 2801 insertions, 2833 deletions
diff --git a/src/graph/graph.cpp b/src/graph/graph.cpp
index 30b51413..e8d58a58 100644
--- a/src/graph/graph.cpp
+++ b/src/graph/graph.cpp
@@ -3,243 +3,243 @@
#include "application.h"
#include "exception.h"
-namespace cru {
- namespace graph {
- using Microsoft::WRL::ComPtr;
-
- WindowRenderTarget::WindowRenderTarget(GraphManager* graph_manager, HWND hwnd)
- {
- this->graph_manager_ = graph_manager;
-
- const auto d3d11_device = graph_manager->GetD3D11Device();
- const auto dxgi_factory = graph_manager->GetDxgiFactory();
-
- // Allocate a descriptor.
- DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = { 0 };
- swap_chain_desc.Width = 0; // use automatic sizing
- swap_chain_desc.Height = 0;
- swap_chain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format
- swap_chain_desc.Stereo = false;
- swap_chain_desc.SampleDesc.Count = 1; // don't use multi-sampling
- swap_chain_desc.SampleDesc.Quality = 0;
- swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- swap_chain_desc.BufferCount = 2; // use double buffering to enable flip
- swap_chain_desc.Scaling = DXGI_SCALING_NONE;
- swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all apps must use this SwapEffect
- swap_chain_desc.Flags = 0;
-
-
-
- // Get the final swap chain for this window from the DXGI factory.
- ThrowIfFailed(
- dxgi_factory->CreateSwapChainForHwnd(
- d3d11_device.Get(),
- hwnd,
- &swap_chain_desc,
- nullptr,
- nullptr,
- &dxgi_swap_chain_
- )
- );
+namespace cru::graph
+{
+ using Microsoft::WRL::ComPtr;
+
+ WindowRenderTarget::WindowRenderTarget(GraphManager* graph_manager, HWND hwnd)
+ {
+ this->graph_manager_ = graph_manager;
+
+ const auto d3d11_device = graph_manager->GetD3D11Device();
+ const auto dxgi_factory = graph_manager->GetDxgiFactory();
+
+ // Allocate a descriptor.
+ DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = { 0 };
+ swap_chain_desc.Width = 0; // use automatic sizing
+ swap_chain_desc.Height = 0;
+ swap_chain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format
+ swap_chain_desc.Stereo = false;
+ swap_chain_desc.SampleDesc.Count = 1; // don't use multi-sampling
+ swap_chain_desc.SampleDesc.Quality = 0;
+ swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swap_chain_desc.BufferCount = 2; // use double buffering to enable flip
+ swap_chain_desc.Scaling = DXGI_SCALING_NONE;
+ swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all apps must use this SwapEffect
+ swap_chain_desc.Flags = 0;
+
+
+
+ // Get the final swap chain for this window from the DXGI factory.
+ ThrowIfFailed(
+ dxgi_factory->CreateSwapChainForHwnd(
+ d3d11_device.Get(),
+ hwnd,
+ &swap_chain_desc,
+ nullptr,
+ nullptr,
+ &dxgi_swap_chain_
+ )
+ );
- CreateTargetBitmap();
- }
+ CreateTargetBitmap();
+ }
- WindowRenderTarget::~WindowRenderTarget()
- {
+ WindowRenderTarget::~WindowRenderTarget()
+ {
- }
+ }
- void WindowRenderTarget::ResizeBuffer(const int width, const int height)
- {
- const auto graph_manager = graph_manager_;
- const auto d2d1_device_context = graph_manager->GetD2D1DeviceContext();
+ void WindowRenderTarget::ResizeBuffer(const int width, const int height)
+ {
+ const auto graph_manager = graph_manager_;
+ const auto d2d1_device_context = graph_manager->GetD2D1DeviceContext();
- ComPtr<ID2D1Image> old_target;
- d2d1_device_context->GetTarget(&old_target);
- const auto target_this = old_target == this->target_bitmap_;
- if (target_this)
- d2d1_device_context->SetTarget(nullptr);
+ ComPtr<ID2D1Image> old_target;
+ d2d1_device_context->GetTarget(&old_target);
+ const auto target_this = old_target == this->target_bitmap_;
+ if (target_this)
+ d2d1_device_context->SetTarget(nullptr);
- old_target = nullptr;
- target_bitmap_ = nullptr;
+ old_target = nullptr;
+ target_bitmap_ = nullptr;
- ThrowIfFailed(
- dxgi_swap_chain_->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0)
- );
+ ThrowIfFailed(
+ dxgi_swap_chain_->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0)
+ );
- CreateTargetBitmap();
+ CreateTargetBitmap();
- if (target_this)
- d2d1_device_context->SetTarget(target_bitmap_.Get());
- }
+ if (target_this)
+ d2d1_device_context->SetTarget(target_bitmap_.Get());
+ }
- void WindowRenderTarget::SetAsTarget()
- {
- GetD2DDeviceContext()->SetTarget(target_bitmap_.Get());
- }
+ void WindowRenderTarget::SetAsTarget()
+ {
+ GetD2DDeviceContext()->SetTarget(target_bitmap_.Get());
+ }
- void WindowRenderTarget::Present()
- {
- ThrowIfFailed(
- dxgi_swap_chain_->Present(1, 0)
- );
- }
+ void WindowRenderTarget::Present()
+ {
+ ThrowIfFailed(
+ dxgi_swap_chain_->Present(1, 0)
+ );
+ }
- void WindowRenderTarget::CreateTargetBitmap()
- {
- // Direct2D needs the dxgi version of the backbuffer surface pointer.
- ComPtr<IDXGISurface> dxgiBackBuffer;
- ThrowIfFailed(
- dxgi_swap_chain_->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
+ void WindowRenderTarget::CreateTargetBitmap()
+ {
+ // Direct2D needs the dxgi version of the backbuffer surface pointer.
+ ComPtr<IDXGISurface> dxgiBackBuffer;
+ ThrowIfFailed(
+ dxgi_swap_chain_->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
+ );
+
+ const auto dpi = graph_manager_->GetDpi();
+
+ auto bitmap_properties =
+ D2D1::BitmapProperties1(
+ D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
+ D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
+ dpi.x,
+ dpi.y
);
- const auto dpi = graph_manager_->GetDpi();
-
- auto bitmap_properties =
- D2D1::BitmapProperties1(
- D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
- D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
- dpi.x,
- dpi.y
- );
-
- // Get a D2D surface from the DXGI back buffer to use as the D2D render target.
- ThrowIfFailed(
- graph_manager_->GetD2D1DeviceContext()->CreateBitmapFromDxgiSurface(
- dxgiBackBuffer.Get(),
- &bitmap_properties,
- &target_bitmap_
- )
- );
- }
+ // Get a D2D surface from the DXGI back buffer to use as the D2D render target.
+ ThrowIfFailed(
+ graph_manager_->GetD2D1DeviceContext()->CreateBitmapFromDxgiSurface(
+ dxgiBackBuffer.Get(),
+ &bitmap_properties,
+ &target_bitmap_
+ )
+ );
+ }
- GraphManager* GraphManager::GetInstance()
- {
- return Application::GetInstance()->GetGraphManager();
- }
+ GraphManager* GraphManager::GetInstance()
+ {
+ return Application::GetInstance()->GetGraphManager();
+ }
- GraphManager::GraphManager()
- {
- UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
+ GraphManager::GraphManager()
+ {
+ UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
-#ifdef _DEBUG
+#ifdef CRU_DEBUG
creation_flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
- const D3D_FEATURE_LEVEL feature_levels[] =
- {
- D3D_FEATURE_LEVEL_11_1,
- D3D_FEATURE_LEVEL_11_0,
- D3D_FEATURE_LEVEL_10_1,
- D3D_FEATURE_LEVEL_10_0,
- D3D_FEATURE_LEVEL_9_3,
- D3D_FEATURE_LEVEL_9_2,
- D3D_FEATURE_LEVEL_9_1
- };
-
-
- ThrowIfFailed(D3D11CreateDevice(
- nullptr,
- D3D_DRIVER_TYPE_HARDWARE,
- nullptr,
- creation_flags,
- feature_levels,
- ARRAYSIZE(feature_levels),
- D3D11_SDK_VERSION,
- &d3d11_device_,
- nullptr,
- &d3d11_device_context_
- ));
-
- Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
-
- ThrowIfFailed(d3d11_device_.As(&dxgi_device));
-
- ThrowIfFailed(D2D1CreateFactory(
- D2D1_FACTORY_TYPE_SINGLE_THREADED,
- __uuidof(ID2D1Factory1),
- &d2d1_factory_
- ));
-
- ThrowIfFailed(d2d1_factory_->CreateDevice(dxgi_device.Get(), &d2d1_device_));
-
- ThrowIfFailed(d2d1_device_->CreateDeviceContext(
- D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
- &d2d1_device_context_
- ));
-
- // Identify the physical adapter (GPU or card) this device is runs on.
- ComPtr<IDXGIAdapter> dxgi_adapter;
- ThrowIfFailed(
- dxgi_device->GetAdapter(&dxgi_adapter)
- );
-
- // Get the factory object that created the DXGI device.
- ThrowIfFailed(
- dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory_))
- );
+ const D3D_FEATURE_LEVEL feature_levels[] =
+ {
+ D3D_FEATURE_LEVEL_11_1,
+ D3D_FEATURE_LEVEL_11_0,
+ D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0,
+ D3D_FEATURE_LEVEL_9_3,
+ D3D_FEATURE_LEVEL_9_2,
+ D3D_FEATURE_LEVEL_9_1
+ };
+
+
+ ThrowIfFailed(D3D11CreateDevice(
+ nullptr,
+ D3D_DRIVER_TYPE_HARDWARE,
+ nullptr,
+ creation_flags,
+ feature_levels,
+ ARRAYSIZE(feature_levels),
+ D3D11_SDK_VERSION,
+ &d3d11_device_,
+ nullptr,
+ &d3d11_device_context_
+ ));
+
+ Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
+
+ ThrowIfFailed(d3d11_device_.As(&dxgi_device));
+
+ ThrowIfFailed(D2D1CreateFactory(
+ D2D1_FACTORY_TYPE_SINGLE_THREADED,
+ __uuidof(ID2D1Factory1),
+ &d2d1_factory_
+ ));
+
+ ThrowIfFailed(d2d1_factory_->CreateDevice(dxgi_device.Get(), &d2d1_device_));
+
+ ThrowIfFailed(d2d1_device_->CreateDeviceContext(
+ D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
+ &d2d1_device_context_
+ ));
+
+ // Identify the physical adapter (GPU or card) this device is runs on.
+ ComPtr<IDXGIAdapter> dxgi_adapter;
+ ThrowIfFailed(
+ dxgi_device->GetAdapter(&dxgi_adapter)
+ );
+
+ // Get the factory object that created the DXGI device.
+ ThrowIfFailed(
+ dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory_))
+ );
+
+
+ ThrowIfFailed(DWriteCreateFactory(
+ DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown**>(dwrite_factory_.GetAddressOf())
+ ));
+
+ dwrite_factory_->GetSystemFontCollection(&dwrite_system_font_collection_);
+ }
+ GraphManager::~GraphManager()
+ {
- ThrowIfFailed(DWriteCreateFactory(
- DWRITE_FACTORY_TYPE_SHARED,
- __uuidof(IDWriteFactory),
- reinterpret_cast<IUnknown**>(dwrite_factory_.GetAddressOf())
- ));
+ }
- dwrite_factory_->GetSystemFontCollection(&dwrite_system_font_collection_);
- }
+ std::shared_ptr<WindowRenderTarget> GraphManager::CreateWindowRenderTarget(HWND hwnd)
+ {
+ return std::make_shared<WindowRenderTarget>(this, hwnd);
+ }
- GraphManager::~GraphManager()
- {
+ Dpi GraphManager::GetDpi() const
+ {
+ Dpi dpi;
+ d2d1_factory_->GetDesktopDpi(&dpi.x, &dpi.y);
+ return dpi;
+ }
- }
+ void GraphManager::ReloadSystemMetrics()
+ {
+ ThrowIfFailed(
+ d2d1_factory_->ReloadSystemMetrics()
+ );
+ }
- std::shared_ptr<WindowRenderTarget> GraphManager::CreateWindowRenderTarget(HWND hwnd)
- {
- return std::make_shared<WindowRenderTarget>(this, hwnd);
- }
+ ComPtr<ID2D1SolidColorBrush> CreateSolidBrush(const D2D1_COLOR_F& color)
+ {
+ const auto device_context = GraphManager::GetInstance()->GetD2D1DeviceContext();
+ ComPtr<ID2D1SolidColorBrush> solid_color_brush;
+ device_context->CreateSolidColorBrush(color, &solid_color_brush);
+ return solid_color_brush;
+ }
- Dpi GraphManager::GetDpi() const
- {
- Dpi dpi;
- d2d1_factory_->GetDesktopDpi(&dpi.x, &dpi.y);
- return dpi;
- }
+ ComPtr<IDWriteTextFormat> CreateDefaultTextFormat()
+ {
+ const auto dwrite_factory = GraphManager::GetInstance()->GetDWriteFactory();
- void GraphManager::ReloadSystemMetrics()
- {
- ThrowIfFailed(
- d2d1_factory_->ReloadSystemMetrics()
- );
- }
+ ComPtr<IDWriteTextFormat> text_format;
- ComPtr<ID2D1SolidColorBrush> CreateSolidBrush(const D2D1_COLOR_F& color)
- {
- const auto device_context = GraphManager::GetInstance()->GetD2D1DeviceContext();
- ComPtr<ID2D1SolidColorBrush> solid_color_brush;
- device_context->CreateSolidColorBrush(color, &solid_color_brush);
- return solid_color_brush;
- }
+ ThrowIfFailed(dwrite_factory->CreateTextFormat(
+ L"等线", nullptr,
+ DWRITE_FONT_WEIGHT_NORMAL,
+ DWRITE_FONT_STYLE_NORMAL,
+ DWRITE_FONT_STRETCH_NORMAL,
+ 24.0, L"zh-cn",
+ &text_format
+ ));
- ComPtr<IDWriteTextFormat> CreateDefaultTextFormat()
- {
- const auto dwrite_factory = GraphManager::GetInstance()->GetDWriteFactory();
-
- ComPtr<IDWriteTextFormat> text_format;
-
- ThrowIfFailed(dwrite_factory->CreateTextFormat(
- L"等线", nullptr,
- DWRITE_FONT_WEIGHT_NORMAL,
- DWRITE_FONT_STYLE_NORMAL,
- DWRITE_FONT_STRETCH_NORMAL,
- 24.0, L"zh-cn",
- &text_format
- ));
-
- ThrowIfFailed(text_format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
- ThrowIfFailed(text_format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
- return text_format;
- }
+ ThrowIfFailed(text_format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
+ ThrowIfFailed(text_format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));
+ return text_format;
}
}
+
diff --git a/src/graph/graph.h b/src/graph/graph.h
index 19f060e2..ff8b88b8 100644
--- a/src/graph/graph.h
+++ b/src/graph/graph.h
@@ -7,174 +7,171 @@
#include "application.h"
-namespace cru
+namespace cru::graph
{
- namespace graph
- {
- class GraphManager;
-
- //Represents a window render target.
- class WindowRenderTarget : public Object
- {
- public:
- WindowRenderTarget(GraphManager* graph_manager, HWND hwnd);
- WindowRenderTarget(const WindowRenderTarget& other) = delete;
- WindowRenderTarget(WindowRenderTarget&& other) = delete;
- WindowRenderTarget& operator=(const WindowRenderTarget& other) = delete;
- WindowRenderTarget& operator=(WindowRenderTarget&& other) = delete;
- ~WindowRenderTarget() override;
-
- public:
- //Get the graph manager that created the render target.
- GraphManager* GetGraphManager() const
- {
- return graph_manager_;
- }
-
- //Get the d2d device context.
- inline Microsoft::WRL::ComPtr<ID2D1DeviceContext> GetD2DDeviceContext() const;
-
- //Get the target bitmap which can be set as the ID2D1DeviceContext's target.
- Microsoft::WRL::ComPtr<ID2D1Bitmap1> GetTargetBitmap() const
- {
- return target_bitmap_;
- }
-
- //Resize the underlying buffer.
- void ResizeBuffer(int width, int height);
-
- //Set this render target as the d2d device context's target.
- void SetAsTarget();
-
- //Present the data of the underlying buffer to the window.
- void Present();
-
- private:
- void CreateTargetBitmap();
-
- private:
- GraphManager* graph_manager_;
- Microsoft::WRL::ComPtr<IDXGISwapChain1> dxgi_swap_chain_;
- Microsoft::WRL::ComPtr<ID2D1Bitmap1> target_bitmap_;
- };
-
- struct Dpi
- {
- float x;
- float y;
- };
+ class GraphManager;
- class GraphManager : public Object
- {
- public:
- static GraphManager* GetInstance();
-
- public:
- GraphManager();
- GraphManager(const GraphManager& other) = delete;
- GraphManager(GraphManager&& other) = delete;
- GraphManager& operator=(const GraphManager& other) = delete;
- GraphManager& operator=(GraphManager&& other) = delete;
- ~GraphManager() override;
-
- public:
- Microsoft::WRL::ComPtr<ID2D1Factory1> GetD2D1Factory() const
- {
- return d2d1_factory_;
- }
-
- Microsoft::WRL::ComPtr<ID2D1DeviceContext> GetD2D1DeviceContext() const
- {
- return d2d1_device_context_;
- }
-
- Microsoft::WRL::ComPtr<ID3D11Device> GetD3D11Device() const
- {
- return d3d11_device_;
- }
-
- Microsoft::WRL::ComPtr<IDXGIFactory2> GetDxgiFactory() const
- {
- return dxgi_factory_;
- }
-
- Microsoft::WRL::ComPtr<IDWriteFactory> GetDWriteFactory() const
- {
- return dwrite_factory_;
- }
-
-
- //Create a window render target with the HWND.
- std::shared_ptr<WindowRenderTarget> CreateWindowRenderTarget(HWND hwnd);
-
- //Get the desktop dpi.
- Dpi GetDpi() const;
-
- //Reload system metrics including desktop dpi.
- void ReloadSystemMetrics();
-
- Microsoft::WRL::ComPtr<IDWriteFontCollection> GetSystemFontCollection() const
- {
- return dwrite_system_font_collection_.Get();
- }
-
- private:
- Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
- Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_device_context_;
- Microsoft::WRL::ComPtr<ID2D1Factory1> d2d1_factory_;
- Microsoft::WRL::ComPtr<ID2D1Device> d2d1_device_;
- Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2d1_device_context_;
- Microsoft::WRL::ComPtr<IDXGIFactory2> dxgi_factory_;
-
- Microsoft::WRL::ComPtr<IDWriteFactory> dwrite_factory_;
- Microsoft::WRL::ComPtr<IDWriteFontCollection> dwrite_system_font_collection_;
- };
-
- inline int DipToPixelInternal(const float dip, const float dpi)
+ //Represents a window render target.
+ class WindowRenderTarget : public Object
+ {
+ public:
+ WindowRenderTarget(GraphManager* graph_manager, HWND hwnd);
+ WindowRenderTarget(const WindowRenderTarget& other) = delete;
+ WindowRenderTarget(WindowRenderTarget&& other) = delete;
+ WindowRenderTarget& operator=(const WindowRenderTarget& other) = delete;
+ WindowRenderTarget& operator=(WindowRenderTarget&& other) = delete;
+ ~WindowRenderTarget() override;
+
+ public:
+ //Get the graph manager that created the render target.
+ GraphManager* GetGraphManager() const
{
- return static_cast<int>(dip * dpi / 96.0f);
+ return graph_manager_;
}
- inline int DipToPixelX(const float dip_x)
+ //Get the d2d device context.
+ inline Microsoft::WRL::ComPtr<ID2D1DeviceContext> GetD2DDeviceContext() const;
+
+ //Get the target bitmap which can be set as the ID2D1DeviceContext's target.
+ Microsoft::WRL::ComPtr<ID2D1Bitmap1> GetTargetBitmap() const
{
- return DipToPixelInternal(dip_x, Application::GetInstance()->GetGraphManager()->GetDpi().x);
+ return target_bitmap_;
}
- inline int DipToPixelY(const float dip_y)
+ //Resize the underlying buffer.
+ void ResizeBuffer(int width, int height);
+
+ //Set this render target as the d2d device context's target.
+ void SetAsTarget();
+
+ //Present the data of the underlying buffer to the window.
+ void Present();
+
+ private:
+ void CreateTargetBitmap();
+
+ private:
+ GraphManager* graph_manager_;
+ Microsoft::WRL::ComPtr<IDXGISwapChain1> dxgi_swap_chain_;
+ Microsoft::WRL::ComPtr<ID2D1Bitmap1> target_bitmap_;
+ };
+
+ struct Dpi
+ {
+ float x;
+ float y;
+ };
+
+ class GraphManager : public Object
+ {
+ public:
+ static GraphManager* GetInstance();
+
+ public:
+ GraphManager();
+ GraphManager(const GraphManager& other) = delete;
+ GraphManager(GraphManager&& other) = delete;
+ GraphManager& operator=(const GraphManager& other) = delete;
+ GraphManager& operator=(GraphManager&& other) = delete;
+ ~GraphManager() override;
+
+ public:
+ Microsoft::WRL::ComPtr<ID2D1Factory1> GetD2D1Factory() const
{
- return DipToPixelInternal(dip_y, Application::GetInstance()->GetGraphManager()->GetDpi().y);
+ return d2d1_factory_;
}
- inline float DipToPixelInternal(const int pixel, const float dpi)
+ Microsoft::WRL::ComPtr<ID2D1DeviceContext> GetD2D1DeviceContext() const
{
- return static_cast<float>(pixel) * 96.0f / dpi;
+ return d2d1_device_context_;
}
- inline float PixelToDipX(const int pixel_x)
+ Microsoft::WRL::ComPtr<ID3D11Device> GetD3D11Device() const
{
- return DipToPixelInternal(pixel_x, Application::GetInstance()->GetGraphManager()->GetDpi().x);
+ return d3d11_device_;
}
- inline float PixelToDipY(const int pixel_y)
+ Microsoft::WRL::ComPtr<IDXGIFactory2> GetDxgiFactory() const
{
- return DipToPixelInternal(pixel_y, Application::GetInstance()->GetGraphManager()->GetDpi().y);
+ return dxgi_factory_;
}
- Microsoft::WRL::ComPtr<ID2D1DeviceContext> WindowRenderTarget::GetD2DDeviceContext() const
+ Microsoft::WRL::ComPtr<IDWriteFactory> GetDWriteFactory() const
{
- return graph_manager_->GetD2D1DeviceContext();
+ return dwrite_factory_;
}
- Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> CreateSolidBrush(const D2D1_COLOR_F& color);
- Microsoft::WRL::ComPtr<IDWriteTextFormat> CreateDefaultTextFormat();
- inline void WithTransform(ID2D1DeviceContext* device_context, const D2D1_MATRIX_3X2_F matrix, const std::function<void(ID2D1DeviceContext*)>& action)
+ //Create a window render target with the HWND.
+ std::shared_ptr<WindowRenderTarget> CreateWindowRenderTarget(HWND hwnd);
+
+ //Get the desktop dpi.
+ Dpi GetDpi() const;
+
+ //Reload system metrics including desktop dpi.
+ void ReloadSystemMetrics();
+
+ Microsoft::WRL::ComPtr<IDWriteFontCollection> GetSystemFontCollection() const
{
- D2D1_MATRIX_3X2_F old_transform;
- device_context->GetTransform(&old_transform);
- device_context->SetTransform(old_transform * matrix);
- action(device_context);
- device_context->SetTransform(old_transform);
+ return dwrite_system_font_collection_.Get();
}
+
+ private:
+ Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
+ Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_device_context_;
+ Microsoft::WRL::ComPtr<ID2D1Factory1> d2d1_factory_;
+ Microsoft::WRL::ComPtr<ID2D1Device> d2d1_device_;
+ Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2d1_device_context_;
+ Microsoft::WRL::ComPtr<IDXGIFactory2> dxgi_factory_;
+
+ Microsoft::WRL::ComPtr<IDWriteFactory> dwrite_factory_;
+ Microsoft::WRL::ComPtr<IDWriteFontCollection> dwrite_system_font_collection_;
+ };
+
+ inline int DipToPixelInternal(const float dip, const float dpi)
+ {
+ return static_cast<int>(dip * dpi / 96.0f);
+ }
+
+ inline int DipToPixelX(const float dip_x)
+ {
+ return DipToPixelInternal(dip_x, Application::GetInstance()->GetGraphManager()->GetDpi().x);
+ }
+
+ inline int DipToPixelY(const float dip_y)
+ {
+ return DipToPixelInternal(dip_y, Application::GetInstance()->GetGraphManager()->GetDpi().y);
+ }
+
+ inline float DipToPixelInternal(const int pixel, const float dpi)
+ {
+ return static_cast<float>(pixel) * 96.0f / dpi;
+ }
+
+ inline float PixelToDipX(const int pixel_x)
+ {
+ return DipToPixelInternal(pixel_x, Application::GetInstance()->GetGraphManager()->GetDpi().x);
+ }
+
+ inline float PixelToDipY(const int pixel_y)
+ {
+ return DipToPixelInternal(pixel_y, Application::GetInstance()->GetGraphManager()->GetDpi().y);
+ }
+
+ Microsoft::WRL::ComPtr<ID2D1DeviceContext> WindowRenderTarget::GetD2DDeviceContext() const
+ {
+ return graph_manager_->GetD2D1DeviceContext();
+ }
+
+ Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> CreateSolidBrush(const D2D1_COLOR_F& color);
+ Microsoft::WRL::ComPtr<IDWriteTextFormat> CreateDefaultTextFormat();
+
+ inline void WithTransform(ID2D1DeviceContext* device_context, const D2D1_MATRIX_3X2_F matrix, const std::function<void(ID2D1DeviceContext*)>& action)
+ {
+ D2D1_MATRIX_3X2_F old_transform;
+ device_context->GetTransform(&old_transform);
+ device_context->SetTransform(old_transform * matrix);
+ action(device_context);
+ device_context->SetTransform(old_transform);
}
}
diff --git a/src/ui/control.cpp b/src/ui/control.cpp
index 9416d48a..ec8420c1 100644
--- a/src/ui/control.cpp
+++ b/src/ui/control.cpp
@@ -7,880 +7,879 @@
#include "exception.h"
#include "cru_debug.h"
-namespace cru {
- namespace ui {
- using namespace events;
+namespace cru::ui
+{
+ using namespace events;
- Control::Control(const bool container) :
- is_container_(container)
- {
-
- }
-
- Control::Control(WindowConstructorTag, Window* window) : Control(true)
- {
- window_ = window;
- }
-
- Control::~Control()
- {
- for (auto control: GetChildren())
- {
- delete control;
- }
- }
-
- 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.");
- }
-
- const std::vector<Control*>& Control::GetChildren() const
- {
- return children_;
- }
-
- 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, const std::function<void(Control*)>& predicate)
- {
- predicate(control);
- if (control->IsContainer())
- for (auto c: control->GetChildren())
- {
- TraverseDescendantsInternal(c, predicate);
- }
- }
-
- void Control::TraverseDescendants(const std::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::ControlToWindow(const Point& point) const
- {
- return Point(point.x + position_cache_.lefttop_position_absolute.x,
- point.y + position_cache_.lefttop_position_absolute.y);
- }
-
- Point Control::WindowToControl(const Point & point) const
- {
- return Point(point.x - position_cache_.lefttop_position_absolute.x,
- point.y - position_cache_.lefttop_position_absolute.y);
- }
+ Control::Control(const bool container) :
+ is_container_(container)
+ {
- 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);
-
- const auto rect = GetRect(RectRange::Content);
- graph::WithTransform(device_context, D2D1::Matrix3x2F::Translation(rect.left, rect.top),
- [this](ID2D1DeviceContext* device_context)
- {
- OnDrawContent(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();
- }
+ Control::Control(WindowConstructorTag, Window* window) : Control(true)
+ {
+ window_ = window;
+ }
- bool Control::RequestFocus()
+ Control::~Control()
+ {
+ for (auto control: GetChildren())
{
- auto window = GetWindow();
- if (window == nullptr)
- return false;
-
- return window->RequestFocusFor(this);
+ delete control;
}
+ }
- bool Control::HasFocus()
- {
- auto window = GetWindow();
- if (window == nullptr)
- return false;
-
- return window->GetFocusControl() == this;
- }
+ void AddChildCheck(Control* control)
+ {
+ if (control->GetParent() != nullptr)
+ throw std::invalid_argument("The control already has a parent.");
- void Control::InvalidateLayout()
- {
- if (const auto window = GetWindow())
- LayoutManager::GetInstance()->InvalidateWindowLayout(window);
- }
+ if (dynamic_cast<Window*>(control))
+ throw std::invalid_argument("Can't add a window as child.");
+ }
- void Control::Measure(const Size& available_size)
- {
- SetDesiredSize(OnMeasureCore(available_size));
- }
+ const std::vector<Control*>& Control::GetChildren() const
+ {
+ return children_;
+ }
- void Control::Layout(const Rect& rect)
- {
- SetPositionRelative(rect.GetLeftTop());
- SetSize(rect.GetSize());
- OnLayoutCore(Rect(Point::Zero(), rect.GetSize()));
- }
+ void Control::AddChild(Control* control)
+ {
+ ThrowIfNotContainer();
+ AddChildCheck(control);
- Size Control::GetDesiredSize() const
- {
- return desired_size_;
- }
+ this->children_.push_back(control);
- void Control::SetDesiredSize(const Size& desired_size)
- {
- desired_size_ = desired_size;
- }
+ control->parent_ = this;
- inline void Shrink(Rect& rect, const Thickness& thickness)
- {
- rect.left += thickness.left;
- rect.top += thickness.top;
- rect.width -= thickness.GetHorizontalTotal();
- rect.height -= thickness.GetVerticalTotal();
- }
+ this->OnAddChild(control);
+ }
- Rect Control::GetRect(const RectRange range)
- {
- if (GetSize() == Size::Zero())
- return Rect();
+ void Control::AddChild(Control* control, int position)
+ {
+ ThrowIfNotContainer();
+ AddChildCheck(control);
- const auto layout_params = GetLayoutParams();
+ if (position < 0 || static_cast<decltype(this->children_.size())>(position) > this->children_.size())
+ throw std::invalid_argument("The position is out of range.");
- auto result = Rect(Point::Zero(), GetSize());
+ this->children_.insert(this->children_.cbegin() + position, control);
- if (range == RectRange::Margin)
- return result;
+ control->parent_ = this;
- Shrink(result, layout_params->margin);
+ this->OnAddChild(this);
+ }
- if (range == RectRange::FullBorder)
- return result;
+ 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.");
- if (is_bordered_)
- Shrink(result, Thickness(GetBorderProperty().GetStrokeWidth() / 2.0f));
+ this->children_.erase(i);
- if (range == RectRange::HalfBorder)
- return result;
+ child->parent_ = nullptr;
- if (is_bordered_)
- Shrink(result, Thickness(GetBorderProperty().GetStrokeWidth() / 2.0f));
+ this->OnRemoveChild(this);
+ }
- if (range == RectRange::Padding)
- return result;
+ 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.");
- Shrink(result, layout_params->padding);
+ const auto p = children_.cbegin() + position;
+ const auto child = *p;
+ children_.erase(p);
- return result;
- }
+ child->parent_ = nullptr;
- Point Control::TransformPoint(const Point& point, const RectRange from, const RectRange to)
- {
- const auto rect_from = GetRect(from);
- const auto rect_to = GetRect(to);
- auto p = point;
- p.x += rect_from.left;
- p.y += rect_from.top;
- p.x -= rect_to.left;
- p.y -= rect_to.top;
- return p;
- }
+ this->OnRemoveChild(child);
+ }
- void Control::InvalidateBorder()
- {
- InvalidateLayout();
- Repaint();
- }
+ 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 Control::SetBordered(const bool bordered)
- {
- if (bordered != is_bordered_)
+ void TraverseDescendantsInternal(Control* control, const std::function<void(Control*)>& predicate)
+ {
+ predicate(control);
+ if (control->IsContainer())
+ for (auto c: control->GetChildren())
{
- is_bordered_ = bordered;
- InvalidateBorder();
+ TraverseDescendantsInternal(c, predicate);
}
- }
+ }
- void Control::SetCursor(const Cursor::Ptr& cursor)
- {
- if (cursor != cursor_)
- {
- cursor_ = cursor;
- const auto window = GetWindow();
- if (window && window->GetMouseHoverControl() == this)
- window->UpdateCursor();
- }
- }
+ void Control::TraverseDescendants(const std::function<void(Control*)>& predicate)
+ {
+ if (is_container_)
+ TraverseDescendantsInternal(this, predicate);
+ else
+ predicate(this);
+ }
- void Control::OnAddChild(Control* child)
- {
- if (auto window = GetWindow())
- {
- child->TraverseDescendants([window](Control* control) {
- control->OnAttachToWindow(window);
- });
- window->RefreshControlList();
- InvalidateLayout();
- }
- }
+ Point Control::GetPositionRelative()
+ {
+ return position_;
+ }
- void Control::OnRemoveChild(Control* child)
+ 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())
{
- child->TraverseDescendants([window](Control* control) {
- control->OnDetachToWindow(window);
- });
- window->RefreshControlList();
- InvalidateLayout();
- }
- }
-
- void Control::OnAttachToWindow(Window* window)
- {
- window_ = window;
- }
-
- void Control::OnDetachToWindow(Window * window)
- {
- window_ = nullptr;
- }
-
- inline D2D1_RECT_F Convert(const Rect& rect)
- {
- return D2D1::RectF(rect.left, rect.top, rect.left + rect.width, rect.top + rect.height);
- }
-
- void Control::OnDraw(ID2D1DeviceContext* device_context)
- {
-#ifdef CRU_DEBUG_LAYOUT
- if (GetWindow()->IsDebugLayout())
- {
- const auto resource = Application::GetInstance()->GetDebugLayoutResource();
- if (padding_geometry_ != nullptr)
- device_context->FillGeometry(padding_geometry_.Get(), resource->padding_brush.Get());
- if (margin_geometry_ != nullptr)
- device_context->FillGeometry(margin_geometry_.Get(), resource->margin_brush.Get());
- device_context->DrawRectangle(Convert(GetRect(RectRange::Margin)), resource->out_border_brush.Get());
- }
-#endif
-
- if (is_bordered_)
- {
- const auto border_rect = GetRect(RectRange::HalfBorder);
- device_context->DrawRoundedRectangle(
- D2D1::RoundedRect(
- Convert(border_rect),
- GetBorderProperty().GetRadiusX(),
- GetBorderProperty().GetRadiusY()
- ),
- GetBorderProperty().GetBrush().Get(),
- GetBorderProperty().GetStrokeWidth(),
- GetBorderProperty().GetStrokeStyle().Get()
- );
- }
- }
-
- void Control::OnDrawContent(ID2D1DeviceContext * device_context)
- {
-
- }
-
- void Control::OnPositionChanged(PositionChangedEventArgs & args)
- {
-
- }
-
- void Control::OnSizeChanged(SizeChangedEventArgs & args)
- {
- }
-
- void Control::OnPositionChangedCore(PositionChangedEventArgs & args)
- {
-
- }
-
- namespace
- {
-#ifdef CRU_DEBUG_LAYOUT
- Microsoft::WRL::ComPtr<ID2D1Geometry> CalculateSquareRingGeometry(const Rect& out, const Rect& in)
- {
- const auto d2d1_factory = graph::GraphManager::GetInstance()->GetD2D1Factory();
- Microsoft::WRL::ComPtr<ID2D1RectangleGeometry> out_geometry;
- ThrowIfFailed(d2d1_factory->CreateRectangleGeometry(Convert(out), &out_geometry));
- Microsoft::WRL::ComPtr<ID2D1RectangleGeometry> in_geometry;
- ThrowIfFailed(d2d1_factory->CreateRectangleGeometry(Convert(in), &in_geometry));
- Microsoft::WRL::ComPtr<ID2D1PathGeometry> result_geometry;
- ThrowIfFailed(d2d1_factory->CreatePathGeometry(&result_geometry));
- Microsoft::WRL::ComPtr<ID2D1GeometrySink> sink;
- ThrowIfFailed(result_geometry->Open(&sink));
- ThrowIfFailed(out_geometry->CombineWithGeometry(in_geometry.Get(), D2D1_COMBINE_MODE_EXCLUDE, D2D1::Matrix3x2F::Identity(), sink.Get()));
- ThrowIfFailed(sink->Close());
- return result_geometry;
+ window->Repaint();
}
-#endif
- }
-
- void Control::OnSizeChangedCore(SizeChangedEventArgs & args)
- {
-#ifdef CRU_DEBUG_LAYOUT
- margin_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Margin), GetRect(RectRange::FullBorder));
- padding_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Padding), GetRect(RectRange::Content));
-#endif
- }
-
- 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);
- }
+ Size Control::GetSize()
+ {
+ return size_;
+ }
- void Control::OnMouseEnter(MouseEventArgs & args)
- {
- }
+ 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();
+ }
- void Control::OnMouseLeave(MouseEventArgs & args)
- {
- }
+ Point Control::GetPositionAbsolute() const
+ {
+ return position_cache_.lefttop_position_absolute;
+ }
- void Control::OnMouseMove(MouseEventArgs & args)
- {
- }
+ Point Control::ControlToWindow(const Point& point) const
+ {
+ return Point(point.x + position_cache_.lefttop_position_absolute.x,
+ point.y + position_cache_.lefttop_position_absolute.y);
+ }
- void Control::OnMouseDown(MouseButtonEventArgs & args)
- {
- }
+ Point Control::WindowToControl(const Point & point) const
+ {
+ return Point(point.x - position_cache_.lefttop_position_absolute.x,
+ point.y - position_cache_.lefttop_position_absolute.y);
+ }
- void Control::OnMouseUp(MouseButtonEventArgs & args)
- {
- }
+ 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::OnMouseClick(MouseButtonEventArgs& args)
- {
+ 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));
- void Control::OnMouseEnterCore(MouseEventArgs & args)
- {
- is_mouse_inside_ = true;
- }
+ OnDraw(device_context);
- void Control::OnMouseLeaveCore(MouseEventArgs & args)
- {
- is_mouse_inside_ = false;
- for (auto& is_mouse_click_valid : is_mouse_click_valid_map_)
+ const auto rect = GetRect(RectRange::Content);
+ graph::WithTransform(device_context, D2D1::Matrix3x2F::Translation(rect.left, rect.top),
+ [this](ID2D1DeviceContext* device_context)
{
- if (is_mouse_click_valid.second)
- {
- is_mouse_click_valid.second = false;
- OnMouseClickEnd(is_mouse_click_valid.first);
- }
- }
- }
+ OnDrawContent(device_context);
+ DrawEventArgs args(this, this, device_context);
+ draw_event.Raise(args);
+ });
- void Control::OnMouseMoveCore(MouseEventArgs & args)
- {
+ for (auto child : GetChildren())
+ child->Draw(device_context);
- }
+ device_context->SetTransform(old_transform);
+ }
- 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::Repaint()
+ {
+ if (window_ != nullptr)
+ window_->Repaint();
+ }
- 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());
- }
- }
+ bool Control::RequestFocus()
+ {
+ auto window = GetWindow();
+ if (window == nullptr)
+ return false;
- void Control::OnMouseClickCore(MouseButtonEventArgs& args)
- {
+ return window->RequestFocusFor(this);
+ }
- }
+ bool Control::HasFocus()
+ {
+ auto window = GetWindow();
+ if (window == nullptr)
+ return false;
- void Control::RaiseMouseEnterEvent(MouseEventArgs& args)
- {
- OnMouseEnterCore(args);
- OnMouseEnter(args);
- mouse_enter_event.Raise(args);
- }
+ return window->GetFocusControl() == this;
+ }
- void Control::RaiseMouseLeaveEvent(MouseEventArgs& args)
- {
- OnMouseLeaveCore(args);
- OnMouseLeave(args);
- mouse_leave_event.Raise(args);
- }
+ void Control::InvalidateLayout()
+ {
+ if (const auto window = GetWindow())
+ LayoutManager::GetInstance()->InvalidateWindowLayout(window);
+ }
- void Control::RaiseMouseMoveEvent(MouseEventArgs& args)
- {
- OnMouseMoveCore(args);
- OnMouseMove(args);
- mouse_move_event.Raise(args);
- }
+ void Control::Measure(const Size& available_size)
+ {
+ SetDesiredSize(OnMeasureCore(available_size));
+ }
- void Control::RaiseMouseDownEvent(MouseButtonEventArgs& args)
- {
- OnMouseDownCore(args);
- OnMouseDown(args);
- mouse_down_event.Raise(args);
- }
+ void Control::Layout(const Rect& rect)
+ {
+ SetPositionRelative(rect.GetLeftTop());
+ SetSize(rect.GetSize());
+ OnLayoutCore(Rect(Point::Zero(), rect.GetSize()));
+ }
- void Control::RaiseMouseUpEvent(MouseButtonEventArgs& args)
- {
- OnMouseUpCore(args);
- OnMouseUp(args);
- mouse_up_event.Raise(args);
- }
+ Size Control::GetDesiredSize() const
+ {
+ return desired_size_;
+ }
- void Control::RaiseMouseClickEvent(MouseButtonEventArgs& args)
- {
- OnMouseClickCore(args);
- OnMouseClick(args);
- mouse_click_event.Raise(args);
- }
+ void Control::SetDesiredSize(const Size& desired_size)
+ {
+ desired_size_ = desired_size;
+ }
- void Control::OnMouseClickBegin(MouseButton button)
- {
+ inline void Shrink(Rect& rect, const Thickness& thickness)
+ {
+ rect.left += thickness.left;
+ rect.top += thickness.top;
+ rect.width -= thickness.GetHorizontalTotal();
+ rect.height -= thickness.GetVerticalTotal();
+ }
- }
+ Rect Control::GetRect(const RectRange range)
+ {
+ if (GetSize() == Size::Zero())
+ return Rect();
- void Control::OnMouseClickEnd(MouseButton button)
- {
+ const auto layout_params = GetLayoutParams();
- }
+ auto result = Rect(Point::Zero(), GetSize());
- void Control::OnKeyDown(KeyEventArgs& args)
- {
- }
+ if (range == RectRange::Margin)
+ return result;
- void Control::OnKeyUp(KeyEventArgs& args)
- {
- }
+ Shrink(result, layout_params->margin);
- void Control::OnChar(CharEventArgs& args)
- {
- }
+ if (range == RectRange::FullBorder)
+ return result;
- void Control::OnKeyDownCore(KeyEventArgs& args)
- {
- }
+ if (is_bordered_)
+ Shrink(result, Thickness(GetBorderProperty().GetStrokeWidth() / 2.0f));
- void Control::OnKeyUpCore(KeyEventArgs& args)
- {
- }
+ if (range == RectRange::HalfBorder)
+ return result;
- void Control::OnCharCore(CharEventArgs& args)
- {
- }
+ if (is_bordered_)
+ Shrink(result, Thickness(GetBorderProperty().GetStrokeWidth() / 2.0f));
- void Control::RaiseKeyDownEvent(KeyEventArgs& args)
- {
- OnKeyDownCore(args);
- OnKeyDown(args);
- key_down_event.Raise(args);
- }
+ if (range == RectRange::Padding)
+ return result;
- void Control::RaiseKeyUpEvent(KeyEventArgs& args)
- {
- OnKeyUpCore(args);
- OnKeyUp(args);
- key_up_event.Raise(args);
- }
+ Shrink(result, layout_params->padding);
- void Control::RaiseCharEvent(CharEventArgs& args)
- {
- OnCharCore(args);
- OnChar(args);
- char_event.Raise(args);
- }
+ return result;
+ }
- void Control::OnGetFocus(FocusChangeEventArgs& args)
- {
+ Point Control::TransformPoint(const Point& point, const RectRange from, const RectRange to)
+ {
+ const auto rect_from = GetRect(from);
+ const auto rect_to = GetRect(to);
+ auto p = point;
+ p.x += rect_from.left;
+ p.y += rect_from.top;
+ p.x -= rect_to.left;
+ p.y -= rect_to.top;
+ return p;
+ }
- }
+ void Control::InvalidateBorder()
+ {
+ InvalidateLayout();
+ Repaint();
+ }
- void Control::OnLoseFocus(FocusChangeEventArgs& args)
+ void Control::SetBordered(const bool bordered)
+ {
+ if (bordered != is_bordered_)
{
-
+ is_bordered_ = bordered;
+ InvalidateBorder();
}
+ }
- void Control::OnGetFocusCore(FocusChangeEventArgs& args)
+ void Control::SetCursor(const Cursor::Ptr& cursor)
+ {
+ if (cursor != cursor_)
{
-
+ cursor_ = cursor;
+ const auto window = GetWindow();
+ if (window && window->GetMouseHoverControl() == this)
+ window->UpdateCursor();
}
+ }
- void Control::OnLoseFocusCore(FocusChangeEventArgs& args)
+ void Control::OnAddChild(Control* child)
+ {
+ if (auto window = GetWindow())
{
-
+ child->TraverseDescendants([window](Control* control) {
+ control->OnAttachToWindow(window);
+ });
+ window->RefreshControlList();
+ InvalidateLayout();
}
+ }
- void Control::RaiseGetFocusEvent(FocusChangeEventArgs& args)
+ void Control::OnRemoveChild(Control* child)
+ {
+ if (auto window = GetWindow())
{
- OnGetFocusCore(args);
- OnGetFocus(args);
- get_focus_event.Raise(args);
+ child->TraverseDescendants([window](Control* control) {
+ control->OnDetachToWindow(window);
+ });
+ window->RefreshControlList();
+ InvalidateLayout();
}
+ }
- void Control::RaiseLoseFocusEvent(FocusChangeEventArgs& args)
- {
- OnLoseFocusCore(args);
- OnLoseFocus(args);
- lose_focus_event.Raise(args);
- }
+ void Control::OnAttachToWindow(Window* window)
+ {
+ window_ = window;
+ }
- inline Size ThicknessToSize(const Thickness& thickness)
- {
- return Size(thickness.left + thickness.right, thickness.top + thickness.bottom);
- }
+ void Control::OnDetachToWindow(Window * window)
+ {
+ window_ = nullptr;
+ }
- inline float AtLeast0(const float value)
- {
- return value < 0 ? 0 : value;
- }
+ inline D2D1_RECT_F Convert(const Rect& rect)
+ {
+ return D2D1::RectF(rect.left, rect.top, rect.left + rect.width, rect.top + rect.height);
+ }
- Size Control::OnMeasureCore(const Size& available_size)
+ void Control::OnDraw(ID2D1DeviceContext* device_context)
+ {
+#ifdef CRU_DEBUG_LAYOUT
+ if (GetWindow()->IsDebugLayout())
{
- const auto layout_params = GetLayoutParams();
-
- if (!layout_params->Validate())
- throw std::runtime_error("LayoutParams is not valid. Please check it.");
-
- auto border_size = Size::Zero();
- if (is_bordered_)
- {
- const auto border_width = GetBorderProperty().GetStrokeWidth();
- border_size = Size(border_width * 2.0f, border_width * 2.0f);
- }
-
- // the total size of padding, border and margin
- const auto outer_size = ThicknessToSize(layout_params->padding) +
- ThicknessToSize(layout_params->margin) + border_size;
-
-
- auto&& get_content_measure_length = [](const LayoutSideParams& layout_length, const float available_length, const float outer_length) -> float
- {
- float length;
- if (layout_length.mode == MeasureMode::Exactly)
- length = layout_length.length;
- else if (available_length > outer_length)
- length = available_length - outer_length;
- else
- length = 0;
- return Coerce(length, layout_length.min, layout_length.max);
- };
-
- // if padding, margin and border exceeded, then content size is 0.
- const auto content_measure_size = Size(
- get_content_measure_length(layout_params->width, available_size.width, outer_size.width),
- get_content_measure_length(layout_params->height, available_size.height, outer_size.height)
- );
-
- const auto content_actual_size = OnMeasureContent(content_measure_size);
-
- auto&& calculate_final_length = [](const LayoutSideParams& layout_length, const float measure_length, const float actual_length) -> float
- {
- // only use measure length when stretch and actual length is smaller than measure length, that is "stretch"
- if (layout_length.mode == MeasureMode::Stretch && actual_length < measure_length)
- return measure_length;
- return Coerce(actual_length, layout_length.min, std::nullopt);
- };
-
- const auto final_size = Size(
- calculate_final_length(layout_params->width, content_measure_size.width, content_actual_size.width),
- calculate_final_length(layout_params->height, content_measure_size.height, content_actual_size.height)
- ) + outer_size;
-
- return final_size;
+ const auto resource = Application::GetInstance()->GetDebugLayoutResource();
+ if (padding_geometry_ != nullptr)
+ device_context->FillGeometry(padding_geometry_.Get(), resource->padding_brush.Get());
+ if (margin_geometry_ != nullptr)
+ device_context->FillGeometry(margin_geometry_.Get(), resource->margin_brush.Get());
+ device_context->DrawRectangle(Convert(GetRect(RectRange::Margin)), resource->out_border_brush.Get());
}
+#endif
- void Control::OnLayoutCore(const Rect& rect)
- {
- const auto layout_params = GetLayoutParams();
-
- auto border_width = 0.0f;
- if (is_bordered_)
- {
- border_width = GetBorderProperty().GetStrokeWidth();
- }
-
- const Rect content_rect(
- rect.left + layout_params->padding.left + layout_params->margin.right + border_width,
- rect.top + layout_params->padding.top + layout_params->margin.top + border_width,
- rect.width - layout_params->padding.GetHorizontalTotal() - layout_params->margin.GetHorizontalTotal() - border_width * 2.0f,
- rect.height - layout_params->padding.GetVerticalTotal() - layout_params->margin.GetVerticalTotal() - border_width * 2.0f
+ if (is_bordered_)
+ {
+ const auto border_rect = GetRect(RectRange::HalfBorder);
+ device_context->DrawRoundedRectangle(
+ D2D1::RoundedRect(
+ Convert(border_rect),
+ GetBorderProperty().GetRadiusX(),
+ GetBorderProperty().GetRadiusY()
+ ),
+ GetBorderProperty().GetBrush().Get(),
+ GetBorderProperty().GetStrokeWidth(),
+ GetBorderProperty().GetStrokeStyle().Get()
);
-
- if (content_rect.width < 0.0)
- throw std::runtime_error(Format("Width to layout must sufficient. But in {}, width for content is {}.", ToUtf8String(GetControlType()), content_rect.width));
- if (content_rect.height < 0.0)
- throw std::runtime_error(Format("Height to layout must sufficient. But in {}, height for content is {}.", ToUtf8String(GetControlType()), content_rect.height));
-
- OnLayoutContent(content_rect);
}
+ }
- Size Control::OnMeasureContent(const Size& available_size)
- {
- auto max_child_size = Size::Zero();
- for (auto control: GetChildren())
- {
- control->Measure(available_size);
- 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;
- }
- return max_child_size;
- }
+ void Control::OnDrawContent(ID2D1DeviceContext * device_context)
+ {
- void Control::OnLayoutContent(const Rect& rect)
- {
- for (auto control: GetChildren())
- {
- 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(rect.left, layout_params->width.alignment, rect.width, size.width),
- calculate_anchor(rect.top, 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_;
- }
- }
+ void Control::OnPositionChanged(PositionChangedEventArgs & args)
+ {
- 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;
+ void Control::OnSizeChanged(SizeChangedEventArgs & args)
+ {
+ }
- auto&& left_list = GetAncestorList(left);
- auto&& right_list = GetAncestorList(right);
+ void Control::OnPositionChangedCore(PositionChangedEventArgs & args)
+ {
- // 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;
- }
+ namespace
+ {
+#ifdef CRU_DEBUG_LAYOUT
+ Microsoft::WRL::ComPtr<ID2D1Geometry> CalculateSquareRingGeometry(const Rect& out, const Rect& in)
+ {
+ const auto d2d1_factory = graph::GraphManager::GetInstance()->GetD2D1Factory();
+ Microsoft::WRL::ComPtr<ID2D1RectangleGeometry> out_geometry;
+ ThrowIfFailed(d2d1_factory->CreateRectangleGeometry(Convert(out), &out_geometry));
+ Microsoft::WRL::ComPtr<ID2D1RectangleGeometry> in_geometry;
+ ThrowIfFailed(d2d1_factory->CreateRectangleGeometry(Convert(in), &in_geometry));
+ Microsoft::WRL::ComPtr<ID2D1PathGeometry> result_geometry;
+ ThrowIfFailed(d2d1_factory->CreatePathGeometry(&result_geometry));
+ Microsoft::WRL::ComPtr<ID2D1GeometrySink> sink;
+ ThrowIfFailed(result_geometry->Open(&sink));
+ ThrowIfFailed(out_geometry->CombineWithGeometry(in_geometry.Get(), D2D1_COMBINE_MODE_EXCLUDE, D2D1::Matrix3x2F::Identity(), sink.Get()));
+ ThrowIfFailed(sink->Close());
+ return result_geometry;
}
+#endif
+ }
- 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;
- }
+ void Control::OnSizeChangedCore(SizeChangedEventArgs & args)
+ {
+#ifdef CRU_DEBUG_LAYOUT
+ margin_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Margin), GetRect(RectRange::FullBorder));
+ padding_geometry_ = CalculateSquareRingGeometry(GetRect(RectRange::Padding), GetRect(RectRange::Content));
+#endif
}
+
+ 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);
+ }
+
+ inline Size ThicknessToSize(const Thickness& thickness)
+ {
+ return Size(thickness.left + thickness.right, thickness.top + thickness.bottom);
+ }
+
+ inline float AtLeast0(const float value)
+ {
+ return value < 0 ? 0 : value;
+ }
+
+ Size Control::OnMeasureCore(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 border_size = Size::Zero();
+ if (is_bordered_)
+ {
+ const auto border_width = GetBorderProperty().GetStrokeWidth();
+ border_size = Size(border_width * 2.0f, border_width * 2.0f);
+ }
+
+ // the total size of padding, border and margin
+ const auto outer_size = ThicknessToSize(layout_params->padding) +
+ ThicknessToSize(layout_params->margin) + border_size;
+
+
+ auto&& get_content_measure_length = [](const LayoutSideParams& layout_length, const float available_length, const float outer_length) -> float
+ {
+ float length;
+ if (layout_length.mode == MeasureMode::Exactly)
+ length = layout_length.length;
+ else if (available_length > outer_length)
+ length = available_length - outer_length;
+ else
+ length = 0;
+ return Coerce(length, layout_length.min, layout_length.max);
+ };
+
+ // if padding, margin and border exceeded, then content size is 0.
+ const auto content_measure_size = Size(
+ get_content_measure_length(layout_params->width, available_size.width, outer_size.width),
+ get_content_measure_length(layout_params->height, available_size.height, outer_size.height)
+ );
+
+ const auto content_actual_size = OnMeasureContent(content_measure_size);
+
+ auto&& calculate_final_length = [](const LayoutSideParams& layout_length, const float measure_length, const float actual_length) -> float
+ {
+ // only use measure length when stretch and actual length is smaller than measure length, that is "stretch"
+ if (layout_length.mode == MeasureMode::Stretch && actual_length < measure_length)
+ return measure_length;
+ return Coerce(actual_length, layout_length.min, std::nullopt);
+ };
+
+ const auto final_size = Size(
+ calculate_final_length(layout_params->width, content_measure_size.width, content_actual_size.width),
+ calculate_final_length(layout_params->height, content_measure_size.height, content_actual_size.height)
+ ) + outer_size;
+
+ return final_size;
+ }
+
+ void Control::OnLayoutCore(const Rect& rect)
+ {
+ const auto layout_params = GetLayoutParams();
+
+ auto border_width = 0.0f;
+ if (is_bordered_)
+ {
+ border_width = GetBorderProperty().GetStrokeWidth();
+ }
+
+ const Rect content_rect(
+ rect.left + layout_params->padding.left + layout_params->margin.right + border_width,
+ rect.top + layout_params->padding.top + layout_params->margin.top + border_width,
+ rect.width - layout_params->padding.GetHorizontalTotal() - layout_params->margin.GetHorizontalTotal() - border_width * 2.0f,
+ rect.height - layout_params->padding.GetVerticalTotal() - layout_params->margin.GetVerticalTotal() - border_width * 2.0f
+ );
+
+ if (content_rect.width < 0.0)
+ throw std::runtime_error(Format("Width to layout must sufficient. But in {}, width for content is {}.", ToUtf8String(GetControlType()), content_rect.width));
+ if (content_rect.height < 0.0)
+ throw std::runtime_error(Format("Height to layout must sufficient. But in {}, height for content is {}.", ToUtf8String(GetControlType()), content_rect.height));
+
+ OnLayoutContent(content_rect);
+ }
+
+ Size Control::OnMeasureContent(const Size& available_size)
+ {
+ auto max_child_size = Size::Zero();
+ for (auto control: GetChildren())
+ {
+ control->Measure(available_size);
+ 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;
+ }
+ return max_child_size;
+ }
+
+ void Control::OnLayoutContent(const Rect& rect)
+ {
+ for (auto control: GetChildren())
+ {
+ 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(rect.left, layout_params->width.alignment, rect.width, size.width),
+ calculate_anchor(rect.top, 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/src/ui/control.h b/src/ui/control.h
index 9ee657f7..020f959e 100644
--- a/src/ui/control.h
+++ b/src/ui/control.h
@@ -14,435 +14,432 @@
#include "border_property.h"
#include "cursor.h"
-namespace cru
+namespace cru::ui
{
- namespace ui
- {
- class Control;
- class Window;
+ class Control;
+ class Window;
- //the position cache
- struct ControlPositionCache
- {
- //The lefttop relative to the ancestor.
- Point lefttop_position_absolute;
- };
+ //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;
+ class Control : public Object
+ {
+ friend class Window;
+ friend class LayoutManager;
- protected:
- struct WindowConstructorTag {}; //Used for constructor for class Window.
+ protected:
+ struct WindowConstructorTag {}; //Used for constructor for class Window.
- explicit Control(bool container = false);
+ explicit Control(bool container = false);
- // Used only for creating Window. It will set window_ as window.
- Control(WindowConstructorTag, Window* window);
+ // 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:
+ Control(const Control& other) = delete;
+ Control(Control&& other) = delete;
+ Control& operator=(const Control& other) = delete;
+ Control& operator=(Control&& other) = delete;
+ ~Control() override;
- public:
+ public:
- //*************** region: tree ***************
- virtual StringView GetControlType() const = 0;
+ //*************** region: tree ***************
+ virtual StringView GetControlType() const = 0;
- bool IsContainer() const
- {
- return is_container_;
- }
+ bool IsContainer() const
+ {
+ return is_container_;
+ }
- //Get parent of control, return nullptr if it has no parent.
- Control* GetParent() const
- {
- return parent_;
- }
+ //Get parent of control, return nullptr if it has no parent.
+ Control* GetParent() const
+ {
+ return parent_;
+ }
- //Return a immutable vector of all children.
- const std::vector<Control*>& GetChildren() const;
+ //Return a immutable vector of all children.
+ const std::vector<Control*>& GetChildren() const;
- //Add a child at tail.
- void AddChild(Control* control);
+ //Add a child at tail.
+ void AddChild(Control* control);
- //Add a child before the position.
- void AddChild(Control* control, int position);
+ //Add a child before the position.
+ void AddChild(Control* control, int position);
- //Remove a child.
- void RemoveChild(Control* child);
+ //Remove a child.
+ void RemoveChild(Control* child);
- //Remove a child at specified position.
- void RemoveChild(int position);
+ //Remove a child at specified position.
+ void RemoveChild(int position);
- //Get the ancestor of the control.
- Control* GetAncestor();
+ //Get the ancestor of the control.
+ Control* GetAncestor();
- //Get the window if attached, otherwise, return nullptr.
- Window* GetWindow() const
- {
- return window_;
- }
+ //Get the window if attached, otherwise, return nullptr.
+ Window* GetWindow() const
+ {
+ return window_;
+ }
- //Traverse the tree rooted the control including itself.
- void TraverseDescendants(const std::function<void(Control*)>& predicate);
+ //Traverse the tree rooted the control including itself.
+ void TraverseDescendants(const std::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.
+ //*************** 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();
+ //Get the lefttop relative to its parent.
+ virtual Point GetPositionRelative();
- //Set the lefttop relative to its parent.
- virtual void SetPositionRelative(const Point& position);
+ //Set the lefttop relative to its parent.
+ virtual void SetPositionRelative(const Point& position);
- //Get the actual size.
- virtual Size GetSize();
+ //Get the actual size.
+ virtual Size GetSize();
- //Set the actual size directly without re-layout.
- virtual void SetSize(const Size& size);
+ //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;
+ //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 ControlToWindow(const Point& point) const;
+ //Local point to absolute point.
+ Point ControlToWindow(const Point& point) const;
- //Absolute point to local point.
- Point WindowToControl(const Point& point) const;
+ //Absolute point to local point.
+ Point WindowToControl(const Point& point) const;
- virtual bool IsPointInside(const Point& point);
+ virtual bool IsPointInside(const Point& point);
- //*************** region: graphic ***************
+ //*************** region: graphic ***************
- //Draw this control and its child controls.
- void Draw(ID2D1DeviceContext* device_context);
+ //Draw this control and its child controls.
+ void Draw(ID2D1DeviceContext* device_context);
- virtual void Repaint();
+ virtual void Repaint();
- //*************** region: focus ***************
+ //*************** region: focus ***************
- bool RequestFocus();
+ bool RequestFocus();
- bool HasFocus();
+ bool HasFocus();
- bool IsFocusOnPressed() const
- {
- return is_focus_on_pressed_;
- }
+ bool IsFocusOnPressed() const
+ {
+ return is_focus_on_pressed_;
+ }
- void SetFocusOnPressed(const bool value)
- {
- is_focus_on_pressed_ = value;
- }
+ void SetFocusOnPressed(const bool value)
+ {
+ is_focus_on_pressed_ = value;
+ }
- //*************** region: layout ***************
+ //*************** region: layout ***************
- void InvalidateLayout();
+ void InvalidateLayout();
- void Measure(const Size& available_size);
+ void Measure(const Size& available_size);
- void Layout(const Rect& rect);
+ void Layout(const Rect& rect);
- Size GetDesiredSize() const;
+ Size GetDesiredSize() const;
- void SetDesiredSize(const Size& desired_size);
+ void SetDesiredSize(const Size& desired_size);
- BasicLayoutParams* GetLayoutParams()
- {
- return &layout_params_;
- }
+ BasicLayoutParams* GetLayoutParams()
+ {
+ return &layout_params_;
+ }
- Rect GetRect(RectRange range);
+ Rect GetRect(RectRange range);
- Point TransformPoint(const Point& point, RectRange from = RectRange::Margin, RectRange to = RectRange::Content);
+ Point TransformPoint(const Point& point, RectRange from = RectRange::Margin, RectRange to = RectRange::Content);
- //*************** region: border ***************
+ //*************** region: border ***************
- BorderProperty& GetBorderProperty()
- {
- return border_property_;
- }
+ BorderProperty& GetBorderProperty()
+ {
+ return border_property_;
+ }
- void InvalidateBorder();
+ void InvalidateBorder();
- bool IsBordered() const
- {
- return is_bordered_;
- }
+ bool IsBordered() const
+ {
+ return is_bordered_;
+ }
- void SetBordered(bool bordered);
+ void SetBordered(bool bordered);
- //*************** region: additional properties ***************
- template <typename T>
- std::optional<T> GetAdditionalProperty(const String& key)
+ //*************** region: additional properties ***************
+ template <typename T>
+ std::optional<T> GetAdditionalProperty(const String& key)
+ {
+ try
{
- 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(Format("Key \"{}\" is not of the type {}.", ToUtf8String(key), typeid(T).name()));
- }
+ 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;
}
-
- template <typename T>
- void SetAdditionalProperty(const String& key, const T& value)
+ catch (const std::bad_any_cast&)
{
- additional_properties_[key] = std::make_any<T>(value);
+ throw std::runtime_error(Format("Key \"{}\" is not of the type {}.", ToUtf8String(key), typeid(T).name()));
}
+ }
- template <typename T>
- void SetAdditionalProperty(const String& key, T&& value)
- {
- additional_properties_[key] = std::make_any<T>(std::move(value));
- }
+ template <typename T>
+ void SetAdditionalProperty(const String& key, const T& value)
+ {
+ additional_properties_[key] = std::make_any<T>(value);
+ }
-
- //*************** region: cursor ***************
- // If cursor is set to null, then it uses parent's cursor.
- // Window's cursor can't be null.
+ template <typename T>
+ void SetAdditionalProperty(const String& key, T&& value)
+ {
+ additional_properties_[key] = std::make_any<T>(std::move(value));
+ }
- Cursor::Ptr GetCursor() const
- {
- return cursor_;
- }
+
+ //*************** region: cursor ***************
+ // If cursor is set to null, then it uses parent's cursor.
+ // Window's cursor can't be null.
- void SetCursor(const Cursor::Ptr& cursor);
-
-
- //*************** 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);
-
- private:
- void OnDraw(ID2D1DeviceContext* device_context);
-
- protected:
- virtual void OnDrawContent(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 ***************
- Size OnMeasureCore(const Size& available_size);
- void OnLayoutCore(const Rect& rect);
-
- virtual Size OnMeasureContent(const Size& available_size);
- virtual void OnLayoutContent(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.");
- }
+ Cursor::Ptr GetCursor() const
+ {
+ return cursor_;
+ }
- private:
- bool is_container_;
+ void SetCursor(const Cursor::Ptr& cursor);
+
+
+ //*************** 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);
+
+ private:
+ void OnDraw(ID2D1DeviceContext* device_context);
+
+ protected:
+ virtual void OnDrawContent(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 ***************
+ Size OnMeasureCore(const Size& available_size);
+ void OnLayoutCore(const Rect& rect);
+
+ virtual Size OnMeasureContent(const Size& available_size);
+ virtual void OnLayoutContent(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.");
+ }
- protected:
- Window * window_ = nullptr; // protected for Window class to write it as itself in constructor.
+ private:
+ bool is_container_;
- private:
- Control * parent_ = nullptr;
- std::vector<Control*> children_{};
+ protected:
+ Window * window_ = nullptr; // protected for Window class to write it as itself in constructor.
- // 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();
+ private:
+ Control * parent_ = nullptr;
+ std::vector<Control*> children_{};
- ControlPositionCache position_cache_{};
+ // 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();
- bool is_mouse_inside_ = false;
+ ControlPositionCache position_cache_{};
- std::unordered_map<MouseButton, bool> is_mouse_click_valid_map_
- {
- { MouseButton::Left, true },
- { MouseButton::Middle, true },
- { MouseButton::Right, true }
- }; // used for clicking determination
+ bool is_mouse_inside_ = false;
- BasicLayoutParams layout_params_{};
- Size desired_size_ = Size::Zero();
+ std::unordered_map<MouseButton, bool> is_mouse_click_valid_map_
+ {
+ { MouseButton::Left, true },
+ { MouseButton::Middle, true },
+ { MouseButton::Right, true }
+ }; // used for clicking determination
- bool is_bordered_ = false;
- BorderProperty border_property_;
+ BasicLayoutParams layout_params_{};
+ Size desired_size_ = Size::Zero();
- std::unordered_map<String, std::any> additional_properties_{};
+ bool is_bordered_ = false;
+ BorderProperty border_property_;
- bool is_focus_on_pressed_ = true;
+ std::unordered_map<String, std::any> additional_properties_{};
+
+ bool is_focus_on_pressed_ = true;
#ifdef CRU_DEBUG_LAYOUT
- Microsoft::WRL::ComPtr<ID2D1Geometry> margin_geometry_;
- Microsoft::WRL::ComPtr<ID2D1Geometry> padding_geometry_;
+ Microsoft::WRL::ComPtr<ID2D1Geometry> margin_geometry_;
+ Microsoft::WRL::ComPtr<ID2D1Geometry> padding_geometry_;
#endif
- Cursor::Ptr cursor_{};
- };
+ Cursor::Ptr cursor_{};
+ };
- // Find the lowest common ancestor.
- // Return nullptr if "left" and "right" are not in the same tree.
- Control* FindLowestCommonAncestor(Control* left, Control* right);
+ // 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);
+ // 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;
- }
+ 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;
+ }
- template <typename TControl, typename... Args>
- TControl* CreateWithLayout(const Thickness& padding, const Thickness& margin, 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()->padding = padding;
- control->GetLayoutParams()->margin = margin;
- return control;
- }
-
- template <typename TControl, typename... Args>
- TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, const Thickness& padding, const Thickness& margin, 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;
- control->GetLayoutParams()->padding = padding;
- control->GetLayoutParams()->margin = margin;
- return control;
- }
+ template <typename TControl, typename... Args>
+ TControl* CreateWithLayout(const Thickness& padding, const Thickness& margin, 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()->padding = padding;
+ control->GetLayoutParams()->margin = margin;
+ return control;
+ }
- using ControlList = std::initializer_list<Control*>;
+ template <typename TControl, typename... Args>
+ TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, const Thickness& padding, const Thickness& margin, 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;
+ control->GetLayoutParams()->padding = padding;
+ control->GetLayoutParams()->margin = margin;
+ return control;
}
+
+ using ControlList = std::initializer_list<Control*>;
}
diff --git a/src/ui/controls/text_block.cpp b/src/ui/controls/text_block.cpp
index 7c52684d..e6c7fd7e 100644
--- a/src/ui/controls/text_block.cpp
+++ b/src/ui/controls/text_block.cpp
@@ -2,22 +2,16 @@
#include "ui/window.h"
-namespace cru
+namespace cru::ui::controls
{
- namespace ui
+ TextBlock::TextBlock(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format,
+ const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush) : TextControl(init_text_format, init_brush)
{
- namespace controls
- {
- TextBlock::TextBlock(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format,
- const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush) : TextControl(init_text_format, init_brush)
- {
- }
+ }
- StringView TextBlock::GetControlType() const
- {
- return control_type;
- }
- }
+ StringView TextBlock::GetControlType() const
+ {
+ return control_type;
}
}
diff --git a/src/ui/cursor.h b/src/ui/cursor.h
index 3c09b35e..ccb21d32 100644
--- a/src/ui/cursor.h
+++ b/src/ui/cursor.h
@@ -2,7 +2,6 @@
#include "system_headers.h"
#include <memory>
-#include <unordered_map>
#include "base.h"
diff --git a/src/ui/events/ui_event.cpp b/src/ui/events/ui_event.cpp
index 5e9ca452..9f5185ce 100644
--- a/src/ui/events/ui_event.cpp
+++ b/src/ui/events/ui_event.cpp
@@ -2,18 +2,12 @@
#include "ui/control.h"
-namespace cru
+namespace cru::ui::events
{
- namespace ui
+ Point MouseEventArgs::GetPoint(Control* control, const RectRange range) const
{
- namespace events
- {
- Point MouseEventArgs::GetPoint(Control* control, const RectRange range) const
- {
- if (point_.has_value())
- return control->TransformPoint(control->WindowToControl(point_.value()), RectRange::Margin, range);
- return Point();
- }
- }
+ if (point_.has_value())
+ return control->TransformPoint(control->WindowToControl(point_.value()), RectRange::Margin, range);
+ return Point();
}
}
diff --git a/src/ui/events/ui_event.h b/src/ui/events/ui_event.h
index 1a6f4046..24429f04 100644
--- a/src/ui/events/ui_event.h
+++ b/src/ui/events/ui_event.h
@@ -8,311 +8,308 @@
#include "ui/ui_base.h"
#include "ui/layout_base.h"
-namespace cru
+namespace cru::ui
{
- namespace ui
+ class Control;
+}
+
+namespace cru::ui::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, RectRange range = RectRange::Content) 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
{
- class Control;
+ 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)
+ {
- namespace events
+ }
+ 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)
{
- 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, RectRange range = RectRange::Content) 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
+ 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>;
+}
diff --git a/src/ui/layout_base.h b/src/ui/layout_base.h
index 4a4c09ea..b3001268 100644
--- a/src/ui/layout_base.h
+++ b/src/ui/layout_base.h
@@ -5,187 +5,184 @@
#include "base.h"
#include "ui_base.h"
-namespace cru
+namespace cru::ui
{
- namespace ui
+ class Control;
+ class Window;
+
+ enum class Alignment
{
- class Control;
- class Window;
+ Center,
+ Start,
+ End
+ };
- enum class Alignment
- {
- Center,
- Start,
- End
- };
+ enum class MeasureMode
+ {
+ Exactly,
+ Content,
+ Stretch
+ };
- enum class MeasureMode
+ enum class RectRange
+ {
+ Content, // content excluding padding, border and margin
+ Padding, // only including content and padding
+ HalfBorder, // including content, padding and half border
+ FullBorder, // including content, padding and full border
+ Margin // including content, padding, border and margin
+ };
+
+ struct Thickness
+ {
+ constexpr static Thickness Zero()
{
- Exactly,
- Content,
- Stretch
- };
+ return Thickness(0);
+ }
+
+ constexpr Thickness() : Thickness(0) { }
- enum class RectRange
+ 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 GetHorizontalTotal() const
{
- Content, // content excluding padding, border and margin
- Padding, // only including content and padding
- HalfBorder, // including content, padding and half border
- FullBorder, // including content, padding and full border
- Margin // including content, padding, border and margin
- };
-
- struct Thickness
+ return left + right;
+ }
+
+ float GetVerticalTotal() const
{
- constexpr static Thickness Zero()
- {
- return Thickness(0);
- }
+ return top + bottom;
+ }
- constexpr Thickness() : Thickness(0) { }
+ float Validate() const
+ {
+ return left >= 0.0 && top >= 0.0 && right >= 0.0 && bottom >= 0.0;
+ }
- constexpr explicit Thickness(const float width)
- : left(width), top(width), right(width), bottom(width) { }
+ float left;
+ float top;
+ float right;
+ float bottom;
+ };
- constexpr explicit Thickness(const float horizontal, const float vertical)
- : left(horizontal), top(vertical), right(horizontal), bottom(vertical) { }
+ struct LayoutSideParams final
+ {
+ constexpr static LayoutSideParams Exactly(const float length, const Alignment alignment = Alignment::Center)
+ {
+ return LayoutSideParams(MeasureMode::Exactly, length, alignment);
+ }
- constexpr Thickness(const float left, const float top, const float right, const float bottom)
- : left(left), top(top), right(right), bottom(bottom) { }
+ constexpr static LayoutSideParams Content(const Alignment alignment = Alignment::Center)
+ {
+ return LayoutSideParams(MeasureMode::Content, 0, alignment);
+ }
- float GetHorizontalTotal() const
- {
- return left + right;
- }
+ constexpr static LayoutSideParams Stretch(const Alignment alignment = Alignment::Center)
+ {
+ return LayoutSideParams(MeasureMode::Stretch, 0, alignment);
+ }
- float GetVerticalTotal() const
- {
- return top + bottom;
- }
+ constexpr LayoutSideParams() = default;
- float Validate() const
- {
- return left >= 0.0 && top >= 0.0 && right >= 0.0 && bottom >= 0.0;
- }
+ constexpr explicit LayoutSideParams(const MeasureMode mode, const float length, const Alignment alignment)
+ : length(length), mode(mode), alignment(alignment)
+ {
- float left;
- float top;
- float right;
- float bottom;
- };
+ }
- 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 (length < 0.0)
- return false;
- if (min.has_value() && min.value() < 0.0)
- return false;
- if (max.has_value() && max.value() < 0.0)
- return false;
- if (min.has_value() && max.has_value() && min.value() > max.value())
- return false;
- return true;
- }
-
- // only used in exactly mode, specify the exactly side length of content.
- float length = 0.0;
- MeasureMode mode = MeasureMode::Content;
- Alignment alignment = Alignment::Center;
-
- // min and max specify the min/max side length of content.
- // they are used as hint and respect the actual size that content needs.
- // when mode is exactly, length is coerced into the min-max range.
- std::optional<float> min = std::nullopt;
- std::optional<float> max = std::nullopt;
- };
-
- struct BasicLayoutParams final
+ constexpr bool Validate() const
{
- BasicLayoutParams() = default;
- BasicLayoutParams(const BasicLayoutParams&) = default;
- BasicLayoutParams(BasicLayoutParams&&) = default;
- BasicLayoutParams& operator = (const BasicLayoutParams&) = default;
- BasicLayoutParams& operator = (BasicLayoutParams&&) = default;
- ~BasicLayoutParams() = default;
-
- bool Validate() const
- {
- return width.Validate() && height.Validate() && margin.Validate() && padding.Validate();
- }
-
- LayoutSideParams width;
- LayoutSideParams height;
- Thickness padding;
- Thickness margin;
- };
-
-
- class LayoutManager : public Object
+ if (length < 0.0)
+ return false;
+ if (min.has_value() && min.value() < 0.0)
+ return false;
+ if (max.has_value() && max.value() < 0.0)
+ return false;
+ if (min.has_value() && max.has_value() && min.value() > max.value())
+ return false;
+ return true;
+ }
+
+ // only used in exactly mode, specify the exactly side length of content.
+ float length = 0.0;
+ MeasureMode mode = MeasureMode::Content;
+ Alignment alignment = Alignment::Center;
+
+ // min and max specify the min/max side length of content.
+ // they are used as hint and respect the actual size that content needs.
+ // when mode is exactly, length is coerced into the min-max range.
+ std::optional<float> min = std::nullopt;
+ std::optional<float> max = std::nullopt;
+ };
+
+ 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
{
- public:
- static LayoutManager* GetInstance();
+ return width.Validate() && height.Validate() && margin.Validate() && padding.Validate();
+ }
+
+ LayoutSideParams width;
+ LayoutSideParams height;
+ Thickness padding;
+ Thickness margin;
+ };
+
+
+ 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;
+ 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;
- //*************** region: position cache ***************
+ //*************** region: position cache ***************
- //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);
- //*************** region: layout ***************
+ //*************** region: layout ***************
- void InvalidateWindowLayout(Window* window);
+ void InvalidateWindowLayout(Window* window);
- void RefreshInvalidWindowLayout();
+ void RefreshInvalidWindowLayout();
- private:
- static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute);
+ private:
+ static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute);
- private:
- std::unordered_set<Control*> cache_invalid_controls_;
- std::unordered_set<Window*> layout_invalid_windows_;
- };
- }
+ private:
+ std::unordered_set<Control*> cache_invalid_controls_;
+ std::unordered_set<Window*> layout_invalid_windows_;
+ };
}
diff --git a/src/ui/ui_base.cpp b/src/ui/ui_base.cpp
index 3bee2269..0195c588 100644
--- a/src/ui/ui_base.cpp
+++ b/src/ui/ui_base.cpp
@@ -2,18 +2,17 @@
#include "system_headers.h"
-namespace cru {
- namespace ui {
- bool IsKeyDown(const int virtual_code)
- {
- const auto result = ::GetKeyState(virtual_code);
- return (static_cast<unsigned short>(result) & 0x8000) != 0;
- }
+namespace cru::ui
+{
+ bool IsKeyDown(const int virtual_code)
+ {
+ const auto result = ::GetKeyState(virtual_code);
+ return (static_cast<unsigned short>(result) & 0x8000) != 0;
+ }
- bool IsKeyToggled(const int virtual_code)
- {
- const auto result = ::GetKeyState(virtual_code);
- return (static_cast<unsigned short>(result) & 1) != 0;
- }
+ bool IsKeyToggled(const int virtual_code)
+ {
+ const auto result = ::GetKeyState(virtual_code);
+ return (static_cast<unsigned short>(result) & 1) != 0;
}
}
diff --git a/src/ui/ui_base.h b/src/ui/ui_base.h
index bff30bfd..8daa43d7 100644
--- a/src/ui/ui_base.h
+++ b/src/ui/ui_base.h
@@ -3,158 +3,155 @@
#include <optional>
-namespace cru
+namespace cru::ui
{
- namespace ui
+ struct Point
{
- struct Point
+ constexpr static Point Zero()
{
- constexpr static Point Zero()
- {
- return Point(0, 0);
- }
+ 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 Point() = default;
- constexpr Point(const float x, const float y) : x(x), y(y) { }
+ constexpr bool operator==(const Point& left, const Point& right)
+ {
+ return left.x == right.x && left.y == right.y;
+ }
- float x = 0;
- float y = 0;
- };
+ constexpr bool operator!=(const Point& left, const Point& right)
+ {
+ return !(left == right);
+ }
- constexpr bool operator==(const Point& left, const Point& right)
+ struct Size
+ {
+ constexpr static Size Zero()
{
- return left.x == right.x && left.y == right.y;
+ return Size(0, 0);
}
- constexpr bool operator!=(const Point& left, const Point& right)
+ 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);
+ }
+
+ constexpr bool operator==(const Size& left, const Size& right)
+ {
+ return left.width == right.width && left.height == right.height;
+ }
+
+ constexpr bool operator!=(const Size& left, const Size& right)
+ {
+ return !(left == right);
+ }
+
+ 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 !(left == right);
+ return Rect(left, top, right - left, bottom - top);
}
- struct Size
+ constexpr float GetRight() const
{
- constexpr static Size Zero()
- {
- return Size(0, 0);
- }
-
- constexpr Size() = default;
- constexpr Size(const float width, const float height) : width(width), height(height) { }
+ return left + width;
+ }
- float width = 0;
- float height = 0;
- };
+ constexpr float GetBottom() const
+ {
+ return top + height;
+ }
- constexpr Size operator + (const Size& left, const Size& right)
+ constexpr Point GetLeftTop() const
{
- return Size(left.width + right.width, left.height + right.height);
+ return Point(left, top);
}
- constexpr Size operator - (const Size& left, const Size& right)
+ constexpr Point GetRightBottom() const
{
- return Size(left.width - right.width, left.height - right.height);
+ return Point(left + width, top + height);
}
- constexpr bool operator==(const Size& left, const Size& right)
+ constexpr Size GetSize() const
{
- return left.width == right.width && left.height == right.height;
+ return Size(width, height);
}
- constexpr bool operator!=(const Size& left, const Size& right)
+ constexpr bool IsPointInside(const Point& point) const
{
- return !(left == right);
+ return
+ point.x >= left &&
+ point.x < GetRight() &&
+ point.y >= top &&
+ point.y < GetBottom();
}
- struct Rect
+ float left = 0.0f;
+ float top = 0.0f;
+ float width = 0.0f;
+ float height = 0.0f;
+ };
+
+ enum class MouseButton
+ {
+ Left,
+ Right,
+ Middle
+ };
+
+ struct TextRange
+ {
+ constexpr static std::optional<TextRange> FromTwoSides(unsigned first, unsigned second)
{
- 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;
- };
-
- enum class MouseButton
+ if (first > second)
+ return std::make_optional<TextRange>(second, first - second);
+ if (first < second)
+ return std::make_optional<TextRange>(first, second - first);
+ return std::nullopt;
+ }
+
+ constexpr static std::pair<unsigned, unsigned> ToTwoSides(std::optional<TextRange> text_range, unsigned default_position = 0)
{
- Left,
- Right,
- Middle
- };
+ if (text_range.has_value())
+ return std::make_pair(text_range.value().position, text_range.value().position + text_range.value().count);
+ return std::make_pair(default_position, default_position);
+ }
- struct TextRange
+ constexpr TextRange() = default;
+ constexpr TextRange(const unsigned position, const unsigned count)
+ : position(position), count(count)
{
- constexpr static std::optional<TextRange> FromTwoSides(unsigned first, unsigned second)
- {
- if (first > second)
- return std::make_optional<TextRange>(second, first - second);
- if (first < second)
- return std::make_optional<TextRange>(first, second - first);
- return std::nullopt;
- }
-
- constexpr static std::pair<unsigned, unsigned> ToTwoSides(std::optional<TextRange> text_range, unsigned default_position = 0)
- {
- if (text_range.has_value())
- return std::make_pair(text_range.value().position, text_range.value().position + text_range.value().count);
- return std::make_pair(default_position, default_position);
- }
-
- constexpr TextRange() = default;
- constexpr TextRange(const unsigned position, const unsigned count)
- : position(position), count(count)
- {
-
- }
-
- unsigned position = 0;
- unsigned count = 0;
- };
-
- bool IsKeyDown(int virtual_code);
- bool IsKeyToggled(int virtual_code);
- }
+
+ }
+
+ unsigned position = 0;
+ unsigned count = 0;
+ };
+
+ bool IsKeyDown(int virtual_code);
+ bool IsKeyToggled(int virtual_code);
}
diff --git a/src/ui/window.cpp b/src/ui/window.cpp
index 5ca5ad3f..cc08810b 100644
--- a/src/ui/window.cpp
+++ b/src/ui/window.cpp
@@ -5,661 +5,658 @@
#include "exception.h"
#include "cursor.h"
-namespace cru
+namespace cru::ui
{
- namespace ui
+ WindowClass::WindowClass(const String& name, WNDPROC window_proc, HINSTANCE h_instance)
+ : name_(name)
{
- 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.");
- }
+ 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 __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;
+ LRESULT result;
+ if (window != nullptr && window->HandleWindowMessage(hWnd, Msg, wParam, lParam, result))
+ return result;
- return DefWindowProc(hWnd, Msg, wParam, lParam);
- }
+ return DefWindowProc(hWnd, Msg, wParam, lParam);
+ }
- WindowManager::WindowManager() {
- general_window_class_ = std::make_unique<WindowClass>(
- L"CruUIWindowClass",
- GeneralWndProc,
- Application::GetInstance()->GetInstanceHandle()
- );
- }
+ 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.");
+ 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);
- }
+ 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);
+ 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);
- }
+ 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;
- }
+ 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;
+ }
- std::vector<Window*> WindowManager::GetAllWindows() const
- {
- std::vector<Window*> windows;
- for (auto [key, value] : window_map_)
- windows.push_back(value);
- return windows;
- }
+ std::vector<Window*> WindowManager::GetAllWindows() const
+ {
+ std::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)
- );
- }
+ inline Point PiToDip(const POINT& pi_point)
+ {
+ return Point(
+ graph::PixelToDipX(pi_point.x),
+ graph::PixelToDipY(pi_point.y)
+ );
+ }
- namespace
+ namespace
+ {
+ Cursor::Ptr GetCursorInherit(Control* control)
{
- Cursor::Ptr GetCursorInherit(Control* control)
+ while (control != nullptr)
{
- while (control != nullptr)
- {
- const auto cursor = control->GetCursor();
- if (cursor != nullptr)
- return cursor;
- control = control->GetParent();
- }
- return cursors::arrow;
+ const auto cursor = control->GetCursor();
+ if (cursor != nullptr)
+ return cursor;
+ control = control->GetParent();
}
+ return cursors::arrow;
}
+ }
- 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
- );
+ 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.");
+ if (hwnd_ == nullptr)
+ throw std::runtime_error("Failed to create window.");
- app->GetWindowManager()->RegisterWindow(hwnd_, this);
+ app->GetWindowManager()->RegisterWindow(hwnd_, this);
- render_target_ = app->GetGraphManager()->CreateWindowRenderTarget(hwnd_);
+ render_target_ = app->GetGraphManager()->CreateWindowRenderTarget(hwnd_);
- SetCursor(cursors::arrow);
- }
+ SetCursor(cursors::arrow);
+ }
- Window::~Window() {
- Close();
- TraverseDescendants([this](Control* control) {
- control->OnDetachToWindow(this);
- });
- }
+ Window::~Window() {
+ Close();
+ TraverseDescendants([this](Control* control) {
+ control->OnDetachToWindow(this);
+ });
+ }
- StringView Window::GetControlType() const
- {
- return control_type;
- }
+ StringView Window::GetControlType() const
+ {
+ return control_type;
+ }
- void Window::Close() {
- if (IsWindowValid())
- DestroyWindow(hwnd_);
- }
+ void Window::Close() {
+ if (IsWindowValid())
+ DestroyWindow(hwnd_);
+ }
- void Window::Repaint() {
- if (IsWindowValid()) {
- InvalidateRect(hwnd_, nullptr, false);
- }
+ void Window::Repaint() {
+ if (IsWindowValid()) {
+ InvalidateRect(hwnd_, nullptr, false);
}
+ }
- void Window::Show() {
- if (IsWindowValid()) {
- ShowWindow(hwnd_, SW_SHOWNORMAL);
- }
+ void Window::Show() {
+ if (IsWindowValid()) {
+ ShowWindow(hwnd_, SW_SHOWNORMAL);
}
+ }
- void Window::Hide() {
- if (IsWindowValid()) {
- ShowWindow(hwnd_, SW_HIDE);
- }
+ 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)
+ );
+ }
- Size Window::GetClientSize() {
- if (!IsWindowValid())
- return Size();
+ 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));
- const auto pixel_rect = GetClientRectPixel();
- return Size(
- graph::PixelToDipX(pixel_rect.right),
- graph::PixelToDipY(pixel_rect.bottom)
+ 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
);
}
+ }
- 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 Window::GetWindowRect() {
- if (!IsWindowValid())
- return Rect();
+ RECT rect;
+ ::GetWindowRect(hwnd_, &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)
+ );
+ }
- 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
);
}
+ }
- 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;
- }
- }
+ bool Window::HandleWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param, LRESULT & result) {
- 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:
+ 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())
{
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseUpInternal(MouseButton::Middle, point);
- result = 0;
+ result = args.GetResult().value();
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()
+ 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:
{
- if (!IsWindowValid())
- return Point::Zero();
POINT point;
- ::GetCursorPos(&point);
- ::ScreenToClient(hwnd_, &point);
- return PiToDip(point);
+ point.x = GET_X_LPARAM(l_param);
+ point.y = GET_Y_LPARAM(l_param);
+ OnMouseMoveInternal(point);
+ result = 0;
+ return true;
}
-
- Point Window::GetPositionRelative()
+ case WM_LBUTTONDOWN:
{
- return Point();
+ POINT point;
+ point.x = GET_X_LPARAM(l_param);
+ point.y = GET_Y_LPARAM(l_param);
+ OnMouseDownInternal(MouseButton::Left, point);
+ result = 0;
+ return true;
}
-
- void Window::SetPositionRelative(const Point & position)
+ 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;
}
-
- Size Window::GetSize()
+ case WM_RBUTTONDOWN:
{
- return GetClientSize();
+ POINT point;
+ point.x = GET_X_LPARAM(l_param);
+ point.y = GET_Y_LPARAM(l_param);
+ OnMouseDownInternal(MouseButton::Right, point);
+ result = 0;
+ return true;
}
-
- void Window::SetSize(const Size & size)
+ 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;
}
-
- void Window::Relayout()
+ case WM_MBUTTONDOWN:
{
- OnMeasureCore(GetSize());
- OnLayoutCore(Rect(Point::Zero(), GetSize()));
+ POINT point;
+ point.x = GET_X_LPARAM(l_param);
+ point.y = GET_Y_LPARAM(l_param);
+ OnMouseDownInternal(MouseButton::Middle, point);
+ result = 0;
+ return true;
}
-
- void Window::RefreshControlList() {
- control_list_.clear();
- TraverseDescendants([this](Control* control) {
- this->control_list_.push_back(control);
- });
+ 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;
+ }
+ }
- Control * Window::HitTest(const Point & point)
- {
- for (auto i = control_list_.crbegin(); i != control_list_.crend(); ++i) {
- auto control = *i;
- if (control->IsPointInside(control->WindowToControl(point))) {
- return control;
- }
+ Point Window::GetMousePosition()
+ {
+ if (!IsWindowValid())
+ return Point::Zero();
+ 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::Relayout()
+ {
+ OnMeasureCore(GetSize());
+ OnLayoutCore(Rect(Point::Zero(), GetSize()));
+ }
+
+ 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->WindowToControl(point))) {
+ return control;
}
- return nullptr;
}
+ 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.");
- bool Window::RequestFocusFor(Control * control)
+ if (!IsWindowValid())
+ return false;
+
+ if (!window_focus_)
{
- if (control == nullptr)
- throw std::invalid_argument("The control to request focus can't be null. You can set it as the window.");
+ focus_control_ = control;
+ ::SetFocus(hwnd_);
+ return true; // event dispatch will be done in window message handling function "OnSetFocusInternal".
+ }
- if (!IsWindowValid())
- return false;
+ if (focus_control_ == control)
+ return true;
- if (!window_focus_)
- {
- focus_control_ = control;
- ::SetFocus(hwnd_);
- return true; // event dispatch will be done in window message handling function "OnSetFocusInternal".
- }
+ DispatchEvent(focus_control_, &Control::RaiseLoseFocusEvent, nullptr, false);
- if (focus_control_ == control)
- return true;
+ focus_control_ = control;
- DispatchEvent(focus_control_, &Control::RaiseLoseFocusEvent, nullptr, false);
+ DispatchEvent(control, &Control::RaiseGetFocusEvent, nullptr, false);
- focus_control_ = control;
+ return true;
+ }
- DispatchEvent(control, &Control::RaiseGetFocusEvent, nullptr, false);
+ Control* Window::GetFocusControl()
+ {
+ return focus_control_;
+ }
- return true;
+ 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;
}
-
- Control* Window::GetFocusControl()
+ else
{
- return focus_control_;
+ return ReleaseCurrentMouseCapture();
}
+ }
- Control* Window::CaptureMouseFor(Control* control)
+ Control* Window::ReleaseCurrentMouseCapture()
+ {
+ if (mouse_capture_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();
- }
+ const auto previous = mouse_capture_control_;
+ mouse_capture_control_ = nullptr;
+ ::ReleaseCapture();
+ DispatchMouseHoverControlChangeEvent(previous, mouse_hover_control_, GetMousePosition());
+ return previous;
}
-
- Control* Window::ReleaseCurrentMouseCapture()
+ else
{
- 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;
- }
+ return nullptr;
}
+ }
- void Window::UpdateCursor()
+ void Window::UpdateCursor()
+ {
+ if (IsWindowValid() && mouse_hover_control_ != nullptr)
{
- if (IsWindowValid() && mouse_hover_control_ != nullptr)
- {
- SetCursorInternal(GetCursorInherit(mouse_hover_control_)->GetHandle());
- }
+ SetCursorInternal(GetCursorInherit(mouse_hover_control_)->GetHandle());
}
+ }
#ifdef CRU_DEBUG_LAYOUT
- void Window::SetDebugLayout(const bool value)
+ void Window::SetDebugLayout(const bool value)
+ {
+ if (debug_layout_ != value)
{
- if (debug_layout_ != value)
- {
- debug_layout_ = value;
- Repaint();
- }
+ debug_layout_ = value;
+ Repaint();
}
+ }
#endif
- RECT Window::GetClientRectPixel() {
- RECT rect{ };
- GetClientRect(hwnd_, &rect);
- return rect;
- }
+ 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;
- }
+ bool Window::IsMessageInQueue(UINT message)
+ {
+ MSG msg;
+ return ::PeekMessageW(&msg, hwnd_, message, message, PM_NOREMOVE) != 0;
+ }
- void Window::SetCursorInternal(HCURSOR cursor)
+ void Window::SetCursorInternal(HCURSOR cursor)
+ {
+ if (IsWindowValid())
{
- if (IsWindowValid())
- {
- ::SetClassLongPtrW(GetWindowHandle(), GCLP_HCURSOR, reinterpret_cast<LONG_PTR>(cursor));
- if (mouse_hover_control_ != nullptr)
- ::SetCursor(cursor);
- }
+ ::SetClassLongPtrW(GetWindowHandle(), GCLP_HCURSOR, reinterpret_cast<LONG_PTR>(cursor));
+ if (mouse_hover_control_ != nullptr)
+ ::SetCursor(cursor);
}
+ }
- Size Window::OnMeasureContent(const Size& available_size)
+ Size Window::OnMeasureContent(const Size& available_size)
+ {
+ for (auto control: GetChildren())
{
- for (auto control: GetChildren())
- {
- control->Measure(available_size);
- }
- return available_size;
+ control->Measure(available_size);
}
+ return available_size;
+ }
- void Window::OnDestroyInternal() {
- Application::GetInstance()->GetWindowManager()->UnregisterWindow(hwnd_);
- hwnd_ = nullptr;
- }
+ void Window::OnDestroyInternal() {
+ Application::GetInstance()->GetWindowManager()->UnregisterWindow(hwnd_);
+ hwnd_ = nullptr;
+ }
- void Window::OnPaintInternal() {
- render_target_->SetAsTarget();
+ void Window::OnPaintInternal() {
+ render_target_->SetAsTarget();
- auto device_context = render_target_->GetD2DDeviceContext();
+ auto device_context = render_target_->GetD2DDeviceContext();
- device_context->BeginDraw();
+ device_context->BeginDraw();
- //Clear the background.
- device_context->Clear(D2D1::ColorF(D2D1::ColorF::White));
+ //Clear the background.
+ device_context->Clear(D2D1::ColorF(D2D1::ColorF::White));
- Draw(device_context.Get());
+ Draw(device_context.Get());
- ThrowIfFailed(
- device_context->EndDraw(), "Failed to draw window."
- );
+ ThrowIfFailed(
+ device_context->EndDraw(), "Failed to draw window."
+ );
- render_target_->Present();
+ render_target_->Present();
- ValidateRect(hwnd_, nullptr);
- }
+ ValidateRect(hwnd_, nullptr);
+ }
- void Window::OnResizeInternal(const int new_width, const int new_height) {
- render_target_->ResizeBuffer(new_width, new_height);
- if (!(new_width == 0 && new_height == 0))
- InvalidateLayout();
- }
+ void Window::OnResizeInternal(const int new_width, const int new_height) {
+ render_target_->ResizeBuffer(new_width, new_height);
+ if (!(new_width == 0 && new_height == 0))
+ InvalidateLayout();
+ }
- void Window::OnSetFocusInternal()
- {
- window_focus_ = true;
- DispatchEvent(focus_control_, &Control::RaiseGetFocusEvent, nullptr, true);
- }
+ 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::OnKillFocusInternal()
+ {
+ window_focus_ = false;
+ DispatchEvent(focus_control_, &Control::RaiseLoseFocusEvent, nullptr, true);
+ }
- void Window::OnMouseMoveInternal(const POINT point)
- {
- const auto dip_point = PiToDip(point);
+ 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_;
+ //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);
- }
+ 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;
+ //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);
- }
+ if (mouse_capture_control_) // if mouse is captured
+ {
+ DispatchEvent(mouse_capture_control_, &Control::RaiseMouseMoveEvent, nullptr, dip_point);
}
-
- void Window::OnMouseLeaveInternal()
+ else
{
- DispatchEvent(mouse_hover_control_, &Control::RaiseMouseLeaveEvent, nullptr);
- mouse_hover_control_ = nullptr;
+ DispatchMouseHoverControlChangeEvent(old_control_mouse_hover, new_control_mouse_hover, dip_point);
+ DispatchEvent(new_control_mouse_hover, &Control::RaiseMouseMoveEvent, nullptr, dip_point);
}
+ }
- void Window::OnMouseDownInternal(MouseButton button, POINT point)
- {
- const auto dip_point = PiToDip(point);
+ void Window::OnMouseLeaveInternal()
+ {
+ DispatchEvent(mouse_hover_control_, &Control::RaiseMouseLeaveEvent, nullptr);
+ mouse_hover_control_ = nullptr;
+ }
- Control* control;
+ void Window::OnMouseDownInternal(MouseButton button, POINT point)
+ {
+ const auto dip_point = PiToDip(point);
- if (mouse_capture_control_)
- control = mouse_capture_control_;
- else
- control = HitTest(dip_point);
+ Control* control;
- DispatchEvent(control, &Control::RaiseMouseDownEvent, nullptr, dip_point, button);
- }
+ if (mouse_capture_control_)
+ control = mouse_capture_control_;
+ else
+ control = HitTest(dip_point);
- void Window::OnMouseUpInternal(MouseButton button, POINT point)
- {
- const auto dip_point = PiToDip(point);
+ DispatchEvent(control, &Control::RaiseMouseDownEvent, nullptr, dip_point, button);
+ }
- Control* control;
+ void Window::OnMouseUpInternal(MouseButton button, POINT point)
+ {
+ const auto dip_point = PiToDip(point);
- if (mouse_capture_control_)
- control = mouse_capture_control_;
- else
- control = HitTest(dip_point);
+ Control* control;
- DispatchEvent(control, &Control::RaiseMouseUpEvent, nullptr, dip_point, button);
- }
+ if (mouse_capture_control_)
+ control = mouse_capture_control_;
+ else
+ control = HitTest(dip_point);
- void Window::OnKeyDownInternal(int virtual_code)
- {
- DispatchEvent(focus_control_, &Control::RaiseKeyDownEvent, nullptr, virtual_code);
- }
+ DispatchEvent(control, &Control::RaiseMouseUpEvent, nullptr, dip_point, button);
+ }
- void Window::OnKeyUpInternal(int virtual_code)
- {
- DispatchEvent(focus_control_, &Control::RaiseKeyUpEvent, nullptr, virtual_code);
- }
+ void Window::OnKeyDownInternal(int virtual_code)
+ {
+ DispatchEvent(focus_control_, &Control::RaiseKeyDownEvent, nullptr, virtual_code);
+ }
- void Window::OnCharInternal(wchar_t c)
- {
- DispatchEvent(focus_control_, &Control::RaiseCharEvent, nullptr, c);
- }
+ void Window::OnKeyUpInternal(int virtual_code)
+ {
+ DispatchEvent(focus_control_, &Control::RaiseKeyUpEvent, nullptr, virtual_code);
+ }
- void Window::OnActivatedInternal()
- {
- events::UiEventArgs args(this, this);
- activated_event.Raise(args);
- }
+ void Window::OnCharInternal(wchar_t c)
+ {
+ DispatchEvent(focus_control_, &Control::RaiseCharEvent, nullptr, c);
+ }
- void Window::OnDeactivatedInternal()
- {
- events::UiEventArgs args(this, this);
- deactivated_event.Raise(args);
- }
+ void Window::OnActivatedInternal()
+ {
+ events::UiEventArgs args(this, this);
+ activated_event.Raise(args);
+ }
- void Window::DispatchMouseHoverControlChangeEvent(Control* old_control, Control* new_control, const Point& point)
+ 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
{
- 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)
{
- 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.
- UpdateCursor();
- }
+ DispatchEvent(new_control, &Control::RaiseMouseEnterEvent, lowest_common_ancestor, point); // dispatch mouse enter event.
+ UpdateCursor();
}
}
}
diff --git a/src/ui/window.h b/src/ui/window.h
index 1d188a05..822bf32d 100644
--- a/src/ui/window.h
+++ b/src/ui/window.h
@@ -8,294 +8,295 @@
#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();
- }
+namespace cru::graph
+{
+ class WindowRenderTarget;
+}
- ATOM GetAtom() const
- {
- return atom_;
- }
+namespace cru::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;
- private:
- String name_;
- ATOM atom_;
- };
- class WindowManager : public Object
+ const wchar_t* GetName() const
{
- 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;
+ 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();
+ }
- //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);
- std::vector<Window*> GetAllWindows() const;
+ std::vector<Window*> GetAllWindows() const;
- 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 Window : public Control
- {
- friend class WindowManager;
- public:
- static constexpr auto control_type = L"Window";
+ class Window : public Control
+ {
+ friend class WindowManager;
+ public:
+ static constexpr auto control_type = L"Window";
- Window();
- Window(const Window& other) = delete;
- Window(Window&& other) = delete;
- Window& operator=(const Window& other) = delete;
- Window& operator=(Window&& other) = delete;
- ~Window() override;
+ Window();
+ Window(const Window& other) = delete;
+ Window(Window&& other) = delete;
+ Window& operator=(const Window& other) = delete;
+ Window& operator=(Window&& other) = delete;
+ ~Window() override;
- public:
- StringView GetControlType() const override final;
+ public:
+ StringView GetControlType() const override final;
- //*************** 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: mouse ***************
+ //*************** region: mouse ***************
- Point GetMousePosition();
+ Point GetMousePosition();
- Control* GetMouseHoverControl() const
- {
- return mouse_hover_control_;
- }
+ Control* GetMouseHoverControl() const
+ {
+ return mouse_hover_control_;
+ }
- //*************** 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: layout ***************
+ //*************** region: layout ***************
- void Relayout();
+ void Relayout();
- //*************** region: functions ***************
+ //*************** region: functions ***************
- //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 ***************
+ //*************** region: focus ***************
- //Request focus for specified control.
- bool RequestFocusFor(Control* control);
+ //Request focus for specified control.
+ bool RequestFocusFor(Control* control);
- //Get the control that has focus.
- Control* GetFocusControl();
+ //Get the control that has focus.
+ Control* GetFocusControl();
- //*************** region: mouse capture ***************
+ //*************** region: mouse capture ***************
- Control* CaptureMouseFor(Control* control);
- Control* ReleaseCurrentMouseCapture();
+ Control* CaptureMouseFor(Control* control);
+ Control* ReleaseCurrentMouseCapture();
-
- //*************** region: cursor ***************
- void UpdateCursor();
+
+ //*************** region: cursor ***************
+ void UpdateCursor();
- //*************** region: debug ***************
+ //*************** region: debug ***************
#ifdef CRU_DEBUG_LAYOUT
- bool IsDebugLayout() const
- {
- return debug_layout_;
- }
+ bool IsDebugLayout() const
+ {
+ return debug_layout_;
+ }
- void SetDebugLayout(bool value);
+ void SetDebugLayout(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);
-
- void SetCursorInternal(HCURSOR cursor);
-
-
- //*************** region: layout ***************
-
- Size OnMeasureContent(const Size& available_size) override;
-
-
- //*************** 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)
+
+ 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);
+
+ void SetCursorInternal(HCURSOR cursor);
+
+
+ //*************** region: layout ***************
+
+ Size OnMeasureContent(const Size& available_size) override;
+
+
+ //*************** 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)
{
- 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();
- }
+ 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;
-
+ }
+
+ 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_LAYOUT
- bool debug_layout_ = false;
+ bool debug_layout_ = false;
#endif
- };
- }
+ };
}
+