aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ui/controls/text_box.cpp70
-rw-r--r--src/ui/controls/text_box.h8
-rw-r--r--src/ui/controls/text_control.cpp13
-rw-r--r--src/ui/ui_base.cpp15
-rw-r--r--src/ui/ui_base.h23
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);
}
}