aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/ui/components/Menu.hpp15
-rw-r--r--include/cru/ui/controls/Button.hpp4
-rw-r--r--include/cru/ui/controls/LayoutControl.hpp2
-rw-r--r--include/cru/ui/controls/TextHostControlService.hpp20
-rw-r--r--src/ui/components/Menu.cpp21
-rw-r--r--src/ui/controls/LayoutControl.cpp6
-rw-r--r--src/ui/controls/TextHostControlService.cpp36
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