mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-03-31 09:17:04 +09:00
Entry: implement moving care by word with ctrl+arrow keys
This commit is contained in:
@@ -19,6 +19,11 @@ namespace gsr {
|
|||||||
|
|
||||||
class Entry : public Widget {
|
class Entry : public Widget {
|
||||||
public:
|
public:
|
||||||
|
enum class Direction {
|
||||||
|
LEFT,
|
||||||
|
RIGHT
|
||||||
|
};
|
||||||
|
|
||||||
Entry(mgl::Font *font, const char *text, float max_width);
|
Entry(mgl::Font *font, const char *text, float max_width);
|
||||||
Entry(const Entry&) = delete;
|
Entry(const Entry&) = delete;
|
||||||
Entry& operator=(const Entry&) = delete;
|
Entry& operator=(const Entry&) = delete;
|
||||||
@@ -40,6 +45,7 @@ namespace gsr {
|
|||||||
|
|
||||||
std::function<void(const std::string &text)> on_changed;
|
std::function<void(const std::string &text)> on_changed;
|
||||||
private:
|
private:
|
||||||
|
void move_caret_word(Direction direction, size_t max_codepoints);
|
||||||
EntryValidateHandlerResult set_text_internal(std::string str);
|
EntryValidateHandlerResult set_text_internal(std::string str);
|
||||||
void draw_caret(mgl::Window &window, mgl::vec2f draw_pos, mgl::vec2f caret_size);
|
void draw_caret(mgl::Window &window, mgl::vec2f draw_pos, mgl::vec2f caret_size);
|
||||||
void draw_caret_selection(mgl::Window &window, mgl::vec2f draw_pos, mgl::vec2f caret_size);
|
void draw_caret_selection(mgl::Window &window, mgl::vec2f draw_pos, mgl::vec2f caret_size);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <mglpp/system/FloatRect.hpp>
|
#include <mglpp/system/FloatRect.hpp>
|
||||||
#include <mglpp/system/Utf8.hpp>
|
#include <mglpp/system/Utf8.hpp>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
namespace gsr {
|
namespace gsr {
|
||||||
static const float padding_top_scale = 0.004629f;
|
static const float padding_top_scale = 0.004629f;
|
||||||
@@ -100,31 +101,21 @@ namespace gsr {
|
|||||||
caret.offset_x = text.find_character_pos(caret.utf8_index).x - this->text.get_position().x;
|
caret.offset_x = text.find_character_pos(caret.utf8_index).x - this->text.get_position().x;
|
||||||
|
|
||||||
show_selection = true;
|
show_selection = true;
|
||||||
} else if(event.key.code == mgl::Keyboard::Left && caret.byte_index > 0) {
|
} else if(event.key.code == mgl::Keyboard::Left) {
|
||||||
if(!selecting_with_keyboard && show_selection) {
|
if(!selecting_with_keyboard && show_selection)
|
||||||
show_selection = false;
|
show_selection = false;
|
||||||
} else {
|
else
|
||||||
caret.byte_index = mgl::utf8_get_start_of_codepoint((const unsigned char*)text.get_string().data(), text.get_string().size(), caret.byte_index - 1);
|
move_caret_word(Direction::LEFT, event.key.control ? 999999 : 1);
|
||||||
caret.utf8_index -= 1;
|
|
||||||
// TODO: Move left by one character instead of calculating every character to caret index
|
|
||||||
caret.offset_x = text.find_character_pos(caret.utf8_index).x - this->text.get_position().x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!selecting_with_keyboard) {
|
if(!selecting_with_keyboard) {
|
||||||
selection_start_caret = caret;
|
selection_start_caret = caret;
|
||||||
show_selection = false;
|
show_selection = false;
|
||||||
}
|
}
|
||||||
} else if(event.key.code == mgl::Keyboard::Right) {
|
} else if(event.key.code == mgl::Keyboard::Right) {
|
||||||
if(!selecting_with_keyboard && show_selection) {
|
if(!selecting_with_keyboard && show_selection)
|
||||||
show_selection = false;
|
show_selection = false;
|
||||||
} else {
|
else
|
||||||
const int caret_byte_index_before = caret.byte_index;
|
move_caret_word(Direction::RIGHT, event.key.control ? 999999 : 1);
|
||||||
caret.byte_index = mgl::utf8_index_to_byte_index((const unsigned char*)text.get_string().data(), text.get_string().size(), caret.utf8_index + 1);
|
|
||||||
if(caret.byte_index != caret_byte_index_before)
|
|
||||||
caret.utf8_index += 1;
|
|
||||||
// TODO: Move right by one character instead of calculating every character to caret index
|
|
||||||
caret.offset_x = text.find_character_pos(caret.utf8_index).x - this->text.get_position().x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!selecting_with_keyboard) {
|
if(!selecting_with_keyboard) {
|
||||||
selection_start_caret = caret;
|
selection_start_caret = caret;
|
||||||
@@ -254,11 +245,16 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Entry::draw_caret_selection(mgl::Window &window, mgl::vec2f draw_pos, mgl::vec2f caret_size) {
|
void Entry::draw_caret_selection(mgl::Window &window, mgl::vec2f draw_pos, mgl::vec2f caret_size) {
|
||||||
|
if(selection_start_caret.byte_index == caret.byte_index)
|
||||||
|
return;
|
||||||
|
|
||||||
const int padding_top = padding_top_scale * get_theme().window_height;
|
const int padding_top = padding_top_scale * get_theme().window_height;
|
||||||
const int padding_left = padding_left_scale * get_theme().window_height;
|
const int padding_left = padding_left_scale * get_theme().window_height;
|
||||||
|
const int caret_width = std::max(1.0f, caret_width_scale * get_theme().window_height);
|
||||||
|
const int offset = caret.byte_index < selection_start_caret.byte_index ? caret_width : 0;
|
||||||
|
|
||||||
mgl::Rectangle caret_selection_rect(mgl::vec2f(std::abs(selection_start_caret.offset_x - caret.offset_x), caret_size.y).floor());
|
mgl::Rectangle caret_selection_rect(mgl::vec2f(std::abs(selection_start_caret.offset_x - caret.offset_x) - offset, caret_size.y).floor());
|
||||||
caret_selection_rect.set_position((draw_pos + mgl::vec2f(padding_left + std::min(caret.offset_x, selection_start_caret.offset_x) - text_overflow, padding_top)).floor());
|
caret_selection_rect.set_position((draw_pos + mgl::vec2f(padding_left + std::min(caret.offset_x, selection_start_caret.offset_x) - text_overflow + offset, padding_top)).floor());
|
||||||
mgl::Color caret_select_color = get_color_theme().tint_color;
|
mgl::Color caret_select_color = get_color_theme().tint_color;
|
||||||
caret_select_color.a = 100;
|
caret_select_color.a = 100;
|
||||||
caret_selection_rect.set_color(caret_select_color);
|
caret_selection_rect.set_color(caret_select_color);
|
||||||
@@ -274,6 +270,42 @@ namespace gsr {
|
|||||||
return { max_width, text.get_bounds().size.y + padding_top + padding_bottom };
|
return { max_width, text.get_bounds().size.y + padding_top + padding_bottom };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Entry::move_caret_word(Direction direction, size_t max_codepoints) {
|
||||||
|
const int dir_step = direction == Direction::LEFT ? -1 : 1;
|
||||||
|
const int num_delimiter_chars = 7;
|
||||||
|
const char delimiter_chars[num_delimiter_chars + 1] = " \t\n/.,;";
|
||||||
|
const unsigned char *text_str = (const unsigned char*)text.get_string().data();
|
||||||
|
|
||||||
|
int num_non_delimiter_chars_found = 0;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < max_codepoints; ++i) {
|
||||||
|
const int caret_byte_index_before = caret.byte_index;
|
||||||
|
caret.byte_index = mgl::utf8_index_to_byte_index(text_str, text.get_string().size(), std::max(0, caret.utf8_index + dir_step));
|
||||||
|
if(caret.byte_index == caret_byte_index_before)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const size_t codepoint_start = std::min(caret_byte_index_before, caret.byte_index);
|
||||||
|
const size_t codepoint_end = std::max(caret_byte_index_before, caret.byte_index);
|
||||||
|
uint32_t decoded_codepoint = ' ';
|
||||||
|
size_t codepoint_length = 1;
|
||||||
|
mgl::utf8_decode(text_str + codepoint_start, codepoint_end - codepoint_start, &decoded_codepoint, &codepoint_length);
|
||||||
|
|
||||||
|
const bool is_delimiter_char = !!memchr(delimiter_chars, decoded_codepoint, num_delimiter_chars);
|
||||||
|
if(is_delimiter_char) {
|
||||||
|
if(num_non_delimiter_chars_found > 0) {
|
||||||
|
caret.byte_index = caret_byte_index_before;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
++num_non_delimiter_chars_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
caret.utf8_index += dir_step;
|
||||||
|
}
|
||||||
|
// TODO: Move right by one character instead of calculating every character to caret index
|
||||||
|
caret.offset_x = text.find_character_pos(caret.utf8_index).x - this->text.get_position().x;
|
||||||
|
}
|
||||||
|
|
||||||
EntryValidateHandlerResult Entry::set_text(std::string str) {
|
EntryValidateHandlerResult Entry::set_text(std::string str) {
|
||||||
EntryValidateHandlerResult validate_result = set_text_internal(std::move(str));
|
EntryValidateHandlerResult validate_result = set_text_internal(std::move(str));
|
||||||
if(validate_result == EntryValidateHandlerResult::ALLOW) {
|
if(validate_result == EntryValidateHandlerResult::ALLOW) {
|
||||||
|
|||||||
Reference in New Issue
Block a user