Skip to content

Commit 90fac21

Browse files
committed
fix: use newer sld::Key APi in textinput
also provide a delete + Shift key combination, so that you can delete only the same characters, add ICU for better unicode support, but thats optional, otherwise some ascii functions are used
1 parent ad6b2e8 commit 90fac21

File tree

6 files changed

+172
-21
lines changed

6 files changed

+172
-21
lines changed

src/manager/event_dispatcher.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ struct EventDispatcher final {
2020
sdl::Key{ SDLK_RETURN },
2121
sdl::Key{ SDLK_BACKSPACE },
2222
sdl::Key{ SDLK_BACKSPACE, { sdl::Modifier::CTRL } },
23+
sdl::Key{ SDLK_BACKSPACE, { sdl::Modifier::SHIFT } },
2324
sdl::Key{ SDLK_DOWN },
2425
sdl::Key{ SDLK_UP },
2526
sdl::Key{ SDLK_LEFT },
2627
sdl::Key{ SDLK_RIGHT },
28+
sdl::Key{ SDLK_LEFT, { sdl::Modifier::CTRL } },
29+
sdl::Key{ SDLK_RIGHT, { sdl::Modifier::CTRL } },
2730
sdl::Key{ SDLK_ESCAPE },
2831
sdl::Key{ SDLK_TAB },
2932
sdl::Key{ SDLK_c, { sdl::Modifier::CTRL } },

src/ui/components/textinput.cpp

Lines changed: 126 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
#include "manager/event_dispatcher.hpp"
77
#include "textinput.hpp"
88

9+
#if defined(_HAVE_ICU_DEP)
10+
#include <unicode/uchar.h>
11+
#endif
12+
913

1014
using namespace std::chrono_literals;
1115

@@ -129,26 +133,43 @@ ui::TextInput::handle_event( //NOLINT(readability-function-cognitive-complexity)
129133
{ EventHandleType::RequestAction, this }
130134
};
131135
}
136+
//TODO(Totto): in some cases this is caught before that, and never triggered
132137
case SDLK_BACKSPACE: {
133-
const auto remove_all = (event.key.keysym.mod & KMOD_CTRL) != 0;
138+
const auto sdl_key = sdl::Key{ event.key.keysym };
139+
140+
const auto ctrl_pressed = sdl_key.has_modifier(sdl::Modifier::CTRL);
141+
142+
const auto shift_pressed = sdl_key.has_modifier(sdl::Modifier::SHIFT);
134143

135144
if (not m_text.empty()) {
136-
if (remove_all) {
137-
m_text = "";
138-
m_cursor_position = 0;
145+
// NOTE: if both modifiers are pressed, we prioritize ctrl
146+
if (ctrl_pressed) {
147+
remove_at_cursor(RemoveMode::All);
148+
recalculate_textures(true);
149+
return true;
150+
}
151+
152+
if (shift_pressed) {
153+
remove_at_cursor(RemoveMode::LastWord);
139154
recalculate_textures(true);
140155
return true;
141156
}
142157

143-
remove_at_cursor();
158+
159+
remove_at_cursor(RemoveMode::OneChar);
144160
recalculate_textures(true);
145161
}
146162

147163
return true;
148164
}
149165
case SDLK_LEFT: {
150166
if (m_cursor_position != 0) {
151-
if ((event.key.keysym.mod & KMOD_CTRL) != 0) {
167+
168+
const auto sdl_key = sdl::Key{ event.key.keysym };
169+
170+
const auto ctrl_pressed = sdl_key.has_modifier(sdl::Modifier::CTRL);
171+
172+
if (ctrl_pressed) {
152173
m_cursor_position = 0;
153174
} else {
154175
--m_cursor_position;
@@ -161,7 +182,12 @@ ui::TextInput::handle_event( //NOLINT(readability-function-cognitive-complexity)
161182
case SDLK_RIGHT: {
162183
const u32 current_string_length = static_cast<u32>(utf8::distance(m_text.cbegin(), m_text.cend()));
163184
if (m_cursor_position < current_string_length) {
164-
if ((event.key.keysym.mod & KMOD_CTRL) != 0) {
185+
186+
const auto sdl_key = sdl::Key{ event.key.keysym };
187+
188+
const auto ctrl_pressed = sdl_key.has_modifier(sdl::Modifier::CTRL);
189+
190+
if (ctrl_pressed) {
165191
m_cursor_position = current_string_length;
166192

167193
} else {
@@ -173,7 +199,12 @@ ui::TextInput::handle_event( //NOLINT(readability-function-cognitive-complexity)
173199
return true;
174200
}
175201
case SDLK_v: {
176-
if ((event.key.keysym.mod & KMOD_CTRL) != 0) {
202+
203+
const auto sdl_key = sdl::Key{ event.key.keysym };
204+
205+
const auto ctrl_pressed = sdl_key.has_modifier(sdl::Modifier::CTRL);
206+
207+
if (ctrl_pressed) {
177208

178209
if (SDL_HasClipboardText() != SDL_FALSE) {
179210
char* text = SDL_GetClipboardText();
@@ -193,7 +224,11 @@ ui::TextInput::handle_event( //NOLINT(readability-function-cognitive-complexity)
193224
return false;
194225
}
195226
case SDLK_c: {
196-
if ((event.key.keysym.mod & KMOD_CTRL) != 0) {
227+
const auto sdl_key = sdl::Key{ event.key.keysym };
228+
229+
const auto ctrl_pressed = sdl_key.has_modifier(sdl::Modifier::CTRL);
230+
231+
if (ctrl_pressed) {
197232
const int result = SDL_SetClipboardText(m_text.c_str());
198233
if (result != 0) {
199234
throw helper::MinorError{
@@ -407,27 +442,101 @@ bool ui::TextInput::add_string(const std::string& add) {
407442
return true;
408443
}
409444

410-
bool ui::TextInput::remove_at_cursor() {
445+
446+
bool ui::TextInput::remove_at_cursor(RemoveMode remove_mode) {
411447

412448
if (m_cursor_position == 0) {
413449
return false;
414450
}
415451

452+
if (remove_mode == RemoveMode::All) {
453+
m_text = "";
454+
m_cursor_position = 0;
455+
return true;
456+
}
457+
458+
416459
const u32 current_string_length = static_cast<u32>(utf8::distance(m_text.cbegin(), m_text.cend()));
417460

418461
// cursor_position is the range [0, length] (inclusively !)
419462
if (m_cursor_position > current_string_length) {
420463
throw std::runtime_error("cursor_postion is invalid!");
421464
}
422465

423-
auto start = m_text.begin();
424-
utf8::advance(start, m_cursor_position - 1, m_text.end());
425-
auto end = start;
426-
utf8::next(end, m_text.end());
427-
m_text.erase(start, end);
428466

429-
--m_cursor_position;
430-
return true;
467+
if (remove_mode == RemoveMode::OneChar) {
468+
469+
auto start = m_text.begin();
470+
utf8::advance(start, m_cursor_position - 1, m_text.end());
471+
auto end = start;
472+
utf8::next(end, m_text.end());
473+
m_text.erase(start, end);
474+
475+
--m_cursor_position;
476+
return true;
477+
}
478+
479+
if (remove_mode == RemoveMode::LastWord) {
480+
481+
auto get_char_cat = [](u32 code_point) -> int {
482+
#if defined(_HAVE_ICU_DEP)
483+
// see: https://en.wikipedia.org/wiki/Unicode_character_property#General_Category
484+
return u_charType(code_point);
485+
#else
486+
if (code_point >= 0x80) {
487+
return 1;
488+
}
489+
490+
int int_code_point = static_cast<int>(code_point);
491+
492+
if (isalnum(int_code_point)) {
493+
return 2;
494+
}
495+
496+
if (isblank(int_code_point)) {
497+
return 3;
498+
}
499+
500+
if (iscntrl(int_code_point)) {
501+
return 4;
502+
}
503+
504+
return 5;
505+
506+
#endif
507+
};
508+
509+
auto start = m_text.begin();
510+
utf8::advance(start, m_cursor_position, m_text.end());
511+
auto end = start;
512+
u32 remove_amount = 0;
513+
int char_cat = -1;
514+
515+
while (true) {
516+
auto temp = start;
517+
auto code_point = utf8::prior(temp, m_text.begin());
518+
519+
if (char_cat < 0) {
520+
char_cat = get_char_cat(code_point);
521+
} else if (char_cat != get_char_cat(code_point)) {
522+
break;
523+
}
524+
525+
remove_amount++;
526+
527+
start = temp;
528+
529+
if (temp == m_text.begin()) {
530+
break;
531+
}
532+
}
533+
m_text.erase(start, end);
534+
535+
m_cursor_position -= remove_amount;
536+
return true;
537+
}
538+
539+
utils::unreachable();
431540
}
432541

433542
void ui::TextInput::on_focus() {

src/ui/components/textinput.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
namespace ui {
1515

16-
enum class TextInputMode { Scroll, Scale };
16+
enum class TextInputMode : u8 { Scroll, Scale };
1717

1818
struct TextInput final : public Widget, public Focusable, public Hoverable {
1919
private:
@@ -42,6 +42,8 @@ namespace ui {
4242
bool is_top_level
4343
);
4444

45+
enum class RemoveMode : u8 { LastWord, OneChar, All };
46+
4547
public:
4648
OOPETRIS_GRAPHICS_EXPORTED explicit TextInput(
4749
ServiceProvider* service_provider,
@@ -75,7 +77,7 @@ namespace ui {
7577

7678
bool add_string(const std::string& add);
7779

78-
bool remove_at_cursor();
80+
bool remove_at_cursor(RemoveMode remove_mode);
7981

8082
void on_focus() override;
8183

subprojects/icu.wrap

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[wrap-file]
2+
directory = icu
3+
source_url = https://github.com/unicode-org/icu/releases/download/release-73-2/icu4c-73_2-src.tgz
4+
source_filename = icu4c-73_2-src.tgz
5+
source_hash = 818a80712ed3caacd9b652305e01afc7fa167e6f2e94996da44b90c2ab604ce1
6+
patch_filename = icu_73.2-2_patch.zip
7+
patch_url = https://wrapdb.mesonbuild.com/v2/icu_73.2-2/get_patch
8+
patch_hash = 218a5f20b58b6b2372e636c2eb2d611a898fdc11be17d6c4f35a3cd54d472010
9+
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/icu_73.2-2/icu4c-73_2-src.tgz
10+
wrapdb_version = 73.2-2
11+
12+
[provide]
13+
icu-uc = icuuc_dep
14+
icu-io = icuio_dep
15+
icu-i18n = icui18n_dep
16+
program_names = genbrk, genccode, gencmn

tools/dependencies/meson.build

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,22 @@ utf8cpp_dep = dependency(
119119
required: true,
120120
version: '>=4.0.0',
121121
)
122-
core_lib += {'deps': [core_lib.get('deps'), utf8cpp_dep]}
122+
graphics_lib += {'deps': [graphics_lib.get('deps'), utf8cpp_dep]}
123+
124+
icu_dep = dependency(
125+
'icu-uc',
126+
required: false,
127+
)
128+
129+
if icu_dep.found()
130+
graphics_lib += {
131+
'compile_args': [
132+
graphics_lib.get('compile_args'),
133+
'-D_HAVE_ICU_DEP',
134+
],
135+
'deps': [graphics_lib.get('deps'), icu_dep],
136+
}
137+
endif
123138

124139
is_flatpak_build = false
125140

@@ -339,6 +354,7 @@ if build_application
339354
discord_sdk_dep = dependency(
340355
'discord-game-sdk',
341356
required: not meson.is_cross_build() and get_option('build_installer'),
357+
allow_fallback: true,
342358
# only with msvc we need a static library, all others work without adding __declspec() everywhere
343359
static: c.get_id() == 'msvc',
344360
default_options: c.get_id() != 'msvc' ? {} : {'default_library': 'static'},

tools/install/meson.build

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ if build_application
66
meson.project_source_root() / 'assets',
77
install_dir: 'share/oopetris',
88
install_tag: 'assets',
9-
exclude_files: ['oopetris.desktop.in', 'OOPetris.svg', 'recordings.magic'],
9+
exclude_files: [
10+
'oopetris.desktop.in',
11+
'OOPetris.svg',
12+
'recordings.magic',
13+
'schema',
14+
],
1015
exclude_directories: ['icon'],
1116
)
1217

0 commit comments

Comments
 (0)