From e5513daa53cb958b0c83d575c440f40aaf40f562 Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 10 Nov 2018 21:53:33 +0800 Subject: ... --- src/main.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index f9bc975c..269da573 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,10 +5,12 @@ #include "ui/controls/toggle_button.hpp" #include "ui/controls/button.hpp" #include "ui/controls/text_box.hpp" +#include "ui/controls/list_item.hpp" -using cru::ui::Rect; using cru::String; +using cru::StringView; using cru::Application; +using cru::ui::Rect; using cru::ui::Window; using cru::ui::Alignment; using cru::ui::LayoutSideParams; @@ -20,6 +22,7 @@ using cru::ui::controls::TextBlock; using cru::ui::controls::ToggleButton; using cru::ui::controls::Button; using cru::ui::controls::TextBox; +using cru::ui::controls::ListItem; int APIENTRY wWinMain( HINSTANCE hInstance, @@ -117,7 +120,29 @@ int APIENTRY wWinMain( button->AddChild(TextBlock::Create(L"Show popup window parenting this.")); button->mouse_click_event.AddHandler([window](auto) { - Window::CreatePopup(window)->Show(); + const auto popup = Window::CreatePopup(window); + + auto create_menu_item = [](const String& text) -> ListItem* + { + return CreateWithLayout( + LayoutSideParams::Content(Alignment::Start), + LayoutSideParams::Content(Alignment::Start), + ControlList{ TextBlock::Create(text) } + ); + }; + + const auto menu = LinearLayout::Create(LinearLayout::Orientation::Vertical, ControlList{ + create_menu_item(L"copy"), + create_menu_item(L"cut"), + create_menu_item(L"paste") + }); + + popup->AddChild(menu); + + popup->Relayout(); + popup->SetClientSize(menu->GetSize()); + + popup->Show(); }); layout->AddChild(button); } -- cgit v1.2.3 From 9cf812f77a879d5394a9158ce290f9d7e858de7d Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 10 Nov 2018 22:11:05 +0800 Subject: Refactor layout invalidation system. --- src/main.cpp | 3 +-- src/ui/control.cpp | 2 +- src/ui/layout_base.cpp | 18 ------------------ src/ui/layout_base.hpp | 7 ------- src/ui/window.cpp | 24 +++++++++++++++++++++++- src/ui/window.hpp | 8 +++++++- 6 files changed, 32 insertions(+), 30 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 269da573..f5eb655a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -139,8 +139,7 @@ int APIENTRY wWinMain( popup->AddChild(menu); - popup->Relayout(); - popup->SetClientSize(menu->GetSize()); + popup->SetSizeFitContent(); popup->Show(); }); diff --git a/src/ui/control.cpp b/src/ui/control.cpp index ed904de1..2d09a382 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -238,7 +238,7 @@ namespace cru::ui void Control::InvalidateLayout() { if (const auto window = GetWindow()) - LayoutManager::GetInstance()->InvalidateWindowLayout(window); + window->WindowInvalidateLayout(); } void Control::Measure(const Size& available_size) diff --git a/src/ui/layout_base.cpp b/src/ui/layout_base.cpp index 5363c52b..40bb71b3 100644 --- a/src/ui/layout_base.cpp +++ b/src/ui/layout_base.cpp @@ -68,24 +68,6 @@ namespace cru::ui RefreshControlPositionCacheInternal(control, point); } - void LayoutManager::InvalidateWindowLayout(Window* window) - { - layout_invalid_windows_.insert(window); - - if (layout_invalid_windows_.size() == 1) - InvokeLater([this]() - { - this->RefreshInvalidWindowLayout(); - }); - } - - void LayoutManager::RefreshInvalidWindowLayout() - { - for (const auto window : layout_invalid_windows_) - window->Relayout(); - layout_invalid_windows_.clear(); - } - void LayoutManager::RefreshControlPositionCacheInternal(Control * control, const Point & parent_lefttop_absolute) { const auto position = control->GetPositionRelative(); diff --git a/src/ui/layout_base.hpp b/src/ui/layout_base.hpp index d8e4e2d1..7ae6f65c 100644 --- a/src/ui/layout_base.hpp +++ b/src/ui/layout_base.hpp @@ -132,13 +132,6 @@ namespace cru::ui //Refresh position cache of the control and its descendants immediately. static void RefreshControlPositionCache(Control* control); - - //*************** region: layout *************** - - void InvalidateWindowLayout(Window* window); - - void RefreshInvalidWindowLayout(); - private: static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute); diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 2737b70b..41104924 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -429,10 +429,32 @@ namespace cru::ui } + void Window::WindowInvalidateLayout() + { + if (is_layout_invalid_) + return; + + is_layout_invalid_ = true; + InvokeLater([this] + { + if (is_layout_invalid_) + Relayout(); + }); + } + void Window::Relayout() { OnMeasureCore(GetSize()); OnLayoutCore(Rect(Point::Zero(), GetSize())); + is_layout_invalid_ = false; + } + + void Window::SetSizeFitContent(const Size& max_size) + { + OnMeasureCore(max_size); + SetClientSize(GetDesiredSize()); + OnLayoutCore(Rect(Point::Zero(), GetSize())); + is_layout_invalid_ = false; } void Window::RefreshControlList() { @@ -597,7 +619,7 @@ namespace cru::ui 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(); + WindowInvalidateLayout(); } void Window::OnSetFocusInternal() diff --git a/src/ui/window.hpp b/src/ui/window.hpp index 963bff78..05b1a259 100644 --- a/src/ui/window.hpp +++ b/src/ui/window.hpp @@ -192,8 +192,12 @@ namespace cru::ui //*************** region: layout *************** + void WindowInvalidateLayout(); + void Relayout(); + void SetSizeFitContent(const Size& max_size = Size(1000, 1000)); + //*************** region: functions *************** //Refresh control list. @@ -319,7 +323,9 @@ namespace cru::ui Control* focus_control_ = this; // "focus_control_" can't be nullptr Control* mouse_capture_control_ = nullptr; - + + bool is_layout_invalid_ = false; + #ifdef CRU_DEBUG_LAYOUT bool debug_layout_ = false; #endif -- cgit v1.2.3 From b2eced8d9719eb00796c2674fc2c23ab0c9bbdbf Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 10 Nov 2018 22:28:40 +0800 Subject: ... --- src/main.cpp | 3 ++- src/ui/window.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++----------- src/ui/window.hpp | 12 +++++++----- 3 files changed, 55 insertions(+), 17 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index f5eb655a..19e821a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,7 +118,7 @@ int APIENTRY wWinMain( const auto button = Button::Create(); button->GetLayoutParams()->padding = Thickness(20, 5); button->AddChild(TextBlock::Create(L"Show popup window parenting this.")); - button->mouse_click_event.AddHandler([window](auto) + button->mouse_click_event.AddHandler([window, button](auto) { const auto popup = Window::CreatePopup(window); @@ -140,6 +140,7 @@ int APIENTRY wWinMain( popup->AddChild(menu); popup->SetSizeFitContent(); + popup->SetWindowPosition(window->PointToScreen(button->GetPositionAbsolute())); popup->Show(); }); diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 41104924..f8e6d4f3 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -98,6 +98,15 @@ namespace cru::ui ); } + inline POINT DipToPi(const Point& dip_point) + { + POINT result; + result.x = graph::DipToPixelX(dip_point.x); + result.y = graph::DipToPixelY(dip_point.y); + return result; + } + + namespace { Cursor::Ptr GetCursorInherit(Control* control) @@ -275,6 +284,41 @@ namespace cru::ui } } + void Window::SetWindowPosition(const Point& position) + { + if (IsWindowValid()) { + SetWindowPos( + hwnd_, nullptr, + graph::DipToPixelX(position.x), + graph::DipToPixelY(position.y), + 0, 0, + SWP_NOZORDER | SWP_NOSIZE + ); + } + } + + Point Window::PointToScreen(const Point& point) + { + if (!IsWindowValid()) + return Point::Zero(); + + auto p = DipToPi(point); + if (::ClientToScreen(GetWindowHandle(), &p) == 0) + throw Win32Error(::GetLastError(), "Failed transform point from window to screen."); + return PiToDip(p); + } + + Point Window::PointFromScreen(const Point& point) + { + if (!IsWindowValid()) + return Point::Zero(); + + auto p = DipToPi(point); + if (::ScreenToClient(GetWindowHandle(), &p) == 0) + throw Win32Error(::GetLastError(), "Failed transform point from screen to window."); + return PiToDip(p); + } + bool Window::HandleWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param, LRESULT & result) { if (!native_message_event.IsNoHandler()) @@ -444,14 +488,14 @@ namespace cru::ui void Window::Relayout() { - OnMeasureCore(GetSize()); + Measure(GetSize()); OnLayoutCore(Rect(Point::Zero(), GetSize())); is_layout_invalid_ = false; } void Window::SetSizeFitContent(const Size& max_size) { - OnMeasureCore(max_size); + Measure(max_size); SetClientSize(GetDesiredSize()); OnLayoutCore(Rect(Point::Zero(), GetSize())); is_layout_invalid_ = false; @@ -579,15 +623,6 @@ namespace cru::ui } } - Size Window::OnMeasureContent(const Size& available_size) - { - for (auto control: GetChildren()) - { - control->Measure(available_size); - } - return available_size; - } - void Window::OnDestroyInternal() { WindowManager::GetInstance()->UnregisterWindow(hwnd_); hwnd_ = nullptr; diff --git a/src/ui/window.hpp b/src/ui/window.hpp index 05b1a259..b2b8cde0 100644 --- a/src/ui/window.hpp +++ b/src/ui/window.hpp @@ -162,6 +162,13 @@ namespace cru::ui //The lefttop of the rect is relative to screen lefttop. void SetWindowRect(const Rect& rect); + //Set the lefttop of the window relative to screen. + void SetWindowPosition(const Point& position); + + Point PointToScreen(const Point& point); + + Point PointFromScreen(const Point& point); + //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. @@ -254,11 +261,6 @@ namespace cru::ui void SetCursorInternal(HCURSOR cursor); - //*************** region: layout *************** - - Size OnMeasureContent(const Size& available_size) override; - - //*************** region: native messages *************** void OnDestroyInternal(); -- cgit v1.2.3