Skip to content

Commit

Permalink
fix: use newer sld::Key APi in textinput
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Totto16 committed Oct 28, 2024
1 parent ad6b2e8 commit 90fac21
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 21 deletions.
3 changes: 3 additions & 0 deletions src/manager/event_dispatcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ struct EventDispatcher final {
sdl::Key{ SDLK_RETURN },
sdl::Key{ SDLK_BACKSPACE },
sdl::Key{ SDLK_BACKSPACE, { sdl::Modifier::CTRL } },
sdl::Key{ SDLK_BACKSPACE, { sdl::Modifier::SHIFT } },
sdl::Key{ SDLK_DOWN },
sdl::Key{ SDLK_UP },
sdl::Key{ SDLK_LEFT },
sdl::Key{ SDLK_RIGHT },
sdl::Key{ SDLK_LEFT, { sdl::Modifier::CTRL } },
sdl::Key{ SDLK_RIGHT, { sdl::Modifier::CTRL } },
sdl::Key{ SDLK_ESCAPE },
sdl::Key{ SDLK_TAB },
sdl::Key{ SDLK_c, { sdl::Modifier::CTRL } },
Expand Down
143 changes: 126 additions & 17 deletions src/ui/components/textinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#include "manager/event_dispatcher.hpp"
#include "textinput.hpp"

#if defined(_HAVE_ICU_DEP)
#include <unicode/uchar.h>
#endif


using namespace std::chrono_literals;

Expand Down Expand Up @@ -129,26 +133,43 @@ ui::TextInput::handle_event( //NOLINT(readability-function-cognitive-complexity)
{ EventHandleType::RequestAction, this }
};
}
//TODO(Totto): in some cases this is caught before that, and never triggered
case SDLK_BACKSPACE: {
const auto remove_all = (event.key.keysym.mod & KMOD_CTRL) != 0;
const auto sdl_key = sdl::Key{ event.key.keysym };

const auto ctrl_pressed = sdl_key.has_modifier(sdl::Modifier::CTRL);

const auto shift_pressed = sdl_key.has_modifier(sdl::Modifier::SHIFT);

if (not m_text.empty()) {
if (remove_all) {
m_text = "";
m_cursor_position = 0;
// NOTE: if both modifiers are pressed, we prioritize ctrl
if (ctrl_pressed) {
remove_at_cursor(RemoveMode::All);
recalculate_textures(true);
return true;
}

if (shift_pressed) {
remove_at_cursor(RemoveMode::LastWord);
recalculate_textures(true);
return true;
}

remove_at_cursor();

remove_at_cursor(RemoveMode::OneChar);
recalculate_textures(true);
}

return true;
}
case SDLK_LEFT: {
if (m_cursor_position != 0) {
if ((event.key.keysym.mod & KMOD_CTRL) != 0) {

const auto sdl_key = sdl::Key{ event.key.keysym };

const auto ctrl_pressed = sdl_key.has_modifier(sdl::Modifier::CTRL);

if (ctrl_pressed) {
m_cursor_position = 0;
} else {
--m_cursor_position;
Expand All @@ -161,7 +182,12 @@ ui::TextInput::handle_event( //NOLINT(readability-function-cognitive-complexity)
case SDLK_RIGHT: {
const u32 current_string_length = static_cast<u32>(utf8::distance(m_text.cbegin(), m_text.cend()));
if (m_cursor_position < current_string_length) {
if ((event.key.keysym.mod & KMOD_CTRL) != 0) {

const auto sdl_key = sdl::Key{ event.key.keysym };

const auto ctrl_pressed = sdl_key.has_modifier(sdl::Modifier::CTRL);

if (ctrl_pressed) {
m_cursor_position = current_string_length;

} else {
Expand All @@ -173,7 +199,12 @@ ui::TextInput::handle_event( //NOLINT(readability-function-cognitive-complexity)
return true;
}
case SDLK_v: {
if ((event.key.keysym.mod & KMOD_CTRL) != 0) {

const auto sdl_key = sdl::Key{ event.key.keysym };

const auto ctrl_pressed = sdl_key.has_modifier(sdl::Modifier::CTRL);

if (ctrl_pressed) {

if (SDL_HasClipboardText() != SDL_FALSE) {
char* text = SDL_GetClipboardText();
Expand All @@ -193,7 +224,11 @@ ui::TextInput::handle_event( //NOLINT(readability-function-cognitive-complexity)
return false;
}
case SDLK_c: {
if ((event.key.keysym.mod & KMOD_CTRL) != 0) {
const auto sdl_key = sdl::Key{ event.key.keysym };

const auto ctrl_pressed = sdl_key.has_modifier(sdl::Modifier::CTRL);

if (ctrl_pressed) {
const int result = SDL_SetClipboardText(m_text.c_str());
if (result != 0) {
throw helper::MinorError{
Expand Down Expand Up @@ -407,27 +442,101 @@ bool ui::TextInput::add_string(const std::string& add) {
return true;
}

bool ui::TextInput::remove_at_cursor() {

bool ui::TextInput::remove_at_cursor(RemoveMode remove_mode) {

if (m_cursor_position == 0) {
return false;
}

if (remove_mode == RemoveMode::All) {
m_text = "";
m_cursor_position = 0;
return true;
}


const u32 current_string_length = static_cast<u32>(utf8::distance(m_text.cbegin(), m_text.cend()));

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

auto start = m_text.begin();
utf8::advance(start, m_cursor_position - 1, m_text.end());
auto end = start;
utf8::next(end, m_text.end());
m_text.erase(start, end);

--m_cursor_position;
return true;
if (remove_mode == RemoveMode::OneChar) {

auto start = m_text.begin();
utf8::advance(start, m_cursor_position - 1, m_text.end());
auto end = start;
utf8::next(end, m_text.end());
m_text.erase(start, end);

--m_cursor_position;
return true;
}

if (remove_mode == RemoveMode::LastWord) {

auto get_char_cat = [](u32 code_point) -> int {
#if defined(_HAVE_ICU_DEP)
// see: https://en.wikipedia.org/wiki/Unicode_character_property#General_Category
return u_charType(code_point);
#else
if (code_point >= 0x80) {
return 1;
}

int int_code_point = static_cast<int>(code_point);

if (isalnum(int_code_point)) {
return 2;
}

if (isblank(int_code_point)) {
return 3;
}

if (iscntrl(int_code_point)) {
return 4;
}

return 5;

#endif
};

auto start = m_text.begin();
utf8::advance(start, m_cursor_position, m_text.end());
auto end = start;
u32 remove_amount = 0;
int char_cat = -1;

while (true) {
auto temp = start;
auto code_point = utf8::prior(temp, m_text.begin());

if (char_cat < 0) {
char_cat = get_char_cat(code_point);
} else if (char_cat != get_char_cat(code_point)) {
break;
}

remove_amount++;

start = temp;

if (temp == m_text.begin()) {
break;
}
}
m_text.erase(start, end);

m_cursor_position -= remove_amount;
return true;
}

utils::unreachable();
}

void ui::TextInput::on_focus() {
Expand Down
6 changes: 4 additions & 2 deletions src/ui/components/textinput.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace ui {

enum class TextInputMode { Scroll, Scale };
enum class TextInputMode : u8 { Scroll, Scale };

struct TextInput final : public Widget, public Focusable, public Hoverable {
private:
Expand Down Expand Up @@ -42,6 +42,8 @@ namespace ui {
bool is_top_level
);

enum class RemoveMode : u8 { LastWord, OneChar, All };

public:
OOPETRIS_GRAPHICS_EXPORTED explicit TextInput(
ServiceProvider* service_provider,
Expand Down Expand Up @@ -75,7 +77,7 @@ namespace ui {

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

bool remove_at_cursor();
bool remove_at_cursor(RemoveMode remove_mode);

void on_focus() override;

Expand Down
16 changes: 16 additions & 0 deletions subprojects/icu.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[wrap-file]
directory = icu
source_url = https://github.com/unicode-org/icu/releases/download/release-73-2/icu4c-73_2-src.tgz
source_filename = icu4c-73_2-src.tgz
source_hash = 818a80712ed3caacd9b652305e01afc7fa167e6f2e94996da44b90c2ab604ce1
patch_filename = icu_73.2-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/icu_73.2-2/get_patch
patch_hash = 218a5f20b58b6b2372e636c2eb2d611a898fdc11be17d6c4f35a3cd54d472010
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/icu_73.2-2/icu4c-73_2-src.tgz
wrapdb_version = 73.2-2

[provide]
icu-uc = icuuc_dep
icu-io = icuio_dep
icu-i18n = icui18n_dep
program_names = genbrk, genccode, gencmn
18 changes: 17 additions & 1 deletion tools/dependencies/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,22 @@ utf8cpp_dep = dependency(
required: true,
version: '>=4.0.0',
)
core_lib += {'deps': [core_lib.get('deps'), utf8cpp_dep]}
graphics_lib += {'deps': [graphics_lib.get('deps'), utf8cpp_dep]}

icu_dep = dependency(
'icu-uc',
required: false,
)

if icu_dep.found()
graphics_lib += {
'compile_args': [
graphics_lib.get('compile_args'),
'-D_HAVE_ICU_DEP',
],
'deps': [graphics_lib.get('deps'), icu_dep],
}
endif

is_flatpak_build = false

Expand Down Expand Up @@ -339,6 +354,7 @@ if build_application
discord_sdk_dep = dependency(
'discord-game-sdk',
required: not meson.is_cross_build() and get_option('build_installer'),
allow_fallback: true,
# only with msvc we need a static library, all others work without adding __declspec() everywhere
static: c.get_id() == 'msvc',
default_options: c.get_id() != 'msvc' ? {} : {'default_library': 'static'},
Expand Down
7 changes: 6 additions & 1 deletion tools/install/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ if build_application
meson.project_source_root() / 'assets',
install_dir: 'share/oopetris',
install_tag: 'assets',
exclude_files: ['oopetris.desktop.in', 'OOPetris.svg', 'recordings.magic'],
exclude_files: [
'oopetris.desktop.in',
'OOPetris.svg',
'recordings.magic',
'schema',
],
exclude_directories: ['icon'],
)

Expand Down

0 comments on commit 90fac21

Please sign in to comment.