aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-11-20 21:25:29 +0800
committercrupest <crupest@outlook.com>2021-11-20 21:25:29 +0800
commit1a53ed0791d9793ed8030d3a44e833e5e7c4542b (patch)
tree28aedaabee675b192e414489122349ad4985a31b
parenta9da4c10459e3c45115c8a42e771b00cb1caeab7 (diff)
downloadcru-1a53ed0791d9793ed8030d3a44e833e5e7c4542b.tar.gz
cru-1a53ed0791d9793ed8030d3a44e833e5e7c4542b.tar.bz2
cru-1a53ed0791d9793ed8030d3a44e833e5e7c4542b.zip
...
-rw-r--r--demos/main/main.cpp13
-rw-r--r--include/cru/ui/components/Menu.hpp29
-rw-r--r--include/cru/ui/controls/Popup.hpp8
-rw-r--r--include/cru/ui/host/WindowHost.hpp5
-rw-r--r--src/osx/graphics/quartz/TextLayout.cpp2
-rw-r--r--src/osx/gui/Window.mm17
-rw-r--r--src/ui/components/Menu.cpp37
-rw-r--r--src/ui/host/WindowHost.cpp14
8 files changed, 113 insertions, 12 deletions
diff --git a/demos/main/main.cpp b/demos/main/main.cpp
index 9a28ade8..1a92e5ff 100644
--- a/demos/main/main.cpp
+++ b/demos/main/main.cpp
@@ -1,13 +1,16 @@
+#include <memory>
#include "cru/platform/HeapDebug.hpp"
#include "cru/platform/bootstrap/Bootstrap.hpp"
#include "cru/platform/gui/UiApplication.hpp"
#include "cru/platform/gui/Window.hpp"
#include "cru/ui/Base.hpp"
+#include "cru/ui/components/Menu.hpp"
#include "cru/ui/controls/Button.hpp"
#include "cru/ui/controls/FlexLayout.hpp"
#include "cru/ui/controls/TextBlock.hpp"
#include "cru/ui/controls/TextBox.hpp"
#include "cru/ui/controls/Window.hpp"
+#include "cru/ui/events/UiEvent.hpp"
#include "cru/ui/host/WindowHost.hpp"
using cru::platform::gui::IUiApplication;
@@ -40,6 +43,16 @@ int main() {
const auto text_box = TextBox::Create();
flex_layout->AddChild(text_box, 2);
+ auto popup_menu = std::make_unique<cru::ui::components::PopupMenu>(window);
+ popup_menu->GetMenu()->AddTextItem(u"Item 1");
+ popup_menu->GetMenu()->AddTextItem(u"Item 2000");
+
+ window->MouseDownEvent()->Bubble()->AddHandler(
+ [window, &popup_menu](cru::ui::event::MouseButtonEventArgs& e) {
+ popup_menu->SetPosition(e.GetPoint());
+ popup_menu->Show();
+ });
+
window->Show();
return application->Run();
diff --git a/include/cru/ui/components/Menu.hpp b/include/cru/ui/components/Menu.hpp
index d60d38eb..96b21173 100644
--- a/include/cru/ui/components/Menu.hpp
+++ b/include/cru/ui/components/Menu.hpp
@@ -4,9 +4,9 @@
#include "cru/ui/controls/Button.hpp"
#include "cru/ui/controls/Control.hpp"
#include "cru/ui/controls/FlexLayout.hpp"
+#include "cru/ui/controls/Popup.hpp"
#include "cru/ui/controls/TextBlock.hpp"
-#include <string>
#include <vector>
namespace cru::ui::components {
@@ -40,6 +40,8 @@ class Menu : public Component {
~Menu();
public:
+ controls::Control* GetRootControl() override { return container_; }
+
gsl::index GetItemCount() const {
return static_cast<gsl::index>(items_.size());
}
@@ -57,4 +59,29 @@ class Menu : public Component {
controls::FlexLayout* container_;
std::vector<Component*> items_;
};
+
+class PopupMenu : public Component {
+ public:
+ explicit PopupMenu(controls::Control* attached_control = nullptr);
+
+ CRU_DELETE_COPY(PopupMenu)
+ CRU_DELETE_MOVE(PopupMenu)
+
+ ~PopupMenu();
+
+ public:
+ controls::Control* GetRootControl() override;
+
+ controls::Popup* GetPopup() { return popup_; }
+ Menu* GetMenu() { return menu_; }
+
+ void SetPosition(const Point& position);
+ void Show();
+
+ private:
+ controls::Control* attached_control_;
+
+ controls::Popup* popup_;
+ Menu* menu_;
+};
} // namespace cru::ui::components
diff --git a/include/cru/ui/controls/Popup.hpp b/include/cru/ui/controls/Popup.hpp
index 321bbbc6..cd5e1813 100644
--- a/include/cru/ui/controls/Popup.hpp
+++ b/include/cru/ui/controls/Popup.hpp
@@ -8,6 +8,12 @@
namespace cru::ui::controls {
class Popup : public RootControl {
public:
+ static constexpr StringView kControlType = u"Popup";
+
+ static Popup* Create(Control* attached_control = nullptr) {
+ return new Popup(attached_control);
+ }
+
explicit Popup(Control* attached_control = nullptr);
CRU_DELETE_COPY(Popup)
@@ -15,6 +21,8 @@ class Popup : public RootControl {
~Popup() override;
+ String GetControlType() const override { return kControlType.ToString(); }
+
protected:
gsl::not_null<platform::gui::INativeWindow*> CreateNativeWindow(
gsl::not_null<host::WindowHost*> host,
diff --git a/include/cru/ui/host/WindowHost.hpp b/include/cru/ui/host/WindowHost.hpp
index 258b0c4c..f3caeeef 100644
--- a/include/cru/ui/host/WindowHost.hpp
+++ b/include/cru/ui/host/WindowHost.hpp
@@ -59,7 +59,8 @@ class WindowHost : public Object {
}
void Relayout();
- void Relayout(const Size& available_size);
+ void RelayoutWithSize(const Size& available_size = Size::Infinate(),
+ bool set_window_size_to_fit_content = false);
void Repaint();
@@ -173,7 +174,7 @@ class WindowHost : public Object {
controls::Control* mouse_captured_control_ = nullptr;
- bool layout_prefer_to_fill_window_ = true;
+ bool layout_prefer_to_fill_window_ = false;
Event<platform::gui::INativeWindow*> native_window_change_event_;
diff --git a/src/osx/graphics/quartz/TextLayout.cpp b/src/osx/graphics/quartz/TextLayout.cpp
index a5607854..c3a138f2 100644
--- a/src/osx/graphics/quartz/TextLayout.cpp
+++ b/src/osx/graphics/quartz/TextLayout.cpp
@@ -115,6 +115,8 @@ void OsxCTTextLayout::SetEditMode(bool enable) {
}
Rect OsxCTTextLayout::GetTextBounds(bool includingTrailingSpace) {
+ if (text_.empty() && edit_mode_) return Rect(0, 0, 0, font_->GetFontSize());
+
auto result = DoGetTextBoundsIncludingEmptyLines(includingTrailingSpace);
return Rect(0, 0, result.size.width, result.size.height);
}
diff --git a/src/osx/gui/Window.mm b/src/osx/gui/Window.mm
index 0112fd43..9f0d9742 100644
--- a/src/osx/gui/Window.mm
+++ b/src/osx/gui/Window.mm
@@ -71,7 +71,13 @@ void OsxWindowPrivate::OnWindowDidResize() {
[view addTrackingArea:tracking_area];
CGLayerRelease(draw_layer_);
- draw_layer_ = CGLayerCreateWithContext(nullptr, rect.size, nullptr);
+
+ // If size is 0 then create layer will fail.
+ auto s = rect.size;
+ if (s.width == 0) s.width = 1;
+ if (s.height == 0) s.height = 1;
+
+ draw_layer_ = CGLayerCreateWithContext(nullptr, s, nullptr);
Ensures(draw_layer_);
resize_event_.Raise(osx_window_->GetClientSize());
@@ -252,8 +258,13 @@ void OsxWindow::CreateWindow() {
[p_->window_ setContentView:content_view];
- p_->draw_layer_ = CGLayerCreateWithContext(
- nullptr, cru::platform::graphics::osx::quartz::Convert(p_->content_rect_.GetSize()), nullptr);
+ // If size is 0 then create layer will fail.
+ auto s = p_->content_rect_.GetSize();
+ if (s.width == 0) s.width = 1;
+ if (s.height == 0) s.height = 1;
+
+ p_->draw_layer_ =
+ CGLayerCreateWithContext(nullptr, cru::platform::graphics::osx::quartz::Convert(s), nullptr);
Ensures(p_->draw_layer_);
RequestRepaint();
diff --git a/src/ui/components/Menu.cpp b/src/ui/components/Menu.cpp
index afd1ab71..af54c46c 100644
--- a/src/ui/components/Menu.cpp
+++ b/src/ui/components/Menu.cpp
@@ -1,12 +1,12 @@
#include "cru/ui/components/Menu.hpp"
#include "cru/ui/UiManager.hpp"
#include "cru/ui/controls/Button.hpp"
+#include "cru/ui/controls/Control.hpp"
#include "cru/ui/controls/FlexLayout.hpp"
#include "cru/ui/controls/TextBlock.hpp"
+#include "cru/ui/host/WindowHost.hpp"
#include "cru/ui/style/StyleRuleSet.hpp"
-#include <string>
-
namespace cru::ui::components {
MenuItem::MenuItem() {
container_ = controls::Button::Create();
@@ -56,4 +56,37 @@ Component* Menu::RemoveItem(gsl::index index) {
return item;
}
+
+void Menu::AddTextItem(String text, gsl::index index) {
+ MenuItem* item = new MenuItem(std::move(text));
+ AddItem(item, index);
+}
+
+PopupMenu::PopupMenu(controls::Control* attached_control)
+ : attached_control_(attached_control) {
+ popup_ = controls::Popup::Create(attached_control);
+
+ menu_ = new Menu();
+
+ popup_->AddChild(menu_->GetRootControl(), 0);
+}
+
+PopupMenu::~PopupMenu() {
+ delete menu_;
+
+ if (!popup_->GetWindowHost()) {
+ delete popup_;
+ }
+}
+
+controls::Control* PopupMenu::GetRootControl() { return popup_; }
+
+void PopupMenu::SetPosition(const Point& position) {
+ popup_->SetRect(Rect{position, {}});
+}
+
+void PopupMenu::Show() {
+ popup_->GetWindowHost()->RelayoutWithSize(Size::Infinate(), true);
+ popup_->Show();
+}
} // namespace cru::ui::components
diff --git a/src/ui/host/WindowHost.cpp b/src/ui/host/WindowHost.cpp
index f60e2809..d26b43ab 100644
--- a/src/ui/host/WindowHost.cpp
+++ b/src/ui/host/WindowHost.cpp
@@ -180,18 +180,24 @@ void WindowHost::SetLayoutPreferToFillWindow(bool value) {
void WindowHost::Relayout() {
const auto available_size =
- native_window_ ? native_window_->GetClientSize()
- : Size{100, 100}; // a reasonable assumed size
- Relayout(available_size);
+ native_window_ ? native_window_->GetClientSize() : Size::Infinate();
+ RelayoutWithSize(available_size);
}
-void WindowHost::Relayout(const Size& available_size) {
+void WindowHost::RelayoutWithSize(const Size& available_size,
+ bool set_window_size_to_fit_content) {
root_render_object_->Measure(
render::MeasureRequirement{available_size,
IsLayoutPreferToFillWindow()
? render::MeasureSize(available_size)
: render::MeasureSize::NotSpecified()},
render::MeasureSize::NotSpecified());
+
+ if (set_window_size_to_fit_content) {
+ auto rect = GetWindowRect();
+ SetWindowRect({rect.GetLeftTop(), root_render_object_->GetSize()});
+ }
+
root_render_object_->Layout(Point{});
for (auto& action : after_layout_stable_action_) action();
after_layout_event_.Raise(AfterLayoutEventArgs{});