diff options
Diffstat (limited to 'include/cru/ui/controls')
| -rw-r--r-- | include/cru/ui/controls/Base.hpp | 22 | ||||
| -rw-r--r-- | include/cru/ui/controls/Button.hpp | 29 | ||||
| -rw-r--r-- | include/cru/ui/controls/Container.hpp | 5 | ||||
| -rw-r--r-- | include/cru/ui/controls/ContentControl.hpp | 38 | ||||
| -rw-r--r-- | include/cru/ui/controls/Control.hpp | 157 | ||||
| -rw-r--r-- | include/cru/ui/controls/FlexLayout.hpp | 9 | ||||
| -rw-r--r-- | include/cru/ui/controls/IBorderControl.hpp | 10 | ||||
| -rw-r--r-- | include/cru/ui/controls/IClickableControl.hpp | 12 | ||||
| -rw-r--r-- | include/cru/ui/controls/LayoutControl.hpp | 35 | ||||
| -rw-r--r-- | include/cru/ui/controls/NoChildControl.hpp | 20 | ||||
| -rw-r--r-- | include/cru/ui/controls/Popup.hpp | 24 | ||||
| -rw-r--r-- | include/cru/ui/controls/RootControl.hpp | 45 | ||||
| -rw-r--r-- | include/cru/ui/controls/StackLayout.hpp | 6 | ||||
| -rw-r--r-- | include/cru/ui/controls/TextBlock.hpp | 23 | ||||
| -rw-r--r-- | include/cru/ui/controls/TextBox.hpp | 27 | ||||
| -rw-r--r-- | include/cru/ui/controls/TextHostControlService.hpp | 137 | ||||
| -rw-r--r-- | include/cru/ui/controls/Window.hpp | 32 | 
17 files changed, 560 insertions, 71 deletions
| diff --git a/include/cru/ui/controls/Base.hpp b/include/cru/ui/controls/Base.hpp index b550601b..7c85cdb2 100644 --- a/include/cru/ui/controls/Base.hpp +++ b/include/cru/ui/controls/Base.hpp @@ -1,24 +1,4 @@  #pragma once  #include "../Base.hpp" -namespace cru::ui::controls { -using ButtonStateStyle = BorderStyle; - -struct ButtonStyle { -  // corresponds to ClickState::None -  ButtonStateStyle normal; -  // corresponds to ClickState::Hover -  ButtonStateStyle hover; -  // corresponds to ClickState::Press -  ButtonStateStyle press; -  // corresponds to ClickState::PressInactive -  ButtonStateStyle press_cancel; -}; - -struct TextBoxBorderStyle { -  BorderStyle normal; -  BorderStyle hover; -  BorderStyle focus; -  BorderStyle focus_hover; -}; -}  // namespace cru::ui::controls +namespace cru::ui::controls {}  // namespace cru::ui::controls diff --git a/include/cru/ui/controls/Button.hpp b/include/cru/ui/controls/Button.hpp index a4f727d6..1c9b1216 100644 --- a/include/cru/ui/controls/Button.hpp +++ b/include/cru/ui/controls/Button.hpp @@ -1,11 +1,16 @@  #pragma once -#include "../ContentControl.hpp" -#include "Base.hpp" +#include "ContentControl.hpp" -#include "../ClickDetector.hpp" +#include "../helper/ClickDetector.hpp" +#include "IBorderControl.hpp" +#include "IClickableControl.hpp" +#include "cru/common/Event.hpp" +#include "cru/ui/style/ApplyBorderStyleInfo.hpp"  namespace cru::ui::controls { -class Button : public ContentControl { +class Button : public ContentControl, +               public virtual IClickableControl, +               public virtual IBorderControl {   public:    static constexpr std::u16string_view control_type = u"Button"; @@ -26,17 +31,19 @@ class Button : public ContentControl {    render::RenderObject* GetRenderObject() const override;   public: -  const ButtonStyle& GetStyle() const { return style_; } -  void SetStyle(ButtonStyle style); +  helper::ClickState GetClickState() override { +    return click_detector_.GetState(); +  } - protected: -  void OnChildChanged(Control* old_child, Control* new_child) override; +  IEvent<helper::ClickState>* ClickStateChangeEvent() override { +    return click_detector_.StateChangeEvent(); +  } + +  void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) override;   private:    std::unique_ptr<render::BorderRenderObject> render_object_{}; -  ButtonStyle style_; - -  ClickDetector click_detector_; +  helper::ClickDetector click_detector_;  };  }  // namespace cru::ui::controls diff --git a/include/cru/ui/controls/Container.hpp b/include/cru/ui/controls/Container.hpp index 304d402c..18958837 100644 --- a/include/cru/ui/controls/Container.hpp +++ b/include/cru/ui/controls/Container.hpp @@ -1,5 +1,5 @@  #pragma once -#include "../ContentControl.hpp" +#include "ContentControl.hpp"  namespace cru::ui::controls {  class Container : public ContentControl { @@ -19,9 +19,6 @@ class Container : public ContentControl {    render::RenderObject* GetRenderObject() const override; - protected: -  void OnChildChanged(Control* old_child, Control* new_child) override; -   private:    std::unique_ptr<render::BorderRenderObject> render_object_;  }; diff --git a/include/cru/ui/controls/ContentControl.hpp b/include/cru/ui/controls/ContentControl.hpp new file mode 100644 index 00000000..1bdaf7e4 --- /dev/null +++ b/include/cru/ui/controls/ContentControl.hpp @@ -0,0 +1,38 @@ +#pragma once +#include "Control.hpp" + +#include "cru/ui/render/RenderObject.hpp" + +namespace cru::ui::controls { +class ContentControl : public Control { + protected: +  ContentControl() = default; + + public: +  ContentControl(const ContentControl& other) = delete; +  ContentControl(ContentControl&& other) = delete; +  ContentControl& operator=(const ContentControl& other) = delete; +  ContentControl& operator=(ContentControl&& other) = delete; +  ~ContentControl() override = default; + +  Control* GetChild() const; +  void SetChild(Control* child); + + protected: +  virtual void OnChildChanged(Control* old_child, Control* new_child); + +  render::RenderObject* GetContainerRenderObject() const { +    return container_render_object_; +  } +  void SetContainerRenderObject(render::RenderObject* ro) { +    container_render_object_ = ro; +  } + + private: +  using Control::AddChild; +  using Control::RemoveChild; + + private: +  render::RenderObject* container_render_object_ = nullptr; +}; +}  // namespace cru::ui::controls diff --git a/include/cru/ui/controls/Control.hpp b/include/cru/ui/controls/Control.hpp new file mode 100644 index 00000000..341b6ef2 --- /dev/null +++ b/include/cru/ui/controls/Control.hpp @@ -0,0 +1,157 @@ +#pragma once +#include "Base.hpp" + +#include "../events/UiEvent.hpp" +#include "../render/Base.hpp" +#include "cru/common/Event.hpp" + +#include <string_view> + +namespace cru::ui::controls { +class Control : public Object { +  friend host::WindowHost; + + protected: +  Control(); + + public: +  Control(const Control& other) = delete; +  Control(Control&& other) = delete; +  Control& operator=(const Control& other) = delete; +  Control& operator=(Control&& other) = delete; +  ~Control() override; + + public: +  virtual std::u16string_view GetControlType() const = 0; + +  //*************** region: tree *************** + public: +  host::WindowHost* GetWindowHost() const; + +  Control* GetParent() const { return parent_; } + +  const std::vector<Control*>& GetChildren() const { return children_; } + +  // Traverse the tree rooted the control including itself. +  void TraverseDescendants(const std::function<void(Control*)>& predicate); + + public: +  virtual render::RenderObject* GetRenderObject() const = 0; + +  //*************** region: focus *************** + public: +  bool HasFocus(); + +  void SetFocus(); + +  //*************** region: mouse *************** + public: +  bool IsMouseOver() const { return is_mouse_over_; } + +  bool CaptureMouse(); + +  bool ReleaseMouse(); + +  bool IsMouseCaptured(); + +  //*************** region: cursor *************** +  // Cursor is inherited from parent recursively if not set. + public: +  // null for not set +  std::shared_ptr<platform::gui::ICursor> GetCursor(); + +  // will not return nullptr +  std::shared_ptr<platform::gui::ICursor> GetInheritedCursor(); + +  // null to unset +  void SetCursor(std::shared_ptr<platform::gui::ICursor> cursor); + + public: +  style::StyleRuleSet* GetStyleRuleSet(); + +  //*************** region: events *************** + public: +  // Raised when mouse enter the control. Even when the control itself captures +  // the mouse, this event is raised as regular. But if mouse is captured by +  // another control, the control will not receive any mouse enter event. You +  // can use `IsMouseCaptured` to get more info. +  event::RoutedEvent<event::MouseEventArgs>* MouseEnterEvent() { +    return &mouse_enter_event_; +  } +  // Raised when mouse is leave the control. Even when the control itself +  // captures the mouse, this event is raised as regular. But if mouse is +  // captured by another control, the control will not receive any mouse leave +  // event. You can use `IsMouseCaptured` to get more info. +  event::RoutedEvent<event::MouseEventArgs>* MouseLeaveEvent() { +    return &mouse_leave_event_; +  } +  // Raised when mouse is move in the control. +  event::RoutedEvent<event::MouseEventArgs>* MouseMoveEvent() { +    return &mouse_move_event_; +  } +  // Raised when a mouse button is pressed in the control. +  event::RoutedEvent<event::MouseButtonEventArgs>* MouseDownEvent() { +    return &mouse_down_event_; +  } +  // Raised when a mouse button is released in the control. +  event::RoutedEvent<event::MouseButtonEventArgs>* MouseUpEvent() { +    return &mouse_up_event_; +  } +  event::RoutedEvent<event::MouseWheelEventArgs>* MouseWheelEvent() { +    return &mouse_wheel_event_; +  } +  event::RoutedEvent<event::KeyEventArgs>* KeyDownEvent() { +    return &key_down_event_; +  } +  event::RoutedEvent<event::KeyEventArgs>* KeyUpEvent() { +    return &key_up_event_; +  } +  event::RoutedEvent<event::FocusChangeEventArgs>* GainFocusEvent() { +    return &gain_focus_event_; +  } +  event::RoutedEvent<event::FocusChangeEventArgs>* LoseFocusEvent() { +    return &lose_focus_event_; +  } + + private: +  event::RoutedEvent<event::MouseEventArgs> mouse_enter_event_; +  event::RoutedEvent<event::MouseEventArgs> mouse_leave_event_; +  event::RoutedEvent<event::MouseEventArgs> mouse_move_event_; +  event::RoutedEvent<event::MouseButtonEventArgs> mouse_down_event_; +  event::RoutedEvent<event::MouseButtonEventArgs> mouse_up_event_; +  event::RoutedEvent<event::MouseWheelEventArgs> mouse_wheel_event_; + +  event::RoutedEvent<event::KeyEventArgs> key_down_event_; +  event::RoutedEvent<event::KeyEventArgs> key_up_event_; + +  event::RoutedEvent<event::FocusChangeEventArgs> gain_focus_event_; +  event::RoutedEvent<event::FocusChangeEventArgs> lose_focus_event_; + +  //*************** region: tree *************** + protected: +  void AddChild(Control* control, Index position); +  void RemoveChild(Index position); +  virtual void OnAddChild(Control* child, Index position); +  virtual void OnRemoveChild(Control* child, Index position); +  virtual void OnParentChanged(Control* old_parent, Control* new_parent); +  virtual void OnAttachToHost(host::WindowHost* host); +  virtual void OnDetachFromHost(host::WindowHost* host); + + protected: +  virtual void OnMouseHoverChange(bool newHover) { CRU_UNUSED(newHover) } + + private: +  Control* parent_ = nullptr; +  std::vector<Control*> children_; + +  host::WindowHost* window_host_ = nullptr; + + private: +  bool is_mouse_over_ = false; + +  std::shared_ptr<platform::gui::ICursor> cursor_ = nullptr; + +  std::unique_ptr<style::StyleRuleSet> style_rule_set_; +  std::unique_ptr<style::StyleRuleSetBind> style_rule_set_bind_; +}; +}  // namespace cru::ui::controls diff --git a/include/cru/ui/controls/FlexLayout.hpp b/include/cru/ui/controls/FlexLayout.hpp index 87162569..4f6abfdb 100644 --- a/include/cru/ui/controls/FlexLayout.hpp +++ b/include/cru/ui/controls/FlexLayout.hpp @@ -1,5 +1,5 @@  #pragma once -#include "../LayoutControl.hpp" +#include "LayoutControl.hpp"  namespace cru::ui::controls {  class FlexLayout : public LayoutControl { @@ -28,13 +28,12 @@ class FlexLayout : public LayoutControl {    FlexDirection GetFlexDirection() const;    void SetFlexDirection(FlexDirection direction); +  FlexCrossAlignment GetItemCrossAlign() const; +  void SetItemCrossAlign(FlexCrossAlignment alignment); +    FlexChildLayoutData GetChildLayoutData(Control* control);    void SetChildLayoutData(Control* control, FlexChildLayoutData data); - protected: -  void OnAddChild(Control* child, Index position) override; -  void OnRemoveChild(Control* child, Index position) override; -   private:    std::shared_ptr<render::FlexLayoutRenderObject> render_object_;  }; diff --git a/include/cru/ui/controls/IBorderControl.hpp b/include/cru/ui/controls/IBorderControl.hpp new file mode 100644 index 00000000..817305ef --- /dev/null +++ b/include/cru/ui/controls/IBorderControl.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "../style/ApplyBorderStyleInfo.hpp" +#include "Base.hpp" +#include "cru/common/Base.hpp" + +namespace cru::ui::controls { +struct IBorderControl : virtual Interface { +  virtual void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) = 0; +}; +}  // namespace cru::ui::controls diff --git a/include/cru/ui/controls/IClickableControl.hpp b/include/cru/ui/controls/IClickableControl.hpp new file mode 100644 index 00000000..aa7f13ab --- /dev/null +++ b/include/cru/ui/controls/IClickableControl.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "Base.hpp" + +#include "cru/common/Event.hpp" +#include "cru/ui/helper/ClickDetector.hpp" + +namespace cru::ui::controls { +struct IClickableControl : virtual Interface { +  virtual helper::ClickState GetClickState() = 0; +  virtual IEvent<helper::ClickState>* ClickStateChangeEvent() = 0; +}; +}  // namespace cru::ui::controls diff --git a/include/cru/ui/controls/LayoutControl.hpp b/include/cru/ui/controls/LayoutControl.hpp new file mode 100644 index 00000000..106dd94d --- /dev/null +++ b/include/cru/ui/controls/LayoutControl.hpp @@ -0,0 +1,35 @@ +#pragma once +#include "Control.hpp" + +namespace cru::ui::controls { +class LayoutControl : public Control { + protected: +  LayoutControl() = default; +  explicit LayoutControl(render::RenderObject* container_render_object) +      : container_render_object_(container_render_object) {} + + public: +  LayoutControl(const LayoutControl& other) = delete; +  LayoutControl(LayoutControl&& other) = delete; +  LayoutControl& operator=(const LayoutControl& other) = delete; +  LayoutControl& operator=(LayoutControl&& other) = delete; +  ~LayoutControl() override = default; + +  using Control::AddChild; +  using Control::RemoveChild; + + protected: +  // If container render object is not null. Render object of added or removed +  // child control will automatically sync to the container render object. +  render::RenderObject* GetContainerRenderObject() const; +  void SetContainerRenderObject(render::RenderObject* ro) { +    container_render_object_ = ro; +  } + +  void OnAddChild(Control* child, Index position) override; +  void OnRemoveChild(Control* child, Index position) override; + + private: +  render::RenderObject* container_render_object_ = nullptr; +}; +}  // namespace cru::ui::controls diff --git a/include/cru/ui/controls/NoChildControl.hpp b/include/cru/ui/controls/NoChildControl.hpp new file mode 100644 index 00000000..562137f1 --- /dev/null +++ b/include/cru/ui/controls/NoChildControl.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "Control.hpp" + +namespace cru::ui::controls { +class NoChildControl : public Control { + protected: +  NoChildControl() = default; + + public: +  NoChildControl(const NoChildControl& other) = delete; +  NoChildControl(NoChildControl&& other) = delete; +  NoChildControl& operator=(const NoChildControl& other) = delete; +  NoChildControl& operator=(NoChildControl&& other) = delete; +  ~NoChildControl() override = default; + + private: +  using Control::AddChild; +  using Control::RemoveChild; +}; +}  // namespace cru::ui diff --git a/include/cru/ui/controls/Popup.hpp b/include/cru/ui/controls/Popup.hpp new file mode 100644 index 00000000..d76e1211 --- /dev/null +++ b/include/cru/ui/controls/Popup.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "RootControl.hpp" + +#include "cru/ui/Base.hpp" +#include "cru/platform/gui/Base.hpp" + +#include <memory> + +namespace cru::ui::controls { +class Popup : public RootControl { + public: +  explicit Popup(Control* attached_control = nullptr); + +  CRU_DELETE_COPY(Popup) +  CRU_DELETE_MOVE(Popup) + +  ~Popup() override; + + protected: +  gsl::not_null<platform::gui::INativeWindow*> CreateNativeWindow( +      gsl::not_null<host::WindowHost*> host, +      platform::gui::INativeWindow* parent) override; +}; +}  // namespace cru::ui::controls diff --git a/include/cru/ui/controls/RootControl.hpp b/include/cru/ui/controls/RootControl.hpp new file mode 100644 index 00000000..53e69e7c --- /dev/null +++ b/include/cru/ui/controls/RootControl.hpp @@ -0,0 +1,45 @@ +#pragma once +#include "LayoutControl.hpp" + +#include "cru/common/Base.hpp" +#include "cru/platform/gui/Base.hpp" +#include "cru/ui/Base.hpp" + +namespace cru::ui::controls { +class RootControl : public LayoutControl { + protected: +  explicit RootControl(Control* attached_control); + + public: +  CRU_DELETE_COPY(RootControl) +  CRU_DELETE_MOVE(RootControl) +  ~RootControl() override; + + public: +  render::RenderObject* GetRenderObject() const override; + +  void EnsureWindowCreated(); + +  // If create is false and native window is not create, it will not be created +  // and shown. +  void Show(bool create = true); + +  Rect GetRect(); +  void SetRect(const Rect& rect); + + protected: +  virtual gsl::not_null<platform::gui::INativeWindow*> CreateNativeWindow( +      gsl::not_null<host::WindowHost*> host, +      platform::gui::INativeWindow* parent) = 0; + + private: +  platform::gui::INativeWindow* GetNativeWindow(bool create); + + private: +  std::unique_ptr<host::WindowHost> window_host_; + +  std::unique_ptr<render::StackLayoutRenderObject> render_object_; + +  Control* attached_control_; +}; +}  // namespace cru::ui::controls diff --git a/include/cru/ui/controls/StackLayout.hpp b/include/cru/ui/controls/StackLayout.hpp index c0b95044..aa9440c2 100644 --- a/include/cru/ui/controls/StackLayout.hpp +++ b/include/cru/ui/controls/StackLayout.hpp @@ -1,5 +1,5 @@  #pragma once -#include "../LayoutControl.hpp" +#include "LayoutControl.hpp"  namespace cru::ui::controls {  class StackLayout : public LayoutControl { @@ -21,10 +21,6 @@ class StackLayout : public LayoutControl {    render::RenderObject* GetRenderObject() const override; - protected: -  void OnAddChild(Control* child, Index position) override; -  void OnRemoveChild(Control* child, Index position) override; -   private:    std::shared_ptr<render::StackLayoutRenderObject> render_object_;  }; diff --git a/include/cru/ui/controls/TextBlock.hpp b/include/cru/ui/controls/TextBlock.hpp index 8a9a3bff..be31816c 100644 --- a/include/cru/ui/controls/TextBlock.hpp +++ b/include/cru/ui/controls/TextBlock.hpp @@ -1,15 +1,15 @@  #pragma once -#include "../NoChildControl.hpp" +#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"; -  static TextBlock* Create() { return new TextBlock(); } +  static TextBlock* Create(); +  static TextBlock* Create(std::u16string text, bool selectable = false);   protected:    TextBlock(); @@ -28,12 +28,17 @@ class TextBlock : public NoChildControl {    std::u16string GetText() const;    void SetText(std::u16string text); -  gsl::not_null<render::TextRenderObject*> GetTextRenderObject(); -  render::ScrollRenderObject* GetScrollRenderObject() { return nullptr; } +  bool IsSelectable() const; +  void SetSelectable(bool value); + +  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 5976f6da..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 "Base.hpp" +#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 { +class TextBox : public NoChildControl, +                public virtual IBorderControl, +                public virtual ITextHostControl {   public:    static constexpr std::u16string_view control_type = u"TextBox"; @@ -27,25 +31,16 @@ class TextBox : public NoChildControl {    render::RenderObject* GetRenderObject() const override; -  gsl::not_null<render::TextRenderObject*> GetTextRenderObject(); -  render::ScrollRenderObject* GetScrollRenderObject(); - -  const TextBoxBorderStyle& GetBorderStyle(); -  void SetBorderStyle(TextBoxBorderStyle border_style); - - protected: -  void OnMouseHoverChange(bool newHover) override; +  gsl::not_null<render::TextRenderObject*> GetTextRenderObject() override; +  render::ScrollRenderObject* GetScrollRenderObject() override; - private: -  void UpdateBorderStyle(); +  void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) override;   private:    std::unique_ptr<render::BorderRenderObject> border_render_object_;    std::unique_ptr<render::ScrollRenderObject> scroll_render_object_;    std::unique_ptr<render::TextRenderObject> text_render_object_; -  TextBoxBorderStyle border_style_; - -  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..340228fe --- /dev/null +++ b/include/cru/ui/controls/TextHostControlService.hpp @@ -0,0 +1,137 @@ +#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 ChangeSelectionEnd(gsl::index new_end); +  void AbortSelection(); + +  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 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)()->Bubble()->AddHandler( +        std::bind(handler, this, std::placeholders::_1)); +  } + +  void MouseMoveHandler(event::MouseEventArgs& args); +  void MouseDownHandler(event::MouseButtonEventArgs& args); +  void MouseUpHandler(event::MouseButtonEventArgs& args); +  void GainFocusHandler(event::FocusChangeEventArgs& args); +  void LoseFocusHandler(event::FocusChangeEventArgs& args); + +  void SetUpShortcuts(); + + 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_ = false; +}; +}  // namespace cru::ui::controls diff --git a/include/cru/ui/controls/Window.hpp b/include/cru/ui/controls/Window.hpp new file mode 100644 index 00000000..cca56b64 --- /dev/null +++ b/include/cru/ui/controls/Window.hpp @@ -0,0 +1,32 @@ +#pragma once +#include "cru/platform/gui/Base.hpp" +#include "cru/ui/controls/RootControl.hpp" + +#include "cru/common/Base.hpp" + +namespace cru::ui::controls { +class Window final : public RootControl { + public: +  static constexpr std::u16string_view control_type = u"Window"; + + public: +  static Window* Create(Control* attached_control = nullptr); + + private: +  explicit Window(Control* attached_control); + + public: +  CRU_DELETE_COPY(Window) +  CRU_DELETE_MOVE(Window) + +  ~Window() override; + + public: +  std::u16string_view GetControlType() const final { return control_type; } + + protected: +  gsl::not_null<platform::gui::INativeWindow*> CreateNativeWindow( +      gsl::not_null<host::WindowHost*> host, +      platform::gui::INativeWindow* parent) override; +}; +}  // namespace cru::ui::controls | 
