aboutsummaryrefslogtreecommitdiff
path: root/src/ui/controls
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-03-18 22:57:08 +0800
committercrupest <crupest@outlook.com>2020-03-18 22:57:08 +0800
commitc5a4f8c11d0d84d85359e5ff03477da5e9f12926 (patch)
tree47122aa3c07ecc536ca387f416de1179c8203329 /src/ui/controls
parentbfd277f9f621931a1c6ea05ea2cd6d04455cfe67 (diff)
downloadcru-c5a4f8c11d0d84d85359e5ff03477da5e9f12926.tar.gz
cru-c5a4f8c11d0d84d85359e5ff03477da5e9f12926.tar.bz2
cru-c5a4f8c11d0d84d85359e5ff03477da5e9f12926.zip
...
Diffstat (limited to 'src/ui/controls')
-rw-r--r--src/ui/controls/container.cpp2
-rw-r--r--src/ui/controls/text_block.cpp3
-rw-r--r--src/ui/controls/text_control_service.hpp (renamed from src/ui/controls/text_common.cpp)137
3 files changed, 110 insertions, 32 deletions
diff --git a/src/ui/controls/container.cpp b/src/ui/controls/container.cpp
index 4695ad4c..84582d80 100644
--- a/src/ui/controls/container.cpp
+++ b/src/ui/controls/container.cpp
@@ -11,7 +11,7 @@ Container::Container() {
Container::~Container() = default;
-void Container::OnChildChanged(Control* old_child, Control* new_child) {
+void Container::OnChildChanged(Control*, Control* new_child) {
render_object_->RemoveChild(0);
render_object_->AddChild(new_child->GetRenderObject(), 0);
}
diff --git a/src/ui/controls/text_block.cpp b/src/ui/controls/text_block.cpp
index ece599e8..0a243d2e 100644
--- a/src/ui/controls/text_block.cpp
+++ b/src/ui/controls/text_block.cpp
@@ -4,6 +4,7 @@
#include "cru/ui/render/stack_layout_render_object.hpp"
#include "cru/ui/render/text_render_object.hpp"
#include "cru/ui/ui_manager.hpp"
+#include "text_control_service.hpp"
namespace cru::ui::controls {
using render::CanvasRenderObject;
@@ -29,7 +30,7 @@ TextBlock::TextBlock()
caret_brush_ = theme_resources->caret_brush;
- service_ = std::make_unique<TextControlService>(this, this);
+ service_ = std::make_unique<TextControlService<TextBlock>>(this);
service_->SetEnabled(true);
}
diff --git a/src/ui/controls/text_common.cpp b/src/ui/controls/text_control_service.hpp
index fdfdcc2c..3885242a 100644
--- a/src/ui/controls/text_common.cpp
+++ b/src/ui/controls/text_control_service.hpp
@@ -1,5 +1,4 @@
-#include "cru/ui/controls/text_common.hpp"
-
+#pragma once
#include "cru/common/logger.hpp"
#include "cru/platform/graph/font.hpp"
#include "cru/platform/graph/painter.hpp"
@@ -7,24 +6,87 @@
#include "cru/ui/control.hpp"
#include "cru/ui/render/canvas_render_object.hpp"
#include "cru/ui/render/text_render_object.hpp"
-
-#include <cassert>
+#include "cru/ui/ui_event.hpp"
namespace cru::ui::controls {
-using platform::graph::ITextLayout;
-
constexpr float caret_width = 2;
constexpr long long caret_blink_duration = 500;
-TextControlService::TextControlService(Control* control,
- ITextControl* text_control)
- : control_(control), text_control_(text_control) {}
+// TControl should inherits `Control` and has following methods:
+// ```
+// render::TextRenderObject* GetTextRenderObject();
+// render::CanvasRenderObject* GetCaretRenderObject();
+// platform::graph::IBrush* GetCaretBrush();
+// ```
+template <typename TControl>
+class TextControlService : public Object {
+ public:
+ TextControlService(TControl* control);
+
+ CRU_DELETE_COPY(TextControlService)
+ CRU_DELETE_MOVE(TextControlService)
+
+ ~TextControlService();
+
+ public:
+ bool IsEnabled() { return enable_; }
+ void SetEnabled(bool enable);
+
+ int GetCaretPosition() { return caret_position_; }
+ void SetCaretPosition(int position) { caret_position_ = position; }
+
+ bool IsCaretVisible() { return caret_visible_; }
+ void SetCaretVisible(bool visible);
+
+ // please set correct offset before calling this
+ void DrawCaret(platform::graph::IPainter* painter);
+
+ private:
+ void AbortSelection();
+
+ void SetupCaretTimer();
+ void TearDownCaretTimer();
+
+ void SetupHandlers();
+
+ void MouseMoveHandler(event::MouseEventArgs& args);
+ void MouseDownHandler(event::MouseButtonEventArgs& args);
+ void MouseUpHandler(event::MouseButtonEventArgs& args);
+ void LoseFocusHandler(event::FocusChangeEventArgs& args);
+
+ private:
+ TControl* control_;
+ std::vector<EventRevokerGuard> event_revoker_guards_;
+
+ bool enable_ = false;
+
+ bool caret_visible_ = false;
+ int caret_position_ = 0;
+#ifdef CRU_DEBUG
+ bool caret_timer_set_ = false;
+#endif
+ unsigned long caret_timer_tag_;
+ // this is used for blinking of caret
+ bool caret_show_ = true;
+
+ // nullopt means not selecting
+ std::optional<MouseButton> select_down_button_;
+
+ // before the char
+ int select_start_position_;
+};
+
+template <typename TControl>
+TextControlService<TControl>::TextControlService(TControl* control)
+ : control_(control) {}
-TextControlService::~TextControlService() {
+template <typename TControl>
+TextControlService<TControl>::~TextControlService() {
if (enable_ && caret_visible_) TearDownCaretTimer();
}
-void TextControlService::SetEnabled(bool enable) {
+template <typename TControl>
+void TextControlService<TControl>::SetEnabled(bool enable) {
if (enable == enable_) return;
if (enable) {
AbortSelection();
@@ -40,7 +102,8 @@ void TextControlService::SetEnabled(bool enable) {
}
}
-void TextControlService::SetCaretVisible(bool visible) {
+template <typename TControl>
+void TextControlService<TControl>::SetCaretVisible(bool visible) {
if (visible == caret_visible_) return;
if (enable_) {
@@ -52,27 +115,31 @@ void TextControlService::SetCaretVisible(bool visible) {
}
} // namespace cru::ui::controls
-void TextControlService::DrawCaret(platform::graph::IPainter* painter) {
+template <typename TControl>
+void TextControlService<TControl>::DrawCaret(
+ platform::graph::IPainter* painter) {
if (caret_show_) {
- const auto text_render_object = text_control_->GetTextRenderObject();
+ const auto text_render_object = control_->GetTextRenderObject();
const auto point = text_render_object->TextSingleRect(
caret_position_, false); // Maybe cache the result???
painter->FillRectangle(
Rect{point,
Size{caret_width, text_render_object->GetFont()->GetFontSize()}},
- text_control_->GetCaretBrush());
+ control_->GetCaretBrush());
}
}
-void TextControlService::AbortSelection() {
+template <typename TControl>
+void TextControlService<TControl>::AbortSelection() {
if (select_down_button_.has_value()) {
control_->ReleaseMouse();
select_down_button_ = std::nullopt;
}
- text_control_->GetTextRenderObject()->SetSelectionRange(std::nullopt);
+ control_->GetTextRenderObject()->SetSelectionRange(std::nullopt);
}
-void TextControlService::SetupCaretTimer() {
+template <typename TControl>
+void TextControlService<TControl>::SetupCaretTimer() {
#ifdef CRU_DEBUG
assert(!caret_timer_set_);
caret_timer_set_ = true;
@@ -81,11 +148,12 @@ void TextControlService::SetupCaretTimer() {
platform::native::IUiApplication::GetInstance()->SetInterval(
std::chrono::milliseconds(caret_blink_duration), [this] {
this->caret_show_ = !this->caret_show_;
- this->text_control_->GetCaretRenderObject()->InvalidatePaint();
+ this->control_->GetCaretRenderObject()->InvalidatePaint();
});
}
-void TextControlService::TearDownCaretTimer() {
+template <typename TControl>
+void TextControlService<TControl>::TearDownCaretTimer() {
#ifdef CRU_DEBUG
assert(!caret_timer_set_);
caret_timer_set_ = false;
@@ -94,7 +162,8 @@ void TextControlService::TearDownCaretTimer() {
caret_timer_tag_);
}
-void TextControlService::SetupHandlers() {
+template <typename TControl>
+void TextControlService<TControl>::SetupHandlers() {
assert(event_revoker_guards_.empty());
event_revoker_guards_.push_back(
EventRevokerGuard{control_->MouseMoveEvent()->Direct()->AddHandler(
@@ -113,9 +182,11 @@ void TextControlService::SetupHandlers() {
std::placeholders::_1))});
}
-void TextControlService::MouseMoveHandler(event::MouseEventArgs& args) {
+template <typename TControl>
+void TextControlService<TControl>::MouseMoveHandler(
+ event::MouseEventArgs& args) {
if (this->select_down_button_.has_value()) {
- const auto text_render_object = this->text_control_->GetTextRenderObject();
+ const auto text_render_object = this->control_->GetTextRenderObject();
const auto result = text_render_object->TextHitTest(
text_render_object->FromRootToContent(args.GetPoint()));
const auto position = result.position + (result.trailing ? 1 : 0);
@@ -124,22 +195,24 @@ void TextControlService::MouseMoveHandler(event::MouseEventArgs& args) {
"TextControlService: Text selection changed on mouse move, range: {}, "
"{}.",
position, this->select_start_position_);
- this->text_control_->GetTextRenderObject()->SetSelectionRange(
+ this->control_->GetTextRenderObject()->SetSelectionRange(
TextRange::FromTwoSides(
static_cast<unsigned>(position),
static_cast<unsigned>(this->select_start_position_)));
- this->text_control_->GetTextRenderObject()->InvalidatePaint();
- this->text_control_->GetCaretRenderObject()->InvalidatePaint();
+ this->control_->GetTextRenderObject()->InvalidatePaint();
+ this->control_->GetCaretRenderObject()->InvalidatePaint();
}
}
-void TextControlService::MouseDownHandler(event::MouseButtonEventArgs& args) {
+template <typename TControl>
+void TextControlService<TControl>::MouseDownHandler(
+ event::MouseButtonEventArgs& args) {
if (this->select_down_button_.has_value()) {
return;
} else {
if (!this->control_->CaptureMouse()) return;
if (!this->control_->RequestFocus()) return;
- const auto text_render_object = this->text_control_->GetTextRenderObject();
+ const auto text_render_object = this->control_->GetTextRenderObject();
this->select_down_button_ = args.GetButton();
const auto result = text_render_object->TextHitTest(
text_render_object->FromRootToContent(args.GetPoint()));
@@ -150,7 +223,9 @@ void TextControlService::MouseDownHandler(event::MouseButtonEventArgs& args) {
}
}
-void TextControlService::MouseUpHandler(event::MouseButtonEventArgs& args) {
+template <typename TControl>
+void TextControlService<TControl>::MouseUpHandler(
+ event::MouseButtonEventArgs& args) {
if (this->select_down_button_.has_value() &&
this->select_down_button_.value() == args.GetButton()) {
this->control_->ReleaseMouse();
@@ -159,7 +234,9 @@ void TextControlService::MouseUpHandler(event::MouseButtonEventArgs& args) {
}
}
-void TextControlService::LoseFocusHandler(event::FocusChangeEventArgs& args) {
+template <typename TControl>
+void TextControlService<TControl>::LoseFocusHandler(
+ event::FocusChangeEventArgs& args) {
if (!args.IsWindow()) this->AbortSelection();
}
} // namespace cru::ui::controls