diff options
author | crupest <crupest@outlook.com> | 2021-12-04 18:06:43 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-12-04 18:06:43 +0800 |
commit | 942f1d34c48e61a853db745cd68e46db13266a5c (patch) | |
tree | fdb859933dbb302404391ed686bae8c7126c96ee | |
parent | 2317061516b0bd0002467acbead3120cbe49a6c5 (diff) | |
download | cru-942f1d34c48e61a853db745cd68e46db13266a5c.tar.gz cru-942f1d34c48e61a853db745cd68e46db13266a5c.tar.bz2 cru-942f1d34c48e61a853db745cd68e46db13266a5c.zip |
...
-rw-r--r-- | include/cru/ui/components/Menu.hpp | 15 | ||||
-rw-r--r-- | include/cru/ui/controls/Button.hpp | 4 | ||||
-rw-r--r-- | include/cru/ui/controls/LayoutControl.hpp | 2 | ||||
-rw-r--r-- | include/cru/ui/controls/TextHostControlService.hpp | 20 | ||||
-rw-r--r-- | src/ui/components/Menu.cpp | 21 | ||||
-rw-r--r-- | src/ui/controls/LayoutControl.cpp | 6 | ||||
-rw-r--r-- | src/ui/controls/TextHostControlService.cpp | 36 |
7 files changed, 100 insertions, 4 deletions
diff --git a/include/cru/ui/components/Menu.hpp b/include/cru/ui/components/Menu.hpp index 96b21173..a72c0313 100644 --- a/include/cru/ui/components/Menu.hpp +++ b/include/cru/ui/components/Menu.hpp @@ -7,6 +7,7 @@ #include "cru/ui/controls/Popup.hpp" #include "cru/ui/controls/TextBlock.hpp" +#include <functional> #include <vector> namespace cru::ui::components { @@ -25,9 +26,14 @@ class MenuItem : public Component { void SetText(String text); + void SetOnClick(std::function<void()> on_click) { + on_click_ = std::move(on_click); + } + private: controls::Button* container_; controls::TextBlock* text_; + std::function<void()> on_click_; }; class Menu : public Component { @@ -49,11 +55,13 @@ class Menu : public Component { void AddItem(Component* component) { AddItem(component, GetItemCount()); } void AddItem(Component* component, gsl::index index); Component* RemoveItem(gsl::index index); + void ClearItems(); - void AddTextItem(String text) { - AddTextItem(std::move(text), GetItemCount()); + void AddTextItem(String text, std::function<void()> on_click) { + AddTextItem(std::move(text), GetItemCount(), std::move(on_click)); } - void AddTextItem(String text, gsl::index index); + void AddTextItem(String text, gsl::index index, + std::function<void()> on_click); private: controls::FlexLayout* container_; @@ -77,6 +85,7 @@ class PopupMenu : public Component { void SetPosition(const Point& position); void Show(); + void Close(); private: controls::Control* attached_control_; diff --git a/include/cru/ui/controls/Button.hpp b/include/cru/ui/controls/Button.hpp index 9e324c62..e0335a39 100644 --- a/include/cru/ui/controls/Button.hpp +++ b/include/cru/ui/controls/Button.hpp @@ -39,6 +39,10 @@ class Button : public ContentControl, return click_detector_.StateChangeEvent(); } + IEvent<helper::ClickEventArgs>* ClickEvent() { + return click_detector_.ClickEvent(); + } + void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) override; private: diff --git a/include/cru/ui/controls/LayoutControl.hpp b/include/cru/ui/controls/LayoutControl.hpp index 106dd94d..381df1df 100644 --- a/include/cru/ui/controls/LayoutControl.hpp +++ b/include/cru/ui/controls/LayoutControl.hpp @@ -18,6 +18,8 @@ class LayoutControl : public Control { using Control::AddChild; using Control::RemoveChild; + void ClearChildren(); + protected: // If container render object is not null. Render object of added or removed // child control will automatically sync to the container render object. diff --git a/include/cru/ui/controls/TextHostControlService.hpp b/include/cru/ui/controls/TextHostControlService.hpp index 6ebe2a27..5216827b 100644 --- a/include/cru/ui/controls/TextHostControlService.hpp +++ b/include/cru/ui/controls/TextHostControlService.hpp @@ -15,6 +15,10 @@ class TextRenderObject; class ScrollRenderObject; } // namespace cru::ui::render +namespace cru::ui::components { +class PopupMenu; +} + namespace cru::ui::controls { constexpr int k_default_caret_blink_duration = 500; @@ -86,6 +90,9 @@ class TextHostControlService : public Object { bool IsEditable() { return this->editable_; } void SetEditable(bool editable); + bool IsContextMenuEnabled() { return this->context_menu_enabled_; } + void SetContextMenuEnabled(bool enabled); + bool IsMultiLine() { return this->multi_line_; } // If text contains line feed characters, it will be converted to space. void SetMultiLine(bool multi_line); @@ -169,6 +176,15 @@ class TextHostControlService : public Object { void SetUpShortcuts(); + enum ContextMenuItem : unsigned { + kSelectAll = 0b1, + kCut = 0b10, + kCopy = 0b100, + kPaste = 0b1000 + }; + + void OpenContextMenu(const Point& position, ContextMenuItem items); + private: gsl::not_null<Control*> control_; gsl::not_null<ITextHostControl*> text_host_control_; @@ -182,6 +198,7 @@ class TextHostControlService : public Object { bool enable_ = false; bool editable_ = false; bool multi_line_ = false; + bool context_menu_enabled_ = true; bool caret_visible_ = false; platform::gui::TimerAutoCanceler caret_timer_canceler_; @@ -191,5 +208,8 @@ class TextHostControlService : public Object { // true if left mouse is down and selecting bool mouse_move_selecting_ = false; + + bool context_menu_dirty_ = true; + std::unique_ptr<components::PopupMenu> context_menu_; }; } // namespace cru::ui::controls diff --git a/src/ui/components/Menu.cpp b/src/ui/components/Menu.cpp index c3359cf9..60364f13 100644 --- a/src/ui/components/Menu.cpp +++ b/src/ui/components/Menu.cpp @@ -1,10 +1,12 @@ #include "cru/ui/components/Menu.hpp" +#include <functional> #include "cru/platform/gui/Window.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/helper/ClickDetector.hpp" #include "cru/ui/host/WindowHost.hpp" #include "cru/ui/style/StyleRuleSet.hpp" @@ -15,6 +17,9 @@ MenuItem::MenuItem() { container_->SetChild(text_); container_->GetStyleRuleSet()->SetParent( &UiManager::GetInstance()->GetThemeResources()->menu_item_style); + container_->ClickEvent()->AddHandler([this](const helper::ClickEventArgs&) { + if (this->on_click_) this->on_click_(); + }); } MenuItem::MenuItem(String text) : MenuItem() { SetText(std::move(text)); } @@ -61,8 +66,20 @@ Component* Menu::RemoveItem(gsl::index index) { return item; } -void Menu::AddTextItem(String text, gsl::index index) { +void Menu::ClearItems() { + for (auto item : items_) { + delete item; + } + + items_.clear(); + + container_->ClearChildren(); +} + +void Menu::AddTextItem(String text, gsl::index index, + std::function<void()> on_click) { MenuItem* item = new MenuItem(std::move(text)); + item->SetOnClick(std::move(on_click)); AddItem(item, index); } @@ -94,4 +111,6 @@ void PopupMenu::Show() { popup_->GetWindowHost()->GetNativeWindow()->SetVisibility( platform::gui::WindowVisibilityType::Show); } + +void PopupMenu::Close() { popup_->GetWindowHost()->GetNativeWindow()->Close(); } } // namespace cru::ui::components diff --git a/src/ui/controls/LayoutControl.cpp b/src/ui/controls/LayoutControl.cpp index 5954853e..e5a38445 100644 --- a/src/ui/controls/LayoutControl.cpp +++ b/src/ui/controls/LayoutControl.cpp @@ -3,6 +3,12 @@ #include "cru/ui/render/RenderObject.hpp" namespace cru::ui::controls { +void LayoutControl::ClearChildren() { + while (GetChildren().size() > 0) { + RemoveChild(0); + } +} + void LayoutControl::OnAddChild(Control* child, Index position) { if (container_render_object_ != nullptr) { container_render_object_->AddChild(child->GetRenderObject(), position); diff --git a/src/ui/controls/TextHostControlService.cpp b/src/ui/controls/TextHostControlService.cpp index b250ccae..90896632 100644 --- a/src/ui/controls/TextHostControlService.cpp +++ b/src/ui/controls/TextHostControlService.cpp @@ -14,12 +14,15 @@ #include "cru/platform/gui/Window.hpp" #include "cru/ui/Base.hpp" #include "cru/ui/DebugFlags.hpp" +#include "cru/ui/components/Menu.hpp" #include "cru/ui/events/UiEvent.hpp" #include "cru/ui/helper/ShortcutHub.hpp" #include "cru/ui/host/WindowHost.hpp" #include "cru/ui/render/ScrollRenderObject.hpp" #include "cru/ui/render/TextRenderObject.hpp" +#include <memory> + namespace cru::ui::controls { TextControlMovePattern TextControlMovePattern::kLeft( helper::ShortcutKeyBind(platform::gui::KeyCode::Left), @@ -119,6 +122,8 @@ std::vector<TextControlMovePattern> TextControlMovePattern::kDefaultPatterns = { TextHostControlService::TextHostControlService(gsl::not_null<Control*> control) : control_(control), text_host_control_(dynamic_cast<ITextHostControl*>(control.get())) { + context_menu_ = std::make_unique<components::PopupMenu>(); + SetUpShortcuts(); SetupOneHandler(&Control::MouseMoveEvent, @@ -152,6 +157,16 @@ void TextHostControlService::SetEnabled(bool enable) { } } +void TextHostControlService::SetContextMenuEnabled(bool enabled) { + if (context_menu_enabled_ == enabled) return; + + context_menu_enabled_ = enabled; + + if (!context_menu_enabled_ && context_menu_) { + context_menu_->Close(); + } +} + void TextHostControlService::SetEditable(bool editable) { this->editable_ = editable; if (!editable) CancelComposition(); @@ -594,4 +609,25 @@ void TextHostControlService::SetUpShortcuts() { }); } } + +void TextHostControlService::OpenContextMenu(const Point& position, + ContextMenuItem items) { + context_menu_ = std::make_unique<components::PopupMenu>(); + auto menu = context_menu_->GetMenu(); + if (items & ContextMenuItem::kSelectAll) { + menu->AddTextItem(u"Select All", [this] { this->SelectAll(); }); + } + if (items & ContextMenuItem::kCopy) { + menu->AddTextItem(u"Copy", [this] { this->Copy(); }); + } + if (items & ContextMenuItem::kCut) { + menu->AddTextItem(u"Cut", [this] { this->Cut(); }); + } + if (items & ContextMenuItem::kPaste) { + menu->AddTextItem(u"Paste", [this] { this->Paste(); }); + } + context_menu_->SetPosition(position); + context_menu_->Show(); +} + } // namespace cru::ui::controls |