aboutsummaryrefslogtreecommitdiff
path: root/include/cru/ui/controls
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-12-25 15:38:18 +0800
committercrupest <crupest@outlook.com>2020-12-25 15:38:18 +0800
commitda7ad0ff5c5b158be69c6cf9a2c8e9fc9ef2b3cb (patch)
tree9d58ba66119f5a1f6efa5a9b75c22e0453993a07 /include/cru/ui/controls
parenta14704fbd9b9fb377b7009a9fbe641a9b8d0fdfb (diff)
downloadcru-da7ad0ff5c5b158be69c6cf9a2c8e9fc9ef2b3cb.tar.gz
cru-da7ad0ff5c5b158be69c6cf9a2c8e9fc9ef2b3cb.tar.bz2
cru-da7ad0ff5c5b158be69c6cf9a2c8e9fc9ef2b3cb.zip
...
Diffstat (limited to 'include/cru/ui/controls')
-rw-r--r--include/cru/ui/controls/TextBlock.hpp15
-rw-r--r--include/cru/ui/controls/TextBox.hpp12
-rw-r--r--include/cru/ui/controls/TextHostControlService.hpp141
3 files changed, 157 insertions, 11 deletions
diff --git a/include/cru/ui/controls/TextBlock.hpp b/include/cru/ui/controls/TextBlock.hpp
index 66ebe476..be31816c 100644
--- a/include/cru/ui/controls/TextBlock.hpp
+++ b/include/cru/ui/controls/TextBlock.hpp
@@ -1,11 +1,10 @@
#pragma once
#include "NoChildControl.hpp"
-namespace cru::ui::controls {
-template <typename TControl>
-class TextControlService;
+#include "TextHostControlService.hpp"
-class TextBlock : public NoChildControl {
+namespace cru::ui::controls {
+class TextBlock : public NoChildControl, public virtual ITextHostControl {
public:
static constexpr std::u16string_view control_type = u"TextBlock";
@@ -32,12 +31,14 @@ class TextBlock : public NoChildControl {
bool IsSelectable() const;
void SetSelectable(bool value);
- gsl::not_null<render::TextRenderObject*> GetTextRenderObject();
- render::ScrollRenderObject* GetScrollRenderObject() { return nullptr; }
+ gsl::not_null<render::TextRenderObject*> GetTextRenderObject() override;
+ render::ScrollRenderObject* GetScrollRenderObject() override {
+ return nullptr;
+ }
private:
std::unique_ptr<render::TextRenderObject> text_render_object_;
- std::unique_ptr<TextControlService<TextBlock>> service_;
+ std::unique_ptr<TextHostControlService> service_;
};
} // namespace cru::ui::controls
diff --git a/include/cru/ui/controls/TextBox.hpp b/include/cru/ui/controls/TextBox.hpp
index 75e7cb65..5693b315 100644
--- a/include/cru/ui/controls/TextBox.hpp
+++ b/include/cru/ui/controls/TextBox.hpp
@@ -1,6 +1,8 @@
#pragma once
#include "NoChildControl.hpp"
+
#include "IBorderControl.hpp"
+#include "TextHostControlService.hpp"
#include <memory>
@@ -8,7 +10,9 @@ namespace cru::ui::controls {
template <typename TControl>
class TextControlService;
-class TextBox : public NoChildControl, public IBorderControl {
+class TextBox : public NoChildControl,
+ public virtual IBorderControl,
+ public virtual ITextHostControl {
public:
static constexpr std::u16string_view control_type = u"TextBox";
@@ -27,8 +31,8 @@ class TextBox : public NoChildControl, public IBorderControl {
render::RenderObject* GetRenderObject() const override;
- gsl::not_null<render::TextRenderObject*> GetTextRenderObject();
- render::ScrollRenderObject* GetScrollRenderObject();
+ gsl::not_null<render::TextRenderObject*> GetTextRenderObject() override;
+ render::ScrollRenderObject* GetScrollRenderObject() override;
void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) override;
@@ -37,6 +41,6 @@ class TextBox : public NoChildControl, public IBorderControl {
std::unique_ptr<render::ScrollRenderObject> scroll_render_object_;
std::unique_ptr<render::TextRenderObject> text_render_object_;
- std::unique_ptr<TextControlService<TextBox>> service_;
+ std::unique_ptr<TextHostControlService> service_;
};
} // namespace cru::ui::controls
diff --git a/include/cru/ui/controls/TextHostControlService.hpp b/include/cru/ui/controls/TextHostControlService.hpp
new file mode 100644
index 00000000..0bea52c8
--- /dev/null
+++ b/include/cru/ui/controls/TextHostControlService.hpp
@@ -0,0 +1,141 @@
+#pragma once
+#include "Base.hpp"
+
+#include "cru/platform/gui/InputMethod.hpp"
+#include "cru/platform/gui/UiApplication.hpp"
+#include "cru/ui/controls/Control.hpp"
+#include "cru/ui/helper/ShortcutHub.hpp"
+
+#include <functional>
+#include <string>
+
+namespace cru::ui::render {
+class TextRenderObject;
+class ScrollRenderObject;
+} // namespace cru::ui::render
+
+namespace cru::ui::controls {
+constexpr int k_default_caret_blink_duration = 500;
+
+struct ITextHostControl : virtual Interface {
+ virtual gsl::not_null<render::TextRenderObject*> GetTextRenderObject() = 0;
+ // May return nullptr.
+ virtual render::ScrollRenderObject* GetScrollRenderObject() = 0;
+};
+
+class TextHostControlService : public Object {
+ CRU_DEFINE_CLASS_LOG_TAG(u"cru::ui::controls::TextControlService")
+
+ public:
+ TextHostControlService(gsl::not_null<Control*> control);
+
+ CRU_DELETE_COPY(TextHostControlService)
+ CRU_DELETE_MOVE(TextHostControlService)
+
+ ~TextHostControlService() = default;
+
+ public:
+ bool IsEnabled() { return enable_; }
+ void SetEnabled(bool enable);
+
+ bool IsEditable() { return this->editable_; }
+ void SetEditable(bool editable);
+
+ std::u16string GetText() { return this->text_; }
+ std::u16string_view GetTextView() { return this->text_; }
+ void SetText(std::u16string text, bool stop_composition = false);
+
+ void InsertText(gsl::index position, std::u16string_view text,
+ bool stop_composition = false);
+ void DeleteChar(gsl::index position, bool stop_composition = false);
+
+ // Return the position of deleted character.
+ gsl::index DeleteCharPrevious(gsl::index position,
+ bool stop_composition = false);
+ void DeleteText(TextRange range, bool stop_composition = false);
+
+ void CancelComposition();
+
+ std::optional<platform::gui::CompositionText> GetCompositionInfo();
+
+ bool IsCaretVisible() { return caret_visible_; }
+ void SetCaretVisible(bool visible);
+
+ int GetCaretBlinkDuration() { return caret_blink_duration_; }
+ void SetCaretBlinkDuration(int milliseconds);
+
+ gsl::index GetCaretPosition() { return selection_.GetEnd(); }
+ TextRange GetSelection() { return selection_; }
+
+ void SetSelection(gsl::index caret_position);
+ void SetSelection(TextRange selection, bool scroll_to_caret = true);
+
+ void DeleteSelectedText();
+
+ // If some text is selected, then they are deleted first. Then insert text
+ // into caret position.
+ void ReplaceSelectedText(std::u16string_view text);
+
+ void ScrollToCaret();
+
+ private:
+ gsl::not_null<render::TextRenderObject*> GetTextRenderObject();
+ render::ScrollRenderObject* GetScrollRenderObject();
+
+ // May return nullptr.
+ platform::gui::IInputMethodContext* GetInputMethodContext();
+
+ void CoerceSelection();
+
+ void SetupCaret();
+ void TearDownCaret();
+
+ void SyncTextRenderObject();
+
+ void StartSelection(Index start);
+ void UpdateSelection(Index new_end);
+ void AbortSelection();
+
+ void UpdateInputMethodPosition();
+
+ template <typename TArgs>
+ void SetupOneHandler(event::RoutedEvent<TArgs>* (Control::*event)(),
+ void (TextHostControlService::*handler)(
+ typename event::RoutedEvent<TArgs>::EventArgs)) {
+ this->event_guard_ += (this->control_->*event)()->Direct()->AddHandler(
+ std::bind(handler, this, std::placeholders::_1));
+ }
+
+ void SetUpHandlers();
+ void TearDownHandlers();
+
+ void MouseMoveHandler(event::MouseEventArgs& args);
+ void MouseDownHandler(event::MouseButtonEventArgs& args);
+ void MouseUpHandler(event::MouseButtonEventArgs& args);
+ void KeyDownHandler(event::KeyEventArgs& args);
+ void GainFocusHandler(event::FocusChangeEventArgs& args);
+ void LoseFocusHandler(event::FocusChangeEventArgs& args);
+
+ private:
+ gsl::not_null<Control*> control_;
+ gsl::not_null<ITextHostControl*> text_host_control_;
+
+ EventRevokerListGuard event_guard_;
+ EventRevokerListGuard input_method_context_event_guard_;
+
+ std::u16string text_;
+ TextRange selection_;
+
+ bool enable_ = false;
+ bool editable_ = false;
+
+ bool caret_visible_ = false;
+ platform::gui::TimerAutoCanceler caret_timer_canceler_;
+ int caret_blink_duration_ = k_default_caret_blink_duration;
+
+ helper::ShortcutHub shortcut_hub_;
+
+ // true if left mouse is down and selecting
+ bool mouse_move_selecting_;
+};
+} // namespace cru::ui::controls