aboutsummaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-03-04 21:49:05 +0800
committercrupest <crupest@outlook.com>2020-03-04 21:49:05 +0800
commitabf604f8c6ec89c8d7df7062fe10fd17c60d5719 (patch)
tree82347efc2bef1966c0f1562d4467b7c389366ef9 /src/ui
parent79ba10135987cffc31496e8515c5372146d9b31d (diff)
downloadcru-abf604f8c6ec89c8d7df7062fe10fd17c60d5719.tar.gz
cru-abf604f8c6ec89c8d7df7062fe10fd17c60d5719.tar.bz2
cru-abf604f8c6ec89c8d7df7062fe10fd17c60d5719.zip
...
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/controls/text_block.cpp1
-rw-r--r--src/ui/controls/text_common.cpp168
2 files changed, 111 insertions, 58 deletions
diff --git a/src/ui/controls/text_block.cpp b/src/ui/controls/text_block.cpp
index be064ea0..ece599e8 100644
--- a/src/ui/controls/text_block.cpp
+++ b/src/ui/controls/text_block.cpp
@@ -30,6 +30,7 @@ TextBlock::TextBlock()
caret_brush_ = theme_resources->caret_brush;
service_ = std::make_unique<TextControlService>(this, this);
+ service_->SetEnabled(true);
}
TextBlock::~TextBlock() = default;
diff --git a/src/ui/controls/text_common.cpp b/src/ui/controls/text_common.cpp
index d6bcdd03..fdfdcc2c 100644
--- a/src/ui/controls/text_common.cpp
+++ b/src/ui/controls/text_common.cpp
@@ -18,67 +18,39 @@ constexpr long long caret_blink_duration = 500;
TextControlService::TextControlService(Control* control,
ITextControl* text_control)
- : control_(control), text_control_(text_control) {
- event_revoker_guards_.push_back(
- EventRevokerGuard{control->MouseDownEvent()->Direct()->AddHandler(
- [this](event::MouseButtonEventArgs& args) {
- if (this->select_down_button_.has_value()) {
- return;
- } else {
- if (!this->control_->CaptureMouse()) return;
- const auto text_render_object =
- this->text_control_->GetTextRenderObject();
- this->select_down_button_ = args.GetButton();
- const auto result = text_render_object->TextHitTest(
- text_render_object->FromRootToContent(args.GetPoint()));
- const auto position = result.position + (result.trailing ? 1 : 0);
- this->select_start_position_ = position;
- log::Debug("Begin to select text. Position: {}", position);
- }
- })});
-
- event_revoker_guards_.push_back(
- EventRevokerGuard{control->MouseMoveEvent()->Direct()->AddHandler(
- [this](event::MouseEventArgs& args) {
- if (this->select_down_button_.has_value()) {
- const auto text_render_object =
- this->text_control_->GetTextRenderObject();
- const auto result = text_render_object->TextHitTest(
- text_render_object->FromRootToContent(args.GetPoint()));
- const auto position = result.position + (result.trailing ? 1 : 0);
- this->caret_position_ = position;
- log::Debug("Text select range: {} : {}.", position,
- this->select_start_position_);
- this->text_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();
- }
- })});
+ : control_(control), text_control_(text_control) {}
- event_revoker_guards_.push_back(
- EventRevokerGuard{control->MouseUpEvent()->Direct()->AddHandler(
- [this](event::MouseButtonEventArgs& args) {
- if (this->select_down_button_.has_value() &&
- this->select_down_button_.value() == args.GetButton()) {
- this->control_->ReleaseMouse();
- this->select_down_button_ = std::nullopt;
- log::Debug("End selecting text.");
- }
- })});
+TextControlService::~TextControlService() {
+ if (enable_ && caret_visible_) TearDownCaretTimer();
}
-TextControlService::~TextControlService() { TearDownCaretTimer(); }
+void TextControlService::SetEnabled(bool enable) {
+ if (enable == enable_) return;
+ if (enable) {
+ AbortSelection();
+ SetupHandlers();
+ if (caret_visible_) {
+ SetupCaretTimer();
+ }
+ } else {
+ event_revoker_guards_.clear();
+ if (caret_visible_) {
+ TearDownCaretTimer();
+ }
+ }
+}
void TextControlService::SetCaretVisible(bool visible) {
- if (visible) {
- SetupCaretTimer();
+ if (visible == caret_visible_) return;
+
+ if (enable_) {
+ if (visible) {
+ SetupCaretTimer();
+ }
} else {
TearDownCaretTimer();
}
-}
+} // namespace cru::ui::controls
void TextControlService::DrawCaret(platform::graph::IPainter* painter) {
if (caret_show_) {
@@ -92,10 +64,19 @@ void TextControlService::DrawCaret(platform::graph::IPainter* painter) {
}
}
-void TextControlService::SetupCaretTimer() {
- if (caret_visible_) return;
+void TextControlService::AbortSelection() {
+ if (select_down_button_.has_value()) {
+ control_->ReleaseMouse();
+ select_down_button_ = std::nullopt;
+ }
+ text_control_->GetTextRenderObject()->SetSelectionRange(std::nullopt);
+}
- caret_visible_ = true;
+void TextControlService::SetupCaretTimer() {
+#ifdef CRU_DEBUG
+ assert(!caret_timer_set_);
+ caret_timer_set_ = true;
+#endif
caret_timer_tag_ =
platform::native::IUiApplication::GetInstance()->SetInterval(
std::chrono::milliseconds(caret_blink_duration), [this] {
@@ -105,9 +86,80 @@ void TextControlService::SetupCaretTimer() {
}
void TextControlService::TearDownCaretTimer() {
- if (!caret_visible_) return;
- caret_visible_ = false;
+#ifdef CRU_DEBUG
+ assert(!caret_timer_set_);
+ caret_timer_set_ = false;
+#endif
platform::native::IUiApplication::GetInstance()->CancelTimer(
caret_timer_tag_);
}
+
+void TextControlService::SetupHandlers() {
+ assert(event_revoker_guards_.empty());
+ event_revoker_guards_.push_back(
+ EventRevokerGuard{control_->MouseMoveEvent()->Direct()->AddHandler(
+ std::bind(&TextControlService::MouseMoveHandler, this,
+ std::placeholders::_1))});
+ event_revoker_guards_.push_back(
+ EventRevokerGuard{control_->MouseDownEvent()->Direct()->AddHandler(
+ std::bind(&TextControlService::MouseDownHandler, this,
+ std::placeholders::_1))});
+ event_revoker_guards_.push_back(EventRevokerGuard{
+ control_->MouseUpEvent()->Direct()->AddHandler(std::bind(
+ &TextControlService::MouseUpHandler, this, std::placeholders::_1))});
+ event_revoker_guards_.push_back(
+ EventRevokerGuard{control_->LoseFocusEvent()->Direct()->AddHandler(
+ std::bind(&TextControlService::LoseFocusHandler, this,
+ std::placeholders::_1))});
+}
+
+void TextControlService::MouseMoveHandler(event::MouseEventArgs& args) {
+ if (this->select_down_button_.has_value()) {
+ const auto text_render_object = this->text_control_->GetTextRenderObject();
+ const auto result = text_render_object->TextHitTest(
+ text_render_object->FromRootToContent(args.GetPoint()));
+ const auto position = result.position + (result.trailing ? 1 : 0);
+ this->caret_position_ = position;
+ log::Debug(
+ "TextControlService: Text selection changed on mouse move, range: {}, "
+ "{}.",
+ position, this->select_start_position_);
+ this->text_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();
+ }
+}
+
+void TextControlService::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();
+ this->select_down_button_ = args.GetButton();
+ const auto result = text_render_object->TextHitTest(
+ text_render_object->FromRootToContent(args.GetPoint()));
+ const auto position = result.position + (result.trailing ? 1 : 0);
+ this->select_start_position_ = position;
+ log::Debug("TextControlService: Begin to select text, start position: {}.",
+ position);
+ }
+}
+
+void TextControlService::MouseUpHandler(event::MouseButtonEventArgs& args) {
+ if (this->select_down_button_.has_value() &&
+ this->select_down_button_.value() == args.GetButton()) {
+ this->control_->ReleaseMouse();
+ this->select_down_button_ = std::nullopt;
+ log::Debug("TextControlService: End selecting text.");
+ }
+}
+
+void TextControlService::LoseFocusHandler(event::FocusChangeEventArgs& args) {
+ if (!args.IsWindow()) this->AbortSelection();
+}
} // namespace cru::ui::controls