diff options
author | crupest <crupest@outlook.com> | 2018-10-07 00:49:38 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2018-10-07 00:49:38 +0800 |
commit | 36820c22929f4fb11892c4fbd52f321cc63a55ad (patch) | |
tree | 0c87a377fac3d9359995cb1fa62ec541fe83f579 | |
parent | b0057dc911f96258c7280b89c8f4da828ecc283c (diff) | |
download | cru-36820c22929f4fb11892c4fbd52f321cc63a55ad.tar.gz cru-36820c22929f4fb11892c4fbd52f321cc63a55ad.tar.bz2 cru-36820c22929f4fb11892c4fbd52f321cc63a55ad.zip |
Add shift selection, and fix the bug that caret is at wrong position when move with selection.
-rw-r--r-- | src/ui/controls/text_box.cpp | 70 | ||||
-rw-r--r-- | src/ui/controls/text_box.h | 8 | ||||
-rw-r--r-- | src/ui/controls/text_control.cpp | 13 | ||||
-rw-r--r-- | src/ui/ui_base.cpp | 15 | ||||
-rw-r--r-- | src/ui/ui_base.h | 23 |
5 files changed, 109 insertions, 20 deletions
diff --git a/src/ui/controls/text_box.cpp b/src/ui/controls/text_box.cpp index 30b9069a..54b2f7ab 100644 --- a/src/ui/controls/text_box.cpp +++ b/src/ui/controls/text_box.cpp @@ -67,16 +67,47 @@ namespace cru::ui::controls Control::OnKeyDownCore(args); if (args.GetVirtualCode() == VK_LEFT && caret_position_ > 0) { - ClearSelection(); - caret_position_--; + if (IsKeyDown(VK_SHIFT)) + { + if (GetCaretSelectionSide()) + ShiftLeftSelectionRange(-1); + else + ShiftRightSelectionRange(-1); + } + else + { + const auto selection = GetSelectedRange(); + if (selection.has_value()) + { + ClearSelection(); + caret_position_ = selection.value().position; + } + else + caret_position_--; + } Repaint(); } if (args.GetVirtualCode() == VK_RIGHT && caret_position_ < GetText().size()) { - ClearSelection(); - caret_position_++; - Repaint(); + if (IsKeyDown(VK_SHIFT)) + { + if (GetCaretSelectionSide()) + ShiftLeftSelectionRange(1); + else + ShiftRightSelectionRange(1); + } + else + { + const auto selection = GetSelectedRange(); + if (selection.has_value()) + { + ClearSelection(); + caret_position_ = selection.value().position + selection.value().count; + } + else + caret_position_++; + } } } @@ -138,4 +169,33 @@ namespace cru::ui::controls caret_position_ = position; Repaint(); } + + bool TextBox::GetCaretSelectionSide() const + { + const auto selection = TextRange::ToTwoSides(GetSelectedRange(), caret_position_); + if (selection.first == caret_position_) + return true; + if (selection.second == caret_position_) + return false; + assert(false); + return true; + } + + void TextBox::ShiftLeftSelectionRange(const int count) + { + const auto selection_range_side = TextRange::ToTwoSides(GetSelectedRange(), caret_position_); + int new_left = selection_range_side.first + count; + new_left = new_left < 0 ? 0 : new_left; // at least 0 + caret_position_ = new_left; + SetSelectedRange(TextRange::FromTwoSides(static_cast<unsigned>(new_left), selection_range_side.second)); + } + + void TextBox::ShiftRightSelectionRange(const int count) + { + const auto selection_range_side = TextRange::ToTwoSides(GetSelectedRange(), caret_position_); + int new_right = selection_range_side.second + count; + new_right = new_right < 0 ? 0 : new_right; // at least 0 + caret_position_ = new_right; + SetSelectedRange(TextRange::FromTwoSides(selection_range_side.first, static_cast<unsigned>(new_right))); + } } diff --git a/src/ui/controls/text_box.h b/src/ui/controls/text_box.h index 540ac758..37e04835 100644 --- a/src/ui/controls/text_box.h +++ b/src/ui/controls/text_box.h @@ -36,7 +36,13 @@ namespace cru::ui::controls void OnKeyDownCore(events::KeyEventArgs& args) override final; void OnCharCore(events::CharEventArgs& args) override final; - void RequestChangeCaretPosition(unsigned position) override; + void RequestChangeCaretPosition(unsigned position) override final; + + private: + // return true if left + bool GetCaretSelectionSide() const; + void ShiftLeftSelectionRange(int count); + void ShiftRightSelectionRange(int count); private: unsigned caret_position_ = 0; diff --git a/src/ui/controls/text_control.cpp b/src/ui/controls/text_control.cpp index ee5b253d..3c5d7c33 100644 --- a/src/ui/controls/text_control.cpp +++ b/src/ui/controls/text_control.cpp @@ -162,18 +162,7 @@ namespace cru::ui::controls { const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this), false).value(); RequestChangeCaretPosition(hit_test_result); - if (hit_test_result > mouse_down_position_) - { - selected_range_ = TextRange(mouse_down_position_, hit_test_result - mouse_down_position_); - } - else if (hit_test_result < mouse_down_position_) - { - selected_range_ = TextRange(hit_test_result, mouse_down_position_ - hit_test_result); - } - else - { - selected_range_ = std::nullopt; - } + selected_range_ = TextRange::FromTwoSides(hit_test_result, mouse_down_position_); Repaint(); } } diff --git a/src/ui/ui_base.cpp b/src/ui/ui_base.cpp index 550432e4..3bee2269 100644 --- a/src/ui/ui_base.cpp +++ b/src/ui/ui_base.cpp @@ -1,6 +1,19 @@ #include "ui_base.h" +#include "system_headers.h" + namespace cru { namespace ui { - } + bool IsKeyDown(const int virtual_code) + { + const auto result = ::GetKeyState(virtual_code); + return (static_cast<unsigned short>(result) & 0x8000) != 0; + } + + bool IsKeyToggled(const int virtual_code) + { + const auto result = ::GetKeyState(virtual_code); + return (static_cast<unsigned short>(result) & 1) != 0; + } + } } diff --git a/src/ui/ui_base.h b/src/ui/ui_base.h index 51ae4084..bff30bfd 100644 --- a/src/ui/ui_base.h +++ b/src/ui/ui_base.h @@ -1,5 +1,7 @@ #pragma once +#include <optional> + namespace cru { @@ -125,8 +127,24 @@ namespace cru struct TextRange { + constexpr static std::optional<TextRange> FromTwoSides(unsigned first, unsigned second) + { + if (first > second) + return std::make_optional<TextRange>(second, first - second); + if (first < second) + return std::make_optional<TextRange>(first, second - first); + return std::nullopt; + } + + constexpr static std::pair<unsigned, unsigned> ToTwoSides(std::optional<TextRange> text_range, unsigned default_position = 0) + { + if (text_range.has_value()) + return std::make_pair(text_range.value().position, text_range.value().position + text_range.value().count); + return std::make_pair(default_position, default_position); + } + constexpr TextRange() = default; - constexpr TextRange(const int position, const int count) + constexpr TextRange(const unsigned position, const unsigned count) : position(position), count(count) { @@ -135,5 +153,8 @@ namespace cru unsigned position = 0; unsigned count = 0; }; + + bool IsKeyDown(int virtual_code); + bool IsKeyToggled(int virtual_code); } } |