From 549d30635dfbf87d2981898ab2b80bd7b25ce0d0 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sun, 23 Jul 2023 00:07:16 +0200 Subject: [PATCH 1/5] Use system keyboard in ext apps with symbols --- .../scenes/uart_terminal_scene_config.h | 2 +- .../scenes/uart_terminal_scene_text_input.c | 10 +- .../esp32cam_morseflasher/uart_terminal_app.c | 6 +- .../uart_terminal_app_i.h | 4 +- .../esp32cam_morseflasher/uart_text_input.c | 637 --------------- .../esp32cam_morseflasher/uart_text_input.h | 82 -- .../scenes/uart_terminal_scene_config.h | 2 +- .../scenes/uart_terminal_scene_text_input.c | 12 +- .../uart_terminal/uart_terminal_app.c | 6 +- .../uart_terminal/uart_terminal_app_i.h | 4 +- .../external/uart_terminal/uart_text_input.c | 683 ---------------- .../external/uart_terminal/uart_text_input.h | 82 -- .../scenes/wifi_marauder_scene_text_input.c | 30 +- .../scenes/wifi_marauder_scene_user_input.c | 18 +- .../wifi_marauder_app.c | 6 +- .../wifi_marauder_app_i.h | 4 +- .../wifi_marauder_text_input.c | 756 ------------------ .../wifi_marauder_text_input.h | 83 -- 18 files changed, 56 insertions(+), 2371 deletions(-) delete mode 100644 applications/external/esp32cam_morseflasher/uart_text_input.c delete mode 100644 applications/external/esp32cam_morseflasher/uart_text_input.h delete mode 100644 applications/external/uart_terminal/uart_text_input.c delete mode 100644 applications/external/uart_terminal/uart_text_input.h delete mode 100644 applications/external/wifi_marauder_companion/wifi_marauder_text_input.c delete mode 100644 applications/external/wifi_marauder_companion/wifi_marauder_text_input.h diff --git a/applications/external/esp32cam_morseflasher/scenes/uart_terminal_scene_config.h b/applications/external/esp32cam_morseflasher/scenes/uart_terminal_scene_config.h index febdce167..51310800e 100644 --- a/applications/external/esp32cam_morseflasher/scenes/uart_terminal_scene_config.h +++ b/applications/external/esp32cam_morseflasher/scenes/uart_terminal_scene_config.h @@ -1,3 +1,3 @@ ADD_SCENE(uart_terminal, start, Start) ADD_SCENE(uart_terminal, console_output, ConsoleOutput) -ADD_SCENE(uart_terminal, text_input, UART_TextInput) +ADD_SCENE(uart_terminal, text_input, TextInput) diff --git a/applications/external/esp32cam_morseflasher/scenes/uart_terminal_scene_text_input.c b/applications/external/esp32cam_morseflasher/scenes/uart_terminal_scene_text_input.c index b3b469063..fd33aee78 100644 --- a/applications/external/esp32cam_morseflasher/scenes/uart_terminal_scene_text_input.c +++ b/applications/external/esp32cam_morseflasher/scenes/uart_terminal_scene_text_input.c @@ -23,10 +23,10 @@ void uart_terminal_scene_text_input_on_enter(void* context) { } // Setup view - UART_TextInput* text_input = app->text_input; + TextInput* text_input = app->text_input; // Add help message to header - uart_text_input_set_header_text(text_input, "Send new morse message"); - uart_text_input_set_result_callback( + text_input_set_header_text(text_input, "Send new morse message"); + text_input_set_result_callback( text_input, uart_terminal_scene_text_input_callback, app, @@ -34,6 +34,8 @@ void uart_terminal_scene_text_input_on_enter(void* context) { UART_TERMINAL_TEXT_INPUT_STORE_SIZE, false); + text_input_add_illegal_symbols(text_input); + view_dispatcher_switch_to_view(app->view_dispatcher, UART_TerminalAppViewTextInput); } @@ -56,5 +58,5 @@ bool uart_terminal_scene_text_input_on_event(void* context, SceneManagerEvent ev void uart_terminal_scene_text_input_on_exit(void* context) { UART_TerminalApp* app = context; - uart_text_input_reset(app->text_input); + text_input_reset(app->text_input); } diff --git a/applications/external/esp32cam_morseflasher/uart_terminal_app.c b/applications/external/esp32cam_morseflasher/uart_terminal_app.c index 35719afca..4c811b609 100644 --- a/applications/external/esp32cam_morseflasher/uart_terminal_app.c +++ b/applications/external/esp32cam_morseflasher/uart_terminal_app.c @@ -56,11 +56,11 @@ UART_TerminalApp* uart_terminal_app_alloc() { app->text_box_store = furi_string_alloc(); furi_string_reserve(app->text_box_store, UART_TERMINAL_TEXT_BOX_STORE_SIZE); - app->text_input = uart_text_input_alloc(); + app->text_input = text_input_alloc(); view_dispatcher_add_view( app->view_dispatcher, UART_TerminalAppViewTextInput, - uart_text_input_get_view(app->text_input)); + text_input_get_view(app->text_input)); scene_manager_next_scene(app->scene_manager, UART_TerminalSceneStart); @@ -76,7 +76,7 @@ void uart_terminal_app_free(UART_TerminalApp* app) { view_dispatcher_remove_view(app->view_dispatcher, UART_TerminalAppViewTextInput); text_box_free(app->text_box); furi_string_free(app->text_box_store); - uart_text_input_free(app->text_input); + text_input_free(app->text_input); // View dispatcher view_dispatcher_free(app->view_dispatcher); diff --git a/applications/external/esp32cam_morseflasher/uart_terminal_app_i.h b/applications/external/esp32cam_morseflasher/uart_terminal_app_i.h index 80f78c8ab..6d9b20608 100644 --- a/applications/external/esp32cam_morseflasher/uart_terminal_app_i.h +++ b/applications/external/esp32cam_morseflasher/uart_terminal_app_i.h @@ -9,7 +9,7 @@ #include #include #include -#include "uart_text_input.h" +#include #include #define NUM_MENU_ITEMS (3) @@ -26,7 +26,7 @@ struct UART_TerminalApp { FuriString* text_box_store; size_t text_box_store_strlen; TextBox* text_box; - UART_TextInput* text_input; + TextInput* text_input; VariableItemList* var_item_list; diff --git a/applications/external/esp32cam_morseflasher/uart_text_input.c b/applications/external/esp32cam_morseflasher/uart_text_input.c deleted file mode 100644 index 9a1099468..000000000 --- a/applications/external/esp32cam_morseflasher/uart_text_input.c +++ /dev/null @@ -1,637 +0,0 @@ -#include "uart_text_input.h" -#include -#include "assets_icons.h" -#include - -struct UART_TextInput { - View* view; - FuriTimer* timer; -}; - -typedef struct { - const char text; - const uint8_t x; - const uint8_t y; -} UART_TextInputKey; - -typedef struct { - const char* header; - char* text_buffer; - size_t text_buffer_size; - bool clear_default_text; - - UART_TextInputCallback callback; - void* callback_context; - - uint8_t selected_row; - uint8_t selected_column; - - UART_TextInputValidatorCallback validator_callback; - void* validator_callback_context; - FuriString* validator_text; - bool valadator_message_visible; -} UART_TextInputModel; - -static const uint8_t keyboard_origin_x = 1; -static const uint8_t keyboard_origin_y = 29; -static const uint8_t keyboard_row_count = 4; - -#define ENTER_KEY '\r' -#define BACKSPACE_KEY '\b' - -static const UART_TextInputKey keyboard_keys_row_1[] = { - {'{', 1, 0}, - {'(', 9, 0}, - {'[', 17, 0}, - {'|', 25, 0}, - {'@', 33, 0}, - {'&', 41, 0}, - {'#', 49, 0}, - {';', 57, 0}, - {'^', 65, 0}, - {'*', 73, 0}, - {'`', 81, 0}, - {'"', 89, 0}, - {'~', 97, 0}, - {'\'', 105, 0}, - {'.', 113, 0}, - {'/', 120, 0}, -}; - -static const UART_TextInputKey keyboard_keys_row_2[] = { - {'q', 1, 10}, - {'w', 9, 10}, - {'e', 17, 10}, - {'r', 25, 10}, - {'t', 33, 10}, - {'y', 41, 10}, - {'u', 49, 10}, - {'i', 57, 10}, - {'o', 65, 10}, - {'p', 73, 10}, - {'0', 81, 10}, - {'1', 89, 10}, - {'2', 97, 10}, - {'3', 105, 10}, - {'=', 113, 10}, - {'-', 120, 10}, -}; - -static const UART_TextInputKey keyboard_keys_row_3[] = { - {'a', 1, 21}, - {'s', 9, 21}, - {'d', 18, 21}, - {'f', 25, 21}, - {'g', 33, 21}, - {'h', 41, 21}, - {'j', 49, 21}, - {'k', 57, 21}, - {'l', 65, 21}, - {BACKSPACE_KEY, 72, 13}, - {'4', 89, 21}, - {'5', 97, 21}, - {'6', 105, 21}, - {'$', 113, 21}, - {'%', 120, 21}, - -}; - -static const UART_TextInputKey keyboard_keys_row_4[] = { - {'z', 1, 33}, - {'x', 9, 33}, - {'c', 18, 33}, - {'v', 25, 33}, - {'b', 33, 33}, - {'n', 41, 33}, - {'m', 49, 33}, - {'_', 57, 33}, - {ENTER_KEY, 64, 24}, - {'7', 89, 33}, - {'8', 97, 33}, - {'9', 105, 33}, - {'!', 113, 33}, - {'+', 120, 33}, -}; - -static uint8_t get_row_size(uint8_t row_index) { - uint8_t row_size = 0; - - switch(row_index + 1) { - case 1: - row_size = sizeof(keyboard_keys_row_1) / sizeof(UART_TextInputKey); - break; - case 2: - row_size = sizeof(keyboard_keys_row_2) / sizeof(UART_TextInputKey); - break; - case 3: - row_size = sizeof(keyboard_keys_row_3) / sizeof(UART_TextInputKey); - break; - case 4: - row_size = sizeof(keyboard_keys_row_4) / sizeof(UART_TextInputKey); - break; - } - - return row_size; -} - -static const UART_TextInputKey* get_row(uint8_t row_index) { - const UART_TextInputKey* row = NULL; - - switch(row_index + 1) { - case 1: - row = keyboard_keys_row_1; - break; - case 2: - row = keyboard_keys_row_2; - break; - case 3: - row = keyboard_keys_row_3; - break; - case 4: - row = keyboard_keys_row_4; - break; - } - - return row; -} - -static char get_selected_char(UART_TextInputModel* model) { - return get_row(model->selected_row)[model->selected_column].text; -} - -static bool char_is_lowercase(char letter) { - return (letter >= 0x61 && letter <= 0x7A); -} - -static char char_to_uppercase(const char letter) { - switch(letter) { - case '_': - return 0x20; - break; - case '(': - return 0x29; - break; - case '{': - return 0x7d; - break; - case '[': - return 0x5d; - break; - case '/': - return 0x5c; - break; - case ';': - return 0x3a; - break; - case '.': - return 0x2c; - break; - case '!': - return 0x3f; - break; - case '<': - return 0x3e; - break; - } - if(isalpha(letter)) { - return (letter - 0x20); - } else { - return letter; - } -} - -static void uart_text_input_backspace_cb(UART_TextInputModel* model) { - uint8_t text_length = model->clear_default_text ? 1 : strlen(model->text_buffer); - if(text_length > 0) { - model->text_buffer[text_length - 1] = 0; - } -} - -static void uart_text_input_view_draw_callback(Canvas* canvas, void* _model) { - UART_TextInputModel* model = _model; - uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0; - uint8_t needed_string_width = canvas_width(canvas) - 8; - uint8_t start_pos = 4; - - const char* text = model->text_buffer; - - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - - canvas_draw_str(canvas, 2, 7, model->header); - elements_slightly_rounded_frame(canvas, 1, 8, 126, 12); - - if(canvas_string_width(canvas, text) > needed_string_width) { - canvas_draw_str(canvas, start_pos, 17, "..."); - start_pos += 6; - needed_string_width -= 8; - } - - while(text != 0 && canvas_string_width(canvas, text) > needed_string_width) { - text++; - } - - if(model->clear_default_text) { - elements_slightly_rounded_box( - canvas, start_pos - 1, 14, canvas_string_width(canvas, text) + 2, 10); - canvas_set_color(canvas, ColorWhite); - } else { - canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 1, 18, "|"); - canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 2, 18, "|"); - } - canvas_draw_str(canvas, start_pos, 17, text); - - canvas_set_font(canvas, FontKeyboard); - - for(uint8_t row = 0; row <= keyboard_row_count; row++) { - const uint8_t column_count = get_row_size(row); - const UART_TextInputKey* keys = get_row(row); - - for(size_t column = 0; column < column_count; column++) { - if(keys[column].text == ENTER_KEY) { - canvas_set_color(canvas, ColorBlack); - if(model->selected_row == row && model->selected_column == column) { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeySaveSelected_24x11); - } else { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeySave_24x11); - } - } else if(keys[column].text == BACKSPACE_KEY) { - canvas_set_color(canvas, ColorBlack); - if(model->selected_row == row && model->selected_column == column) { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeyBackspaceSelected_16x9); - } else { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeyBackspace_16x9); - } - } else { - if(model->selected_row == row && model->selected_column == column) { - canvas_set_color(canvas, ColorBlack); - canvas_draw_box( - canvas, - keyboard_origin_x + keys[column].x - 1, - keyboard_origin_y + keys[column].y - 8, - 7, - 10); - canvas_set_color(canvas, ColorWhite); - } else { - canvas_set_color(canvas, ColorBlack); - } - - if(model->clear_default_text || - (text_length == 0 && char_is_lowercase(keys[column].text))) { - canvas_draw_glyph( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - //char_to_uppercase(keys[column].text)); - keys[column].text); - } else { - canvas_draw_glyph( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - keys[column].text); - } - } - } - } - if(model->valadator_message_visible) { - canvas_set_font(canvas, FontSecondary); - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 8, 10, 110, 48); - canvas_set_color(canvas, ColorBlack); - canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42); - canvas_draw_rframe(canvas, 8, 8, 112, 50, 3); - canvas_draw_rframe(canvas, 9, 9, 110, 48, 2); - elements_multiline_text(canvas, 62, 20, furi_string_get_cstr(model->validator_text)); - canvas_set_font(canvas, FontKeyboard); - } -} - -static void - uart_text_input_handle_up(UART_TextInput* uart_text_input, UART_TextInputModel* model) { - UNUSED(uart_text_input); - if(model->selected_row > 0) { - model->selected_row--; - if(model->selected_column > get_row_size(model->selected_row) - 6) { - model->selected_column = model->selected_column + 1; - } - } -} - -static void - uart_text_input_handle_down(UART_TextInput* uart_text_input, UART_TextInputModel* model) { - UNUSED(uart_text_input); - if(model->selected_row < keyboard_row_count - 1) { - model->selected_row++; - if(model->selected_column > get_row_size(model->selected_row) - 4) { - model->selected_column = model->selected_column - 1; - } - } -} - -static void - uart_text_input_handle_left(UART_TextInput* uart_text_input, UART_TextInputModel* model) { - UNUSED(uart_text_input); - if(model->selected_column > 0) { - model->selected_column--; - } else { - model->selected_column = get_row_size(model->selected_row) - 1; - } -} - -static void - uart_text_input_handle_right(UART_TextInput* uart_text_input, UART_TextInputModel* model) { - UNUSED(uart_text_input); - if(model->selected_column < get_row_size(model->selected_row) - 1) { - model->selected_column++; - } else { - model->selected_column = 0; - } -} - -static void uart_text_input_handle_ok( - UART_TextInput* uart_text_input, - UART_TextInputModel* model, - bool shift) { - char selected = get_selected_char(model); - uint8_t text_length = strlen(model->text_buffer); - - if(shift) { - selected = char_to_uppercase(selected); - } - - if(selected == ENTER_KEY) { - if(model->validator_callback && - (!model->validator_callback( - model->text_buffer, model->validator_text, model->validator_callback_context))) { - model->valadator_message_visible = true; - furi_timer_start(uart_text_input->timer, furi_kernel_get_tick_frequency() * 4); - } else if(model->callback != 0 && text_length > 0) { - model->callback(model->callback_context); - } - } else if(selected == BACKSPACE_KEY) { - uart_text_input_backspace_cb(model); - } else { - if(model->clear_default_text) { - text_length = 0; - } - if(text_length < (model->text_buffer_size - 1)) { - if(text_length == 0 && char_is_lowercase(selected)) { - //selected = char_to_uppercase(selected); - } - model->text_buffer[text_length] = selected; - model->text_buffer[text_length + 1] = 0; - } - } - model->clear_default_text = false; -} - -static bool uart_text_input_view_input_callback(InputEvent* event, void* context) { - UART_TextInput* uart_text_input = context; - furi_assert(uart_text_input); - - bool consumed = false; - - // Acquire model - UART_TextInputModel* model = view_get_model(uart_text_input->view); - - if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) && - model->valadator_message_visible) { - model->valadator_message_visible = false; - consumed = true; - } else if(event->type == InputTypeShort) { - consumed = true; - switch(event->key) { - case InputKeyUp: - uart_text_input_handle_up(uart_text_input, model); - break; - case InputKeyDown: - uart_text_input_handle_down(uart_text_input, model); - break; - case InputKeyLeft: - uart_text_input_handle_left(uart_text_input, model); - break; - case InputKeyRight: - uart_text_input_handle_right(uart_text_input, model); - break; - case InputKeyOk: - uart_text_input_handle_ok(uart_text_input, model, false); - break; - default: - consumed = false; - break; - } - } else if(event->type == InputTypeLong) { - consumed = true; - switch(event->key) { - case InputKeyUp: - uart_text_input_handle_up(uart_text_input, model); - break; - case InputKeyDown: - uart_text_input_handle_down(uart_text_input, model); - break; - case InputKeyLeft: - uart_text_input_handle_left(uart_text_input, model); - break; - case InputKeyRight: - uart_text_input_handle_right(uart_text_input, model); - break; - case InputKeyOk: - uart_text_input_handle_ok(uart_text_input, model, true); - break; - case InputKeyBack: - uart_text_input_backspace_cb(model); - break; - default: - consumed = false; - break; - } - } else if(event->type == InputTypeRepeat) { - consumed = true; - switch(event->key) { - case InputKeyUp: - uart_text_input_handle_up(uart_text_input, model); - break; - case InputKeyDown: - uart_text_input_handle_down(uart_text_input, model); - break; - case InputKeyLeft: - uart_text_input_handle_left(uart_text_input, model); - break; - case InputKeyRight: - uart_text_input_handle_right(uart_text_input, model); - break; - case InputKeyBack: - uart_text_input_backspace_cb(model); - break; - default: - consumed = false; - break; - } - } - - // Commit model - view_commit_model(uart_text_input->view, consumed); - - return consumed; -} - -void uart_text_input_timer_callback(void* context) { - furi_assert(context); - UART_TextInput* uart_text_input = context; - - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { model->valadator_message_visible = false; }, - true); -} - -UART_TextInput* uart_text_input_alloc() { - UART_TextInput* uart_text_input = malloc(sizeof(UART_TextInput)); - uart_text_input->view = view_alloc(); - view_set_context(uart_text_input->view, uart_text_input); - view_allocate_model(uart_text_input->view, ViewModelTypeLocking, sizeof(UART_TextInputModel)); - view_set_draw_callback(uart_text_input->view, uart_text_input_view_draw_callback); - view_set_input_callback(uart_text_input->view, uart_text_input_view_input_callback); - - uart_text_input->timer = - furi_timer_alloc(uart_text_input_timer_callback, FuriTimerTypeOnce, uart_text_input); - - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { model->validator_text = furi_string_alloc(); }, - false); - - uart_text_input_reset(uart_text_input); - - return uart_text_input; -} - -void uart_text_input_free(UART_TextInput* uart_text_input) { - furi_assert(uart_text_input); - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { furi_string_free(model->validator_text); }, - false); - - // Send stop command - furi_timer_stop(uart_text_input->timer); - // Release allocated memory - furi_timer_free(uart_text_input->timer); - - view_free(uart_text_input->view); - - free(uart_text_input); -} - -void uart_text_input_reset(UART_TextInput* uart_text_input) { - furi_assert(uart_text_input); - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { - model->text_buffer_size = 0; - model->header = ""; - model->selected_row = 0; - model->selected_column = 0; - model->clear_default_text = false; - model->text_buffer = NULL; - model->text_buffer_size = 0; - model->callback = NULL; - model->callback_context = NULL; - model->validator_callback = NULL; - model->validator_callback_context = NULL; - furi_string_reset(model->validator_text); - model->valadator_message_visible = false; - }, - true); -} - -View* uart_text_input_get_view(UART_TextInput* uart_text_input) { - furi_assert(uart_text_input); - return uart_text_input->view; -} - -void uart_text_input_set_result_callback( - UART_TextInput* uart_text_input, - UART_TextInputCallback callback, - void* callback_context, - char* text_buffer, - size_t text_buffer_size, - bool clear_default_text) { - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { - model->callback = callback; - model->callback_context = callback_context; - model->text_buffer = text_buffer; - model->text_buffer_size = text_buffer_size; - model->clear_default_text = clear_default_text; - if(text_buffer && text_buffer[0] != '\0') { - // Set focus on Save - model->selected_row = 2; - model->selected_column = 8; - } - }, - true); -} - -void uart_text_input_set_validator( - UART_TextInput* uart_text_input, - UART_TextInputValidatorCallback callback, - void* callback_context) { - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { - model->validator_callback = callback; - model->validator_callback_context = callback_context; - }, - true); -} - -UART_TextInputValidatorCallback - uart_text_input_get_validator_callback(UART_TextInput* uart_text_input) { - UART_TextInputValidatorCallback validator_callback = NULL; - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { validator_callback = model->validator_callback; }, - false); - return validator_callback; -} - -void* uart_text_input_get_validator_callback_context(UART_TextInput* uart_text_input) { - void* validator_callback_context = NULL; - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { validator_callback_context = model->validator_callback_context; }, - false); - return validator_callback_context; -} - -void uart_text_input_set_header_text(UART_TextInput* uart_text_input, const char* text) { - with_view_model( - uart_text_input->view, UART_TextInputModel * model, { model->header = text; }, true); -} diff --git a/applications/external/esp32cam_morseflasher/uart_text_input.h b/applications/external/esp32cam_morseflasher/uart_text_input.h deleted file mode 100644 index f3703ed5a..000000000 --- a/applications/external/esp32cam_morseflasher/uart_text_input.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include -#include "uart_validators.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Text input anonymous structure */ -typedef struct UART_TextInput UART_TextInput; -typedef void (*UART_TextInputCallback)(void* context); -typedef bool (*UART_TextInputValidatorCallback)(const char* text, FuriString* error, void* context); - -/** Allocate and initialize text input - * - * This text input is used to enter string - * - * @return UART_TextInput instance - */ -UART_TextInput* uart_text_input_alloc(); - -/** Deinitialize and free text input - * - * @param uart_text_input UART_TextInput instance - */ -void uart_text_input_free(UART_TextInput* uart_text_input); - -/** Clean text input view Note: this function does not free memory - * - * @param uart_text_input Text input instance - */ -void uart_text_input_reset(UART_TextInput* uart_text_input); - -/** Get text input view - * - * @param uart_text_input UART_TextInput instance - * - * @return View instance that can be used for embedding - */ -View* uart_text_input_get_view(UART_TextInput* uart_text_input); - -/** Set text input result callback - * - * @param uart_text_input UART_TextInput instance - * @param callback callback fn - * @param callback_context callback context - * @param text_buffer pointer to YOUR text buffer, that we going - * to modify - * @param text_buffer_size YOUR text buffer size in bytes. Max string - * length will be text_buffer_size-1. - * @param clear_default_text clear text from text_buffer on first OK - * event - */ -void uart_text_input_set_result_callback( - UART_TextInput* uart_text_input, - UART_TextInputCallback callback, - void* callback_context, - char* text_buffer, - size_t text_buffer_size, - bool clear_default_text); - -void uart_text_input_set_validator( - UART_TextInput* uart_text_input, - UART_TextInputValidatorCallback callback, - void* callback_context); - -UART_TextInputValidatorCallback - uart_text_input_get_validator_callback(UART_TextInput* uart_text_input); - -void* uart_text_input_get_validator_callback_context(UART_TextInput* uart_text_input); - -/** Set text input header text - * - * @param uart_text_input UART_TextInput instance - * @param text text to be shown - */ -void uart_text_input_set_header_text(UART_TextInput* uart_text_input, const char* text); - -#ifdef __cplusplus -} -#endif diff --git a/applications/external/uart_terminal/scenes/uart_terminal_scene_config.h b/applications/external/uart_terminal/scenes/uart_terminal_scene_config.h index febdce167..51310800e 100644 --- a/applications/external/uart_terminal/scenes/uart_terminal_scene_config.h +++ b/applications/external/uart_terminal/scenes/uart_terminal_scene_config.h @@ -1,3 +1,3 @@ ADD_SCENE(uart_terminal, start, Start) ADD_SCENE(uart_terminal, console_output, ConsoleOutput) -ADD_SCENE(uart_terminal, text_input, UART_TextInput) +ADD_SCENE(uart_terminal, text_input, TextInput) diff --git a/applications/external/uart_terminal/scenes/uart_terminal_scene_text_input.c b/applications/external/uart_terminal/scenes/uart_terminal_scene_text_input.c index e200ba266..5cd6e7472 100644 --- a/applications/external/uart_terminal/scenes/uart_terminal_scene_text_input.c +++ b/applications/external/uart_terminal/scenes/uart_terminal_scene_text_input.c @@ -23,16 +23,16 @@ void uart_terminal_scene_text_input_on_enter(void* context) { } // Setup view - UART_TextInput* text_input = app->text_input; + TextInput* text_input = app->text_input; // Add help message to header if(0 == strncmp("AT", app->selected_tx_string, strlen("AT"))) { app->TERMINAL_MODE = 1; - uart_text_input_set_header_text(text_input, "Send AT command to UART"); + text_input_set_header_text(text_input, "Send AT command to UART"); } else { app->TERMINAL_MODE = 0; - uart_text_input_set_header_text(text_input, "Send command to UART"); + text_input_set_header_text(text_input, "Send command to UART"); } - uart_text_input_set_result_callback( + text_input_set_result_callback( text_input, uart_terminal_scene_text_input_callback, app, @@ -40,6 +40,8 @@ void uart_terminal_scene_text_input_on_enter(void* context) { UART_TERMINAL_TEXT_INPUT_STORE_SIZE, false); + text_input_add_illegal_symbols(text_input); + view_dispatcher_switch_to_view(app->view_dispatcher, UART_TerminalAppViewTextInput); } @@ -62,5 +64,5 @@ bool uart_terminal_scene_text_input_on_event(void* context, SceneManagerEvent ev void uart_terminal_scene_text_input_on_exit(void* context) { UART_TerminalApp* app = context; - uart_text_input_reset(app->text_input); + text_input_reset(app->text_input); } diff --git a/applications/external/uart_terminal/uart_terminal_app.c b/applications/external/uart_terminal/uart_terminal_app.c index 2c18c5bae..fedab3f64 100644 --- a/applications/external/uart_terminal/uart_terminal_app.c +++ b/applications/external/uart_terminal/uart_terminal_app.c @@ -56,11 +56,11 @@ UART_TerminalApp* uart_terminal_app_alloc() { app->text_box_store = furi_string_alloc(); furi_string_reserve(app->text_box_store, UART_TERMINAL_TEXT_BOX_STORE_SIZE); - app->text_input = uart_text_input_alloc(); + app->text_input = text_input_alloc(); view_dispatcher_add_view( app->view_dispatcher, UART_TerminalAppViewTextInput, - uart_text_input_get_view(app->text_input)); + text_input_get_view(app->text_input)); scene_manager_next_scene(app->scene_manager, UART_TerminalSceneStart); @@ -76,7 +76,7 @@ void uart_terminal_app_free(UART_TerminalApp* app) { view_dispatcher_remove_view(app->view_dispatcher, UART_TerminalAppViewTextInput); text_box_free(app->text_box); furi_string_free(app->text_box_store); - uart_text_input_free(app->text_input); + text_input_free(app->text_input); // View dispatcher view_dispatcher_free(app->view_dispatcher); diff --git a/applications/external/uart_terminal/uart_terminal_app_i.h b/applications/external/uart_terminal/uart_terminal_app_i.h index a0c4bb81f..d90e38998 100644 --- a/applications/external/uart_terminal/uart_terminal_app_i.h +++ b/applications/external/uart_terminal/uart_terminal_app_i.h @@ -10,7 +10,7 @@ #include #include #include -#include "uart_text_input.h" +#include #define NUM_MENU_ITEMS (5) @@ -27,7 +27,7 @@ struct UART_TerminalApp { FuriString* text_box_store; size_t text_box_store_strlen; TextBox* text_box; - UART_TextInput* text_input; + TextInput* text_input; VariableItemList* var_item_list; diff --git a/applications/external/uart_terminal/uart_text_input.c b/applications/external/uart_terminal/uart_text_input.c deleted file mode 100644 index 62884550d..000000000 --- a/applications/external/uart_terminal/uart_text_input.c +++ /dev/null @@ -1,683 +0,0 @@ -#include "uart_text_input.h" -#include -#include -#include "uart_terminal_app_i.h" -#include - -struct UART_TextInput { - View* view; - FuriTimer* timer; -}; - -typedef struct { - const char text; - const uint8_t x; - const uint8_t y; -} UART_TextInputKey; - -typedef struct { - const char* header; - char* text_buffer; - size_t text_buffer_size; - bool clear_default_text; - - UART_TextInputCallback callback; - void* callback_context; - - uint8_t selected_row; - uint8_t selected_column; - - UART_TextInputValidatorCallback validator_callback; - void* validator_callback_context; - FuriString* validator_text; - bool valadator_message_visible; -} UART_TextInputModel; - -static const uint8_t keyboard_origin_x = 1; -static const uint8_t keyboard_origin_y = 29; -static const uint8_t keyboard_row_count = 4; - -#define mode_AT "Send AT command to UART" - -#define ENTER_KEY '\r' -#define BACKSPACE_KEY '\b' - -static const UART_TextInputKey keyboard_keys_row_1[] = { - {'{', 1, 0}, - {'(', 9, 0}, - {'[', 17, 0}, - {'|', 25, 0}, - {'@', 33, 0}, - {'&', 41, 0}, - {'#', 49, 0}, - {';', 57, 0}, - {'^', 65, 0}, - {'*', 73, 0}, - {'`', 81, 0}, - {'"', 89, 0}, - {'~', 97, 0}, - {'\'', 105, 0}, - {'.', 113, 0}, - {'/', 120, 0}, -}; - -static const UART_TextInputKey keyboard_keys_row_2[] = { - {'q', 1, 10}, - {'w', 9, 10}, - {'e', 17, 10}, - {'r', 25, 10}, - {'t', 33, 10}, - {'y', 41, 10}, - {'u', 49, 10}, - {'i', 57, 10}, - {'o', 65, 10}, - {'p', 73, 10}, - {'0', 81, 10}, - {'1', 89, 10}, - {'2', 97, 10}, - {'3', 105, 10}, - {'=', 113, 10}, - {'-', 120, 10}, -}; - -static const UART_TextInputKey keyboard_keys_row_3[] = { - {'a', 1, 21}, - {'s', 9, 21}, - {'d', 18, 21}, - {'f', 25, 21}, - {'g', 33, 21}, - {'h', 41, 21}, - {'j', 49, 21}, - {'k', 57, 21}, - {'l', 65, 21}, - {BACKSPACE_KEY, 72, 13}, - {'4', 89, 21}, - {'5', 97, 21}, - {'6', 105, 21}, - {'$', 113, 21}, - {'%', 120, 21}, - -}; - -static const UART_TextInputKey keyboard_keys_row_4[] = { - {'z', 1, 33}, - {'x', 9, 33}, - {'c', 18, 33}, - {'v', 25, 33}, - {'b', 33, 33}, - {'n', 41, 33}, - {'m', 49, 33}, - {'_', 57, 33}, - {ENTER_KEY, 64, 24}, - {'7', 89, 33}, - {'8', 97, 33}, - {'9', 105, 33}, - {'!', 113, 33}, - {'+', 120, 33}, -}; - -static uint8_t get_row_size(uint8_t row_index) { - uint8_t row_size = 0; - - switch(row_index + 1) { - case 1: - row_size = sizeof(keyboard_keys_row_1) / sizeof(UART_TextInputKey); - break; - case 2: - row_size = sizeof(keyboard_keys_row_2) / sizeof(UART_TextInputKey); - break; - case 3: - row_size = sizeof(keyboard_keys_row_3) / sizeof(UART_TextInputKey); - break; - case 4: - row_size = sizeof(keyboard_keys_row_4) / sizeof(UART_TextInputKey); - break; - } - - return row_size; -} - -static const UART_TextInputKey* get_row(uint8_t row_index) { - const UART_TextInputKey* row = NULL; - - switch(row_index + 1) { - case 1: - row = keyboard_keys_row_1; - break; - case 2: - row = keyboard_keys_row_2; - break; - case 3: - row = keyboard_keys_row_3; - break; - case 4: - row = keyboard_keys_row_4; - break; - } - - return row; -} - -static char get_selected_char(UART_TextInputModel* model) { - return get_row(model->selected_row)[model->selected_column].text; -} - -static bool char_is_lowercase(char letter) { - return (letter >= 0x61 && letter <= 0x7A); -} - -static bool char_is_uppercase(char letter) { - return (letter >= 0x41 && letter <= 0x5A); -} - -static char char_to_lowercase(const char letter) { - switch(letter) { - case ' ': - return 0x5f; - break; - case ')': - return 0x28; - break; - case '}': - return 0x7b; - break; - case ']': - return 0x5b; - break; - case '\\': - return 0x2f; - break; - case ':': - return 0x3b; - break; - case ',': - return 0x2e; - break; - case '?': - return 0x21; - break; - case '>': - return 0x3c; - break; - } - if(char_is_uppercase(letter)) { - return (letter + 0x20); - } else { - return letter; - } -} - -static char char_to_uppercase(const char letter) { - switch(letter) { - case '_': - return 0x20; - break; - case '(': - return 0x29; - break; - case '{': - return 0x7d; - break; - case '[': - return 0x5d; - break; - case '/': - return 0x5c; - break; - case ';': - return 0x3a; - break; - case '.': - return 0x2c; - break; - case '!': - return 0x3f; - break; - case '<': - return 0x3e; - break; - } - if(char_is_lowercase(letter)) { - return (letter - 0x20); - } else { - return letter; - } -} - -static void uart_text_input_backspace_cb(UART_TextInputModel* model) { - uint8_t text_length = model->clear_default_text ? 1 : strlen(model->text_buffer); - if(text_length > 0) { - model->text_buffer[text_length - 1] = 0; - } -} - -static void uart_text_input_view_draw_callback(Canvas* canvas, void* _model) { - UART_TextInputModel* model = _model; - //uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0; - uint8_t needed_string_width = canvas_width(canvas) - 8; - uint8_t start_pos = 4; - - const char* text = model->text_buffer; - - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - - canvas_draw_str(canvas, 2, 7, model->header); - elements_slightly_rounded_frame(canvas, 1, 8, 126, 12); - - if(canvas_string_width(canvas, text) > needed_string_width) { - canvas_draw_str(canvas, start_pos, 17, "..."); - start_pos += 6; - needed_string_width -= 8; - } - - while(text != 0 && canvas_string_width(canvas, text) > needed_string_width) { - text++; - } - - if(model->clear_default_text) { - elements_slightly_rounded_box( - canvas, start_pos - 1, 14, canvas_string_width(canvas, text) + 2, 10); - canvas_set_color(canvas, ColorWhite); - } else { - canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 1, 18, "|"); - canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 2, 18, "|"); - } - canvas_draw_str(canvas, start_pos, 17, text); - - canvas_set_font(canvas, FontKeyboard); - - for(uint8_t row = 0; row <= keyboard_row_count; row++) { - const uint8_t column_count = get_row_size(row); - const UART_TextInputKey* keys = get_row(row); - - for(size_t column = 0; column < column_count; column++) { - if(keys[column].text == ENTER_KEY) { - canvas_set_color(canvas, ColorBlack); - if(model->selected_row == row && model->selected_column == column) { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeySaveSelected_24x11); - } else { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeySave_24x11); - } - } else if(keys[column].text == BACKSPACE_KEY) { - canvas_set_color(canvas, ColorBlack); - if(model->selected_row == row && model->selected_column == column) { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeyBackspaceSelected_16x9); - } else { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeyBackspace_16x9); - } - } else { - if(model->selected_row == row && model->selected_column == column) { - canvas_set_color(canvas, ColorBlack); - canvas_draw_box( - canvas, - keyboard_origin_x + keys[column].x - 1, - keyboard_origin_y + keys[column].y - 8, - 7, - 10); - canvas_set_color(canvas, ColorWhite); - } else { - canvas_set_color(canvas, ColorBlack); - } - if(0 == strcmp(model->header, mode_AT)) { - canvas_draw_glyph( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - char_to_uppercase(keys[column].text)); - } else { - canvas_draw_glyph( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - keys[column].text); - } - } - } - } - if(model->valadator_message_visible) { - canvas_set_font(canvas, FontSecondary); - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 8, 10, 110, 48); - canvas_set_color(canvas, ColorBlack); - canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42); - canvas_draw_rframe(canvas, 8, 8, 112, 50, 3); - canvas_draw_rframe(canvas, 9, 9, 110, 48, 2); - elements_multiline_text(canvas, 62, 20, furi_string_get_cstr(model->validator_text)); - canvas_set_font(canvas, FontKeyboard); - } -} - -static void - uart_text_input_handle_up(UART_TextInput* uart_text_input, UART_TextInputModel* model) { - UNUSED(uart_text_input); - if(model->selected_row > 0) { - model->selected_row--; - if(model->selected_column > get_row_size(model->selected_row) - 6) { - model->selected_column = model->selected_column + 1; - } - } -} - -static void - uart_text_input_handle_down(UART_TextInput* uart_text_input, UART_TextInputModel* model) { - UNUSED(uart_text_input); - if(model->selected_row < keyboard_row_count - 1) { - model->selected_row++; - if(model->selected_column > get_row_size(model->selected_row) - 4) { - model->selected_column = model->selected_column - 1; - } - } -} - -static void - uart_text_input_handle_left(UART_TextInput* uart_text_input, UART_TextInputModel* model) { - UNUSED(uart_text_input); - if(model->selected_column > 0) { - model->selected_column--; - } else { - model->selected_column = get_row_size(model->selected_row) - 1; - } -} - -static void - uart_text_input_handle_right(UART_TextInput* uart_text_input, UART_TextInputModel* model) { - UNUSED(uart_text_input); - if(model->selected_column < get_row_size(model->selected_row) - 1) { - model->selected_column++; - } else { - model->selected_column = 0; - } -} - -static void uart_text_input_handle_ok( - UART_TextInput* uart_text_input, - UART_TextInputModel* model, - bool shift) { - char selected = get_selected_char(model); - uint8_t text_length = strlen(model->text_buffer); - - if(0 == strcmp(model->header, mode_AT)) { - selected = char_to_uppercase(selected); - } - - if(shift) { - if(0 == strcmp(model->header, mode_AT)) { - selected = char_to_lowercase(selected); - } else { - selected = char_to_uppercase(selected); - } - } - - if(selected == ENTER_KEY) { - if(model->validator_callback && - (!model->validator_callback( - model->text_buffer, model->validator_text, model->validator_callback_context))) { - model->valadator_message_visible = true; - furi_timer_start(uart_text_input->timer, furi_kernel_get_tick_frequency() * 4); - } else if(model->callback != 0 && text_length > 0) { - model->callback(model->callback_context); - } - } else if(selected == BACKSPACE_KEY) { - uart_text_input_backspace_cb(model); - } else { - if(model->clear_default_text) { - text_length = 0; - } - if(text_length < (model->text_buffer_size - 1)) { - model->text_buffer[text_length] = selected; - model->text_buffer[text_length + 1] = 0; - } - } - model->clear_default_text = false; -} - -static bool uart_text_input_view_input_callback(InputEvent* event, void* context) { - UART_TextInput* uart_text_input = context; - furi_assert(uart_text_input); - - bool consumed = false; - - // Acquire model - UART_TextInputModel* model = view_get_model(uart_text_input->view); - - if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) && - model->valadator_message_visible) { - model->valadator_message_visible = false; - consumed = true; - } else if(event->type == InputTypeShort) { - consumed = true; - switch(event->key) { - case InputKeyUp: - uart_text_input_handle_up(uart_text_input, model); - break; - case InputKeyDown: - uart_text_input_handle_down(uart_text_input, model); - break; - case InputKeyLeft: - uart_text_input_handle_left(uart_text_input, model); - break; - case InputKeyRight: - uart_text_input_handle_right(uart_text_input, model); - break; - case InputKeyOk: - uart_text_input_handle_ok(uart_text_input, model, false); - break; - default: - consumed = false; - break; - } - } else if(event->type == InputTypeLong) { - consumed = true; - switch(event->key) { - case InputKeyUp: - uart_text_input_handle_up(uart_text_input, model); - break; - case InputKeyDown: - uart_text_input_handle_down(uart_text_input, model); - break; - case InputKeyLeft: - uart_text_input_handle_left(uart_text_input, model); - break; - case InputKeyRight: - uart_text_input_handle_right(uart_text_input, model); - break; - case InputKeyOk: - uart_text_input_handle_ok(uart_text_input, model, true); - break; - case InputKeyBack: - uart_text_input_backspace_cb(model); - break; - default: - consumed = false; - break; - } - } else if(event->type == InputTypeRepeat) { - consumed = true; - switch(event->key) { - case InputKeyUp: - uart_text_input_handle_up(uart_text_input, model); - break; - case InputKeyDown: - uart_text_input_handle_down(uart_text_input, model); - break; - case InputKeyLeft: - uart_text_input_handle_left(uart_text_input, model); - break; - case InputKeyRight: - uart_text_input_handle_right(uart_text_input, model); - break; - case InputKeyBack: - uart_text_input_backspace_cb(model); - break; - default: - consumed = false; - break; - } - } - - // Commit model - view_commit_model(uart_text_input->view, consumed); - - return consumed; -} - -void uart_text_input_timer_callback(void* context) { - furi_assert(context); - UART_TextInput* uart_text_input = context; - - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { model->valadator_message_visible = false; }, - true); -} - -UART_TextInput* uart_text_input_alloc() { - UART_TextInput* uart_text_input = malloc(sizeof(UART_TextInput)); - uart_text_input->view = view_alloc(); - view_set_context(uart_text_input->view, uart_text_input); - view_allocate_model(uart_text_input->view, ViewModelTypeLocking, sizeof(UART_TextInputModel)); - view_set_draw_callback(uart_text_input->view, uart_text_input_view_draw_callback); - view_set_input_callback(uart_text_input->view, uart_text_input_view_input_callback); - - uart_text_input->timer = - furi_timer_alloc(uart_text_input_timer_callback, FuriTimerTypeOnce, uart_text_input); - - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { model->validator_text = furi_string_alloc(); }, - false); - - uart_text_input_reset(uart_text_input); - - return uart_text_input; -} - -void uart_text_input_free(UART_TextInput* uart_text_input) { - furi_assert(uart_text_input); - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { furi_string_free(model->validator_text); }, - false); - - // Send stop command - furi_timer_stop(uart_text_input->timer); - // Release allocated memory - furi_timer_free(uart_text_input->timer); - - view_free(uart_text_input->view); - - free(uart_text_input); -} - -void uart_text_input_reset(UART_TextInput* uart_text_input) { - furi_assert(uart_text_input); - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { - model->text_buffer_size = 0; - model->header = ""; - model->selected_row = 0; - model->selected_column = 0; - model->clear_default_text = false; - model->text_buffer = NULL; - model->text_buffer_size = 0; - model->callback = NULL; - model->callback_context = NULL; - model->validator_callback = NULL; - model->validator_callback_context = NULL; - furi_string_reset(model->validator_text); - model->valadator_message_visible = false; - }, - true); -} - -View* uart_text_input_get_view(UART_TextInput* uart_text_input) { - furi_assert(uart_text_input); - return uart_text_input->view; -} - -void uart_text_input_set_result_callback( - UART_TextInput* uart_text_input, - UART_TextInputCallback callback, - void* callback_context, - char* text_buffer, - size_t text_buffer_size, - bool clear_default_text) { - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { - model->callback = callback; - model->callback_context = callback_context; - model->text_buffer = text_buffer; - model->text_buffer_size = text_buffer_size; - model->clear_default_text = clear_default_text; - if(text_buffer && text_buffer[0] != '\0') { - // Set focus on Save - model->selected_row = 2; - model->selected_column = 8; - } - }, - true); -} - -void uart_text_input_set_validator( - UART_TextInput* uart_text_input, - UART_TextInputValidatorCallback callback, - void* callback_context) { - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { - model->validator_callback = callback; - model->validator_callback_context = callback_context; - }, - true); -} - -UART_TextInputValidatorCallback - uart_text_input_get_validator_callback(UART_TextInput* uart_text_input) { - UART_TextInputValidatorCallback validator_callback = NULL; - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { validator_callback = model->validator_callback; }, - false); - return validator_callback; -} - -void* uart_text_input_get_validator_callback_context(UART_TextInput* uart_text_input) { - void* validator_callback_context = NULL; - with_view_model( - uart_text_input->view, - UART_TextInputModel * model, - { validator_callback_context = model->validator_callback_context; }, - false); - return validator_callback_context; -} - -void uart_text_input_set_header_text(UART_TextInput* uart_text_input, const char* text) { - with_view_model( - uart_text_input->view, UART_TextInputModel * model, { model->header = text; }, true); -} diff --git a/applications/external/uart_terminal/uart_text_input.h b/applications/external/uart_terminal/uart_text_input.h deleted file mode 100644 index f3703ed5a..000000000 --- a/applications/external/uart_terminal/uart_text_input.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include -#include "uart_validators.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Text input anonymous structure */ -typedef struct UART_TextInput UART_TextInput; -typedef void (*UART_TextInputCallback)(void* context); -typedef bool (*UART_TextInputValidatorCallback)(const char* text, FuriString* error, void* context); - -/** Allocate and initialize text input - * - * This text input is used to enter string - * - * @return UART_TextInput instance - */ -UART_TextInput* uart_text_input_alloc(); - -/** Deinitialize and free text input - * - * @param uart_text_input UART_TextInput instance - */ -void uart_text_input_free(UART_TextInput* uart_text_input); - -/** Clean text input view Note: this function does not free memory - * - * @param uart_text_input Text input instance - */ -void uart_text_input_reset(UART_TextInput* uart_text_input); - -/** Get text input view - * - * @param uart_text_input UART_TextInput instance - * - * @return View instance that can be used for embedding - */ -View* uart_text_input_get_view(UART_TextInput* uart_text_input); - -/** Set text input result callback - * - * @param uart_text_input UART_TextInput instance - * @param callback callback fn - * @param callback_context callback context - * @param text_buffer pointer to YOUR text buffer, that we going - * to modify - * @param text_buffer_size YOUR text buffer size in bytes. Max string - * length will be text_buffer_size-1. - * @param clear_default_text clear text from text_buffer on first OK - * event - */ -void uart_text_input_set_result_callback( - UART_TextInput* uart_text_input, - UART_TextInputCallback callback, - void* callback_context, - char* text_buffer, - size_t text_buffer_size, - bool clear_default_text); - -void uart_text_input_set_validator( - UART_TextInput* uart_text_input, - UART_TextInputValidatorCallback callback, - void* callback_context); - -UART_TextInputValidatorCallback - uart_text_input_get_validator_callback(UART_TextInput* uart_text_input); - -void* uart_text_input_get_validator_callback_context(UART_TextInput* uart_text_input); - -/** Set text input header text - * - * @param uart_text_input UART_TextInput instance - * @param text text to be shown - */ -void uart_text_input_set_header_text(UART_TextInput* uart_text_input, const char* text); - -#ifdef __cplusplus -} -#endif diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c index 66a508f66..ec4b97cc5 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_text_input.c @@ -44,26 +44,26 @@ void wifi_marauder_scene_text_input_on_enter(void* context) { } // Setup view - WIFI_TextInput* text_input = app->text_input; + TextInput* text_input = app->text_input; // Add help message to header if(app->flash_mode) { - wifi_text_input_set_header_text(text_input, "Enter destination address"); + text_input_set_header_text(text_input, "Enter destination address"); } else if(app->special_case_input_step == 1) { - wifi_text_input_set_header_text(text_input, "Enter source MAC"); + text_input_set_header_text(text_input, "Enter source MAC"); } else if(0 == strncmp("ssid -a -g", app->selected_tx_string, strlen("ssid -a -g"))) { - wifi_text_input_set_header_text(text_input, "Enter # SSIDs to generate"); + text_input_set_header_text(text_input, "Enter # SSIDs to generate"); } else if(0 == strncmp("ssid -a -n", app->selected_tx_string, strlen("ssid -a -n"))) { - wifi_text_input_set_header_text(text_input, "Enter SSID name to add"); + text_input_set_header_text(text_input, "Enter SSID name to add"); } else if(0 == strncmp("ssid -r", app->selected_tx_string, strlen("ssid -r"))) { - wifi_text_input_set_header_text(text_input, "Remove target from SSID list"); + text_input_set_header_text(text_input, "Remove target from SSID list"); } else if(0 == strncmp("select -a", app->selected_tx_string, strlen("select -a"))) { - wifi_text_input_set_header_text(text_input, "Add target from AP list"); + text_input_set_header_text(text_input, "Add target from AP list"); } else if(0 == strncmp("select -s", app->selected_tx_string, strlen("select -s"))) { - wifi_text_input_set_header_text(text_input, "Add target from SSID list"); + text_input_set_header_text(text_input, "Add target from SSID list"); } else { - wifi_text_input_set_header_text(text_input, "Add command arguments"); + text_input_set_header_text(text_input, "Add command arguments"); } - wifi_text_input_set_result_callback( + text_input_set_result_callback( text_input, wifi_marauder_scene_text_input_callback, app, @@ -71,6 +71,8 @@ void wifi_marauder_scene_text_input_on_enter(void* context) { WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE, false); + text_input_add_illegal_symbols(text_input); + view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewTextInput); } @@ -86,7 +88,7 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev consumed = true; } else if(event.event == WifiMarauderEventSaveSourceMac) { if(12 != strlen(app->text_input_store)) { - wifi_text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!"); + text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!"); } else { snprintf( app->special_case_input_src_addr, @@ -108,12 +110,12 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev // Advance scene to input destination MAC, clear text input app->special_case_input_step = 2; bzero(app->text_input_store, WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE); - wifi_text_input_set_header_text(app->text_input, "Enter destination MAC"); + text_input_set_header_text(app->text_input, "Enter destination MAC"); } consumed = true; } else if(event.event == WifiMarauderEventSaveDestinationMac) { if(12 != strlen(app->text_input_store)) { - wifi_text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!"); + text_input_set_header_text(app->text_input, "MAC must be 12 hex chars!"); } else { snprintf( app->special_case_input_dst_addr, @@ -152,5 +154,5 @@ bool wifi_marauder_scene_text_input_on_event(void* context, SceneManagerEvent ev void wifi_marauder_scene_text_input_on_exit(void* context) { WifiMarauderApp* app = context; - wifi_text_input_reset(app->text_input); + text_input_reset(app->text_input); } diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_user_input.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_user_input.c index 3d5697caf..17679a518 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_user_input.c +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_user_input.c @@ -100,8 +100,8 @@ void wifi_marauder_scene_user_input_on_enter(void* context) { switch(app->user_input_type) { // Loads the string value of the reference case WifiMarauderUserInputTypeString: - wifi_text_input_set_header_text(app->text_input, "Enter value:"); - wifi_text_input_set_validator(app->text_input, NULL, app); + text_input_set_header_text(app->text_input, "Enter value:"); + text_input_set_validator(app->text_input, NULL, app); if(app->user_input_string_reference != NULL) { strncpy( app->text_input_store, @@ -111,8 +111,8 @@ void wifi_marauder_scene_user_input_on_enter(void* context) { break; // Loads the numerical value of the reference case WifiMarauderUserInputTypeNumber: - wifi_text_input_set_header_text(app->text_input, "Enter a valid number:"); - wifi_text_input_set_validator( + text_input_set_header_text(app->text_input, "Enter a valid number:"); + text_input_set_validator( app->text_input, wifi_marauder_scene_user_input_validator_number_callback, app); if(app->user_input_number_reference != NULL) { char number_str[32]; @@ -122,8 +122,8 @@ void wifi_marauder_scene_user_input_on_enter(void* context) { break; // File name case WifiMarauderUserInputTypeFileName: - wifi_text_input_set_header_text(app->text_input, "Enter file name:"); - wifi_text_input_set_validator( + text_input_set_header_text(app->text_input, "Enter file name:"); + text_input_set_validator( app->text_input, wifi_marauder_scene_user_input_validator_file_callback, app); break; default: @@ -131,7 +131,7 @@ void wifi_marauder_scene_user_input_on_enter(void* context) { return; } - wifi_text_input_set_result_callback( + text_input_set_result_callback( app->text_input, wifi_marauder_scene_user_input_ok_callback, app, @@ -139,6 +139,8 @@ void wifi_marauder_scene_user_input_on_enter(void* context) { WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE, false); + text_input_add_illegal_symbols(text_input); + view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewTextInput); } @@ -151,5 +153,5 @@ bool wifi_marauder_scene_user_input_on_event(void* context, SceneManagerEvent ev void wifi_marauder_scene_user_input_on_exit(void* context) { WifiMarauderApp* app = context; memset(app->text_input_store, 0, sizeof(app->text_input_store)); - wifi_text_input_reset(app->text_input); + text_input_reset(app->text_input); } diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.c b/applications/external/wifi_marauder_companion/wifi_marauder_app.c index a9faffb82..87a923876 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.c +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.c @@ -66,11 +66,11 @@ WifiMarauderApp* wifi_marauder_app_alloc() { app->text_box_store = furi_string_alloc(); furi_string_reserve(app->text_box_store, WIFI_MARAUDER_TEXT_BOX_STORE_SIZE); - app->text_input = wifi_text_input_alloc(); + app->text_input = text_input_alloc(); view_dispatcher_add_view( app->view_dispatcher, WifiMarauderAppViewTextInput, - wifi_text_input_get_view(app->text_input)); + text_input_get_view(app->text_input)); app->widget = widget_alloc(); view_dispatcher_add_view( @@ -153,7 +153,7 @@ void wifi_marauder_app_free(WifiMarauderApp* app) { widget_free(app->widget); text_box_free(app->text_box); furi_string_free(app->text_box_store); - wifi_text_input_free(app->text_input); + text_input_free(app->text_input); submenu_free(app->submenu); variable_item_list_free(app->var_item_list); storage_file_free(app->capture_file); diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h index 10301e544..15d159450 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app_i.h @@ -19,7 +19,7 @@ #include #include #include -#include "wifi_marauder_text_input.h" +#include #include #include @@ -69,7 +69,7 @@ struct WifiMarauderApp { FuriString* text_box_store; size_t text_box_store_strlen; TextBox* text_box; - WIFI_TextInput* text_input; + TextInput* text_input; Storage* storage; File* capture_file; File* log_file; diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_text_input.c b/applications/external/wifi_marauder_companion/wifi_marauder_text_input.c deleted file mode 100644 index b5ab1d32e..000000000 --- a/applications/external/wifi_marauder_companion/wifi_marauder_text_input.c +++ /dev/null @@ -1,756 +0,0 @@ -#include "wifi_marauder_text_input.h" -#include -#include "esp32_wifi_marauder_icons.h" -#include "wifi_marauder_app_i.h" -#include - -struct WIFI_TextInput { - View* view; - FuriTimer* timer; -}; - -typedef struct { - const char text; - const uint8_t x; - const uint8_t y; -} WIFI_TextInputKey; - -typedef struct { - const WIFI_TextInputKey* rows[3]; - const uint8_t keyboard_index; -} Keyboard; - -typedef struct { - const char* header; - char* text_buffer; - size_t text_buffer_size; - size_t minimum_length; - bool clear_default_text; - - bool cursor_select; - size_t cursor_pos; - - WIFI_TextInputCallback callback; - void* callback_context; - - uint8_t selected_row; - uint8_t selected_column; - uint8_t selected_keyboard; - - WIFI_TextInputValidatorCallback validator_callback; - void* validator_callback_context; - FuriString* validator_text; - bool validator_message_visible; -} WIFI_TextInputModel; - -static const uint8_t keyboard_origin_x = 1; -static const uint8_t keyboard_origin_y = 29; -static const uint8_t keyboard_row_count = 3; -static const uint8_t keyboard_count = 2; - -#define ENTER_KEY '\r' -#define BACKSPACE_KEY '\b' -#define SWITCH_KEYBOARD_KEY 0xfe - -static const WIFI_TextInputKey keyboard_keys_row_1[] = { - {'q', 1, 8}, - {'w', 10, 8}, - {'e', 19, 8}, - {'r', 28, 8}, - {'t', 37, 8}, - {'y', 46, 8}, - {'u', 55, 8}, - {'i', 64, 8}, - {'o', 73, 8}, - {'p', 82, 8}, - {'0', 91, 8}, - {'1', 100, 8}, - {'2', 110, 8}, - {'3', 120, 8}, -}; - -static const WIFI_TextInputKey keyboard_keys_row_2[] = { - {'a', 1, 20}, - {'s', 10, 20}, - {'d', 19, 20}, - {'f', 28, 20}, - {'g', 37, 20}, - {'h', 46, 20}, - {'j', 55, 20}, - {'k', 64, 20}, - {'l', 73, 20}, - {BACKSPACE_KEY, 82, 12}, - {'4', 100, 20}, - {'5', 110, 20}, - {'6', 120, 20}, -}; - -static const WIFI_TextInputKey keyboard_keys_row_3[] = { - {SWITCH_KEYBOARD_KEY, 1, 23}, - {'z', 13, 32}, - {'x', 21, 32}, - {'c', 28, 32}, - {'v', 36, 32}, - {'b', 44, 32}, - {'n', 52, 32}, - {'m', 59, 32}, - {'_', 67, 32}, - {ENTER_KEY, 74, 23}, - {'7', 100, 32}, - {'8', 110, 32}, - {'9', 120, 32}, -}; - -static const WIFI_TextInputKey symbol_keyboard_keys_row_1[] = { - {'!', 2, 8}, - {'@', 12, 8}, - {'#', 22, 8}, - {'$', 32, 8}, - {'%', 42, 8}, - {'^', 52, 8}, - {'&', 62, 8}, - {'(', 71, 8}, - {')', 81, 8}, - {'0', 91, 8}, - {'1', 100, 8}, - {'2', 110, 8}, - {'3', 120, 8}, -}; - -static const WIFI_TextInputKey symbol_keyboard_keys_row_2[] = { - {'~', 2, 20}, - {'+', 12, 20}, - {'-', 22, 20}, - {'=', 32, 20}, - {'[', 42, 20}, - {']', 52, 20}, - {'{', 62, 20}, - {'}', 72, 20}, - {BACKSPACE_KEY, 82, 12}, - {'4', 100, 20}, - {'5', 110, 20}, - {'6', 120, 20}, -}; - -static const WIFI_TextInputKey symbol_keyboard_keys_row_3[] = { - {SWITCH_KEYBOARD_KEY, 1, 23}, - {'.', 15, 32}, - {',', 29, 32}, - {':', 41, 32}, - {'/', 53, 32}, - {'\'', 65, 32}, - {ENTER_KEY, 74, 23}, - {'7', 100, 32}, - {'8', 110, 32}, - {'9', 120, 32}, -}; - -static const Keyboard keyboard = { - .rows = - { - keyboard_keys_row_1, - keyboard_keys_row_2, - keyboard_keys_row_3, - }, - .keyboard_index = 0, -}; - -static const Keyboard symbol_keyboard = { - .rows = - { - symbol_keyboard_keys_row_1, - symbol_keyboard_keys_row_2, - symbol_keyboard_keys_row_3, - }, - .keyboard_index = 1, -}; - -static const Keyboard* keyboards[] = { - &keyboard, - &symbol_keyboard, -}; - -static void switch_keyboard(WIFI_TextInputModel* model) { - model->selected_keyboard = (model->selected_keyboard + 1) % keyboard_count; -} - -static uint8_t get_row_size(const Keyboard* keyboard, uint8_t row_index) { - uint8_t row_size = 0; - if(keyboard == &symbol_keyboard) { - switch(row_index + 1) { - case 1: - row_size = COUNT_OF(symbol_keyboard_keys_row_1); - break; - case 2: - row_size = COUNT_OF(symbol_keyboard_keys_row_2); - break; - case 3: - row_size = COUNT_OF(symbol_keyboard_keys_row_3); - break; - default: - furi_crash(NULL); - } - } else { - switch(row_index + 1) { - case 1: - row_size = COUNT_OF(keyboard_keys_row_1); - break; - case 2: - row_size = COUNT_OF(keyboard_keys_row_2); - break; - case 3: - row_size = COUNT_OF(keyboard_keys_row_3); - break; - default: - furi_crash(NULL); - } - } - - return row_size; -} - -static const WIFI_TextInputKey* get_row(const Keyboard* keyboard, uint8_t row_index) { - const WIFI_TextInputKey* row = NULL; - if(row_index < 3) { - row = keyboard->rows[row_index]; - } else { - furi_crash(NULL); - } - - return row; -} - -static char get_selected_char(WIFI_TextInputModel* model) { - return get_row( - keyboards[model->selected_keyboard], model->selected_row)[model->selected_column] - .text; -} - -static bool char_is_lowercase(char letter) { - return (letter >= 0x61 && letter <= 0x7A); -} - -static char char_to_uppercase(const char letter) { - if(letter == '_') { - return 0x20; - } else if(letter == ':') { - return 0x3B; - } else if(letter == '/') { - return 0x5C; - } else if(letter == '\'') { - return 0x60; - } else if(char_is_lowercase(letter)) { - return (letter - 0x20); - } else { - return letter; - } -} - -static void wifi_text_input_backspace_cb(WIFI_TextInputModel* model) { - if(model->clear_default_text) { - model->text_buffer[0] = 0; - model->cursor_pos = 0; - } else if(model->cursor_pos > 0) { - char* move = model->text_buffer + model->cursor_pos; - memmove(move - 1, move, strlen(move) + 1); - model->cursor_pos--; - } -} - -static void wifi_text_input_view_draw_callback(Canvas* canvas, void* _model) { - WIFI_TextInputModel* model = _model; - uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0; - uint8_t needed_string_width = canvas_width(canvas) - 8; - uint8_t start_pos = 4; - - model->cursor_pos = model->cursor_pos > text_length ? text_length : model->cursor_pos; - size_t cursor_pos = model->cursor_pos; - - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - - canvas_draw_str(canvas, 2, 8, model->header); - elements_slightly_rounded_frame(canvas, 1, 12, 126, 15); - - char buf[model->text_buffer_size + 1]; - if(model->text_buffer) { - strlcpy(buf, model->text_buffer, sizeof(buf)); - } - char* str = buf; - - if(model->clear_default_text) { - elements_slightly_rounded_box( - canvas, start_pos - 1, 14, canvas_string_width(canvas, str) + 2, 10); - canvas_set_color(canvas, ColorWhite); - } else { - char* move = str + cursor_pos; - memmove(move + 1, move, strlen(move) + 1); - str[cursor_pos] = '|'; - } - - if(cursor_pos > 0 && canvas_string_width(canvas, str) > needed_string_width) { - canvas_draw_str(canvas, start_pos, 22, "..."); - start_pos += 6; - needed_string_width -= 8; - for(uint32_t off = 0; - strlen(str) && canvas_string_width(canvas, str) > needed_string_width && - off < cursor_pos; - off++) { - str++; - } - } - - if(canvas_string_width(canvas, str) > needed_string_width) { - needed_string_width -= 4; - size_t len = strlen(str); - while(len && canvas_string_width(canvas, str) > needed_string_width) { - str[len--] = '\0'; - } - strcat(str, "..."); - } - - canvas_draw_str(canvas, start_pos, 22, str); - - canvas_set_font(canvas, FontKeyboard); - - for(uint8_t row = 0; row < keyboard_row_count; row++) { - const uint8_t column_count = get_row_size(keyboards[model->selected_keyboard], row); - const WIFI_TextInputKey* keys = get_row(keyboards[model->selected_keyboard], row); - - for(size_t column = 0; column < column_count; column++) { - bool selected = !model->cursor_select && model->selected_row == row && - model->selected_column == column; - const Icon* icon = NULL; - if(keys[column].text == ENTER_KEY) { - icon = selected ? &I_KeySaveSelected_24x11 : &I_KeySave_24x11; - } else if(keys[column].text == SWITCH_KEYBOARD_KEY) { - icon = selected ? &I_KeyKeyboardSelected_10x11 : &I_KeyKeyboard_10x11; - } else if(keys[column].text == BACKSPACE_KEY) { - icon = selected ? &I_KeyBackspaceSelected_16x9 : &I_KeyBackspace_16x9; - } - canvas_set_color(canvas, ColorBlack); - if(icon != NULL) { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - icon); - } else { - if(selected) { - canvas_draw_box( - canvas, - keyboard_origin_x + keys[column].x - 1, - keyboard_origin_y + keys[column].y - 8, - 7, - 10); - canvas_set_color(canvas, ColorWhite); - } - - if(model->clear_default_text || text_length == 0) { - canvas_draw_glyph( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - char_to_uppercase(keys[column].text)); - } else { - canvas_draw_glyph( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - keys[column].text); - } - } - } - } - if(model->validator_message_visible) { - canvas_set_font(canvas, FontSecondary); - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 8, 10, 110, 48); - canvas_set_color(canvas, ColorBlack); - canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42); - canvas_draw_rframe(canvas, 8, 8, 112, 50, 3); - canvas_draw_rframe(canvas, 9, 9, 110, 48, 2); - elements_multiline_text(canvas, 62, 20, furi_string_get_cstr(model->validator_text)); - canvas_set_font(canvas, FontKeyboard); - } -} - -static void - wifi_text_input_handle_up(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { - UNUSED(wifi_text_input); - if(model->selected_row > 0) { - model->selected_row--; - if(model->selected_row == 0 && - model->selected_column > - get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 6) { - model->selected_column = model->selected_column + 1; - } - if(model->selected_row == 1 && - model->selected_keyboard == symbol_keyboard.keyboard_index) { - if(model->selected_column > 5) - model->selected_column += 2; - else if(model->selected_column > 1) - model->selected_column += 1; - } - } else { - model->cursor_select = true; - model->clear_default_text = false; - } -} - -static void - wifi_text_input_handle_down(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { - UNUSED(wifi_text_input); - if(model->cursor_select) { - model->cursor_select = false; - } else if(model->selected_row < keyboard_row_count - 1) { - model->selected_row++; - if(model->selected_row == 1 && - model->selected_column > - get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 4) { - model->selected_column = model->selected_column - 1; - } - if(model->selected_row == 2 && - model->selected_keyboard == symbol_keyboard.keyboard_index) { - if(model->selected_column > 7) - model->selected_column -= 2; - else if(model->selected_column > 1) - model->selected_column -= 1; - } - } -} - -static void - wifi_text_input_handle_left(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { - UNUSED(wifi_text_input); - if(model->cursor_select) { - if(model->cursor_pos > 0) { - model->cursor_pos = CLAMP(model->cursor_pos - 1, strlen(model->text_buffer), 0u); - } - } else if(model->selected_column > 0) { - model->selected_column--; - } else { - model->selected_column = - get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 1; - } -} - -static void - wifi_text_input_handle_right(WIFI_TextInput* wifi_text_input, WIFI_TextInputModel* model) { - UNUSED(wifi_text_input); - if(model->cursor_select) { - model->cursor_pos = CLAMP(model->cursor_pos + 1, strlen(model->text_buffer), 0u); - } else if( - model->selected_column < - get_row_size(keyboards[model->selected_keyboard], model->selected_row) - 1) { - model->selected_column++; - } else { - model->selected_column = 0; - } -} - -static void wifi_text_input_handle_ok( - WIFI_TextInput* wifi_text_input, - WIFI_TextInputModel* model, - InputType type) { - if(model->cursor_select) return; - bool shift = type == InputTypeLong; - bool repeat = type == InputTypeRepeat; - char selected = get_selected_char(model); - size_t text_length = strlen(model->text_buffer); - - if(selected == ENTER_KEY) { - if(model->validator_callback && - (!model->validator_callback( - model->text_buffer, model->validator_text, model->validator_callback_context))) { - model->validator_message_visible = true; - furi_timer_start(wifi_text_input->timer, furi_kernel_get_tick_frequency() * 4); - } else if(model->callback != 0 && text_length >= model->minimum_length) { - model->callback(model->callback_context); - } - } else if(selected == SWITCH_KEYBOARD_KEY) { - switch_keyboard(model); - } else { - if(selected == BACKSPACE_KEY) { - wifi_text_input_backspace_cb(model); - } else if(!repeat) { - if(model->clear_default_text) { - text_length = 0; - } - if(text_length < (model->text_buffer_size - 1)) { - if(shift != (text_length == 0)) { - selected = char_to_uppercase(selected); - } - if(model->clear_default_text) { - model->text_buffer[0] = selected; - model->text_buffer[1] = '\0'; - model->cursor_pos = 1; - } else { - char* move = model->text_buffer + model->cursor_pos; - memmove(move + 1, move, strlen(move) + 1); - model->text_buffer[model->cursor_pos] = selected; - model->cursor_pos++; - } - } - } - model->clear_default_text = false; - } -} - -static bool wifi_text_input_view_input_callback(InputEvent* event, void* context) { - WIFI_TextInput* wifi_text_input = context; - furi_assert(wifi_text_input); - - bool consumed = false; - - // Acquire model - WIFI_TextInputModel* model = view_get_model(wifi_text_input->view); - - if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) && - model->validator_message_visible) { - model->validator_message_visible = false; - consumed = true; - } else if(event->type == InputTypeShort) { - consumed = true; - switch(event->key) { - case InputKeyUp: - wifi_text_input_handle_up(wifi_text_input, model); - break; - case InputKeyDown: - wifi_text_input_handle_down(wifi_text_input, model); - break; - case InputKeyLeft: - wifi_text_input_handle_left(wifi_text_input, model); - break; - case InputKeyRight: - wifi_text_input_handle_right(wifi_text_input, model); - break; - case InputKeyOk: - wifi_text_input_handle_ok(wifi_text_input, model, event->type); - break; - default: - consumed = false; - break; - } - } else if(event->type == InputTypeLong) { - consumed = true; - switch(event->key) { - case InputKeyUp: - wifi_text_input_handle_up(wifi_text_input, model); - break; - case InputKeyDown: - wifi_text_input_handle_down(wifi_text_input, model); - break; - case InputKeyLeft: - wifi_text_input_handle_left(wifi_text_input, model); - break; - case InputKeyRight: - wifi_text_input_handle_right(wifi_text_input, model); - break; - case InputKeyOk: - wifi_text_input_handle_ok(wifi_text_input, model, event->type); - break; - case InputKeyBack: - wifi_text_input_backspace_cb(model); - break; - default: - consumed = false; - break; - } - } else if(event->type == InputTypeRepeat) { - consumed = true; - switch(event->key) { - case InputKeyUp: - wifi_text_input_handle_up(wifi_text_input, model); - break; - case InputKeyDown: - wifi_text_input_handle_down(wifi_text_input, model); - break; - case InputKeyLeft: - wifi_text_input_handle_left(wifi_text_input, model); - break; - case InputKeyRight: - wifi_text_input_handle_right(wifi_text_input, model); - break; - case InputKeyOk: - wifi_text_input_handle_ok(wifi_text_input, model, event->type); - break; - case InputKeyBack: - wifi_text_input_backspace_cb(model); - break; - default: - consumed = false; - break; - } - } - - // Commit model - view_commit_model(wifi_text_input->view, consumed); - - return consumed; -} - -void wifi_text_input_timer_callback(void* context) { - furi_assert(context); - WIFI_TextInput* wifi_text_input = context; - - with_view_model( - wifi_text_input->view, - WIFI_TextInputModel * model, - { model->validator_message_visible = false; }, - true); -} - -WIFI_TextInput* wifi_text_input_alloc() { - WIFI_TextInput* wifi_text_input = malloc(sizeof(WIFI_TextInput)); - wifi_text_input->view = view_alloc(); - view_set_context(wifi_text_input->view, wifi_text_input); - view_allocate_model(wifi_text_input->view, ViewModelTypeLocking, sizeof(WIFI_TextInputModel)); - view_set_draw_callback(wifi_text_input->view, wifi_text_input_view_draw_callback); - view_set_input_callback(wifi_text_input->view, wifi_text_input_view_input_callback); - - wifi_text_input->timer = - furi_timer_alloc(wifi_text_input_timer_callback, FuriTimerTypeOnce, wifi_text_input); - - with_view_model( - wifi_text_input->view, - WIFI_TextInputModel * model, - { - model->validator_text = furi_string_alloc(); - model->minimum_length = 1; - model->cursor_pos = 0; - model->cursor_select = false; - }, - false); - - wifi_text_input_reset(wifi_text_input); - - return wifi_text_input; -} - -void wifi_text_input_free(WIFI_TextInput* wifi_text_input) { - furi_assert(wifi_text_input); - with_view_model( - wifi_text_input->view, - WIFI_TextInputModel * model, - { furi_string_free(model->validator_text); }, - false); - - // Send stop command - furi_timer_stop(wifi_text_input->timer); - // Release allocated memory - furi_timer_free(wifi_text_input->timer); - - view_free(wifi_text_input->view); - - free(wifi_text_input); -} - -void wifi_text_input_reset(WIFI_TextInput* wifi_text_input) { - furi_assert(wifi_text_input); - with_view_model( - wifi_text_input->view, - WIFI_TextInputModel * model, - { - model->header = ""; - model->selected_row = 0; - model->selected_column = 0; - model->selected_keyboard = 0; - model->minimum_length = 1; - model->clear_default_text = false; - model->cursor_pos = 0; - model->cursor_select = false; - model->text_buffer = NULL; - model->text_buffer_size = 0; - model->callback = NULL; - model->callback_context = NULL; - model->validator_callback = NULL; - model->validator_callback_context = NULL; - furi_string_reset(model->validator_text); - model->validator_message_visible = false; - }, - true); -} - -View* wifi_text_input_get_view(WIFI_TextInput* wifi_text_input) { - furi_assert(wifi_text_input); - return wifi_text_input->view; -} - -void wifi_text_input_set_result_callback( - WIFI_TextInput* wifi_text_input, - WIFI_TextInputCallback callback, - void* callback_context, - char* text_buffer, - size_t text_buffer_size, - bool clear_default_text) { - with_view_model( - wifi_text_input->view, - WIFI_TextInputModel * model, - { - model->callback = callback; - model->callback_context = callback_context; - model->text_buffer = text_buffer; - model->text_buffer_size = text_buffer_size; - model->clear_default_text = clear_default_text; - model->cursor_select = false; - if(text_buffer && text_buffer[0] != '\0') { - model->cursor_pos = strlen(text_buffer); - // Set focus on Save - model->selected_row = 2; - model->selected_column = 9; - model->selected_keyboard = 0; - } else { - model->cursor_pos = 0; - } - }, - true); -} - -void wifi_text_input_set_minimum_length(WIFI_TextInput* wifi_text_input, size_t minimum_length) { - with_view_model( - wifi_text_input->view, - WIFI_TextInputModel * model, - { model->minimum_length = minimum_length; }, - true); -} - -void wifi_text_input_set_validator( - WIFI_TextInput* wifi_text_input, - WIFI_TextInputValidatorCallback callback, - void* callback_context) { - with_view_model( - wifi_text_input->view, - WIFI_TextInputModel * model, - { - model->validator_callback = callback; - model->validator_callback_context = callback_context; - }, - true); -} - -WIFI_TextInputValidatorCallback - wifi_text_input_get_validator_callback(WIFI_TextInput* wifi_text_input) { - WIFI_TextInputValidatorCallback validator_callback = NULL; - with_view_model( - wifi_text_input->view, - WIFI_TextInputModel * model, - { validator_callback = model->validator_callback; }, - false); - return validator_callback; -} - -void* wifi_text_input_get_validator_callback_context(WIFI_TextInput* wifi_text_input) { - void* validator_callback_context = NULL; - with_view_model( - wifi_text_input->view, - WIFI_TextInputModel * model, - { validator_callback_context = model->validator_callback_context; }, - false); - return validator_callback_context; -} - -void wifi_text_input_set_header_text(WIFI_TextInput* wifi_text_input, const char* text) { - with_view_model( - wifi_text_input->view, WIFI_TextInputModel * model, { model->header = text; }, true); -} diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_text_input.h b/applications/external/wifi_marauder_companion/wifi_marauder_text_input.h deleted file mode 100644 index f5efe9234..000000000 --- a/applications/external/wifi_marauder_companion/wifi_marauder_text_input.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -#include -#include "wifi_marauder_validators.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Text input anonymous structure */ -typedef struct WIFI_TextInput WIFI_TextInput; -typedef void (*WIFI_TextInputCallback)(void* context); -typedef bool (*WIFI_TextInputValidatorCallback)(const char* text, FuriString* error, void* context); - -/** Allocate and initialize text input - * - * This text input is used to enter string - * - * @return WIFI_TextInput instance - */ -WIFI_TextInput* wifi_text_input_alloc(); - -/** Deinitialize and free text input - * - * @param text_input WIFI_TextInput instance - */ -void wifi_text_input_free(WIFI_TextInput* text_input); - -/** Clean text input view Note: this function does not free memory - * - * @param text_input Text input instance - */ -void wifi_text_input_reset(WIFI_TextInput* text_input); - -/** Get text input view - * - * @param text_input WIFI_TextInput instance - * - * @return View instance that can be used for embedding - */ -View* wifi_text_input_get_view(WIFI_TextInput* text_input); - -/** Set text input result callback - * - * @param text_input WIFI_TextInput instance - * @param callback callback fn - * @param callback_context callback context - * @param text_buffer pointer to YOUR text buffer, that we going - * to modify - * @param text_buffer_size YOUR text buffer size in bytes. Max string - * length will be text_buffer_size-1. - * @param clear_default_text clear text from text_buffer on first OK - * event - */ -void wifi_text_input_set_result_callback( - WIFI_TextInput* text_input, - WIFI_TextInputCallback callback, - void* callback_context, - char* text_buffer, - size_t text_buffer_size, - bool clear_default_text); - -void wifi_text_input_set_validator( - WIFI_TextInput* text_input, - WIFI_TextInputValidatorCallback callback, - void* callback_context); - -void wifi_text_input_set_minimum_length(WIFI_TextInput* text_input, size_t minimum_length); - -WIFI_TextInputValidatorCallback wifi_text_input_get_validator_callback(WIFI_TextInput* text_input); - -void* wifi_text_input_get_validator_callback_context(WIFI_TextInput* text_input); - -/** Set text input header text - * - * @param text_input WIFI_TextInput instance - * @param text text to be shown - */ -void wifi_text_input_set_header_text(WIFI_TextInput* text_input, const char* text); - -#ifdef __cplusplus -} -#endif \ No newline at end of file From 8d54b4324f9e45731d76633011c8b40a06a27779 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sun, 23 Jul 2023 00:09:40 +0200 Subject: [PATCH 2/5] Rounded keyboard cursor + realign all keys --- .../brainfuck/icons/KeySaveSelected_24x11.png | Bin 1812 -> 1853 bytes .../brainfuck/icons/KeySave_24x11.png | Bin 1829 -> 1863 bytes .../services/gui/modules/byte_input.c | 14 +-- .../services/gui/modules/text_input.c | 80 +++++++++--------- .../Keyboard/KeyBackspaceSelected_17x11.png | Bin 0 -> 5078 bytes assets/icons/Keyboard/KeyBackspace_17x11.png | Bin 0 -> 5085 bytes .../icons/Keyboard/KeySaveSelected_22x11.png | Bin 0 -> 5340 bytes .../icons/Keyboard/KeySaveSelected_24x11.png | Bin 8011 -> 0 bytes assets/icons/Keyboard/KeySave_22x11.png | Bin 0 -> 5340 bytes assets/icons/Keyboard/KeySave_24x11.png | Bin 8330 -> 0 bytes firmware/targets/f7/api_symbols.csv | 8 +- 11 files changed, 52 insertions(+), 50 deletions(-) rename assets/icons/Keyboard/KeyBackspaceSelected_16x9.png => applications/external/brainfuck/icons/KeySaveSelected_24x11.png (52%) rename assets/icons/Keyboard/KeyBackspace_16x9.png => applications/external/brainfuck/icons/KeySave_24x11.png (51%) create mode 100644 assets/icons/Keyboard/KeyBackspaceSelected_17x11.png create mode 100644 assets/icons/Keyboard/KeyBackspace_17x11.png create mode 100644 assets/icons/Keyboard/KeySaveSelected_22x11.png delete mode 100644 assets/icons/Keyboard/KeySaveSelected_24x11.png create mode 100644 assets/icons/Keyboard/KeySave_22x11.png delete mode 100644 assets/icons/Keyboard/KeySave_24x11.png diff --git a/assets/icons/Keyboard/KeyBackspaceSelected_16x9.png b/applications/external/brainfuck/icons/KeySaveSelected_24x11.png similarity index 52% rename from assets/icons/Keyboard/KeyBackspaceSelected_16x9.png rename to applications/external/brainfuck/icons/KeySaveSelected_24x11.png index 7cc0759a8ca6acdb9b9c2e3dc00edde2f0e93a67..eeb3569d3accc5a5c56829b12c85079172b56729 100644 GIT binary patch delta 415 zcmbQjx0g?`Gr-TCmrII^fq{Y7)59eQNJ{`QHwP1td=-9c)<(rzCRQUuDKb2AfT-J~=NLtRtjB#T4~!!)yG%aqBE%vvgG zDW+*@7UoI128rh8x@l=9X1W&UK$cNrTB4D;d8)CoiRt8iW)+o0!xW1oV*^v&R1*sm zpkXFyx)!EDA}P(lAjQbYGTAISY4UaEwZti0!6E~7?Maq0;#`ZY#b)yXR$j(}=h^D- zfngHj>EaloG4bi7ja&^5JkG)&|JVPt6j?o?$((~P&8u25^EBrLeugj0=4jkI8^Wh| z(tYulsas4p@2&eWCu6_()70M=HB7@}IoG~8@TzCM_C)zdQ|I%_Ec+I4zNn?@3ebE8 MPgg&ebxsLQ0Qy*hAOHXW delta 374 zcmdnXH-%5JGr-TCmrII^fq{Y7)59eQNDBZlCkGRd+~Q%Kx>2!~iPg~3%EV;yVkQkJ z>jIM+l=YiQNyXU2B0144EmhYf$vjop+{DB}Hz~>7NY^mgG||M!$js2#!gR7DvzAJt ziAkbis-b~ysMWU`nl1WO6rFo*6NwV4Ger6RFBXiRf!(>AvU2~w6 zuDQ91xo)DFMXGL!g|VecvO!9sQCi~U>&$D3Q@Daf2I|_AEM>&G7FmnU<^!y}jP9cU z4)_AYMBCHFF+^f&@{j-j?U^q&s2qJFb--m+Y0r_>X(=f#<@_h>7Fh^rn1B8M|38E9 XHrbc?wQ3K5+88`t{an^LB{Ts5!We4r diff --git a/assets/icons/Keyboard/KeyBackspace_16x9.png b/applications/external/brainfuck/icons/KeySave_24x11.png similarity index 51% rename from assets/icons/Keyboard/KeyBackspace_16x9.png rename to applications/external/brainfuck/icons/KeySave_24x11.png index 9946232d953ef1cbfbf0e6754be6645e5ea2747b..e7dba987a04dad7dd96001913c55566dbde96c8e 100644 GIT binary patch delta 425 zcmZ3=cbreLGr-TCmrII^fq{Y7)59eQNJ{`QHwP1td=-9c)<(rzCRQT@D-(;!i2!~iPg~3%FuZ7VkQkJ z>jIM+l=YiQNyXSaDKRnC&`j4X&A?38!qmh_H_<%RR5#f)(cH+u(A>xvsM(QOOU1&_ zIMvK7#Y{KV+{8rJ($pkHHz_$eQ8&fdz`!Ui$sokB`c`{IS znwd$WZjye`bmWyHA_S&Pl)1FXD^5!OQQ zS%G0<Dm!qo%1!K&m6Kw?OjasfY(M9lR{2 n%5z+n*lNsE^WtCmk%8fjk-|^;KaL(ia~M2b{an^LB{Ts5(c*6d diff --git a/applications/services/gui/modules/byte_input.c b/applications/services/gui/modules/byte_input.c index 554a7ca5c..3b62daebe 100644 --- a/applications/services/gui/modules/byte_input.c +++ b/applications/services/gui/modules/byte_input.c @@ -46,7 +46,7 @@ static const ByteInputKey keyboard_keys_row_1[] = { {'5', 55, 12}, {'6', 66, 12}, {'7', 77, 12}, - {backspace_symbol, 103, 4}, + {backspace_symbol, 100, 3}, }; static const ByteInputKey keyboard_keys_row_2[] = { @@ -640,13 +640,13 @@ static void byte_input_view_draw_callback(Canvas* canvas, void* _model) { canvas, keyboard_origin_x + keys[column].x, keyboard_origin_y + keys[column].y, - &I_KeySaveSelected_24x11); + &I_KeySaveSelected_22x11); } else { canvas_draw_icon( canvas, keyboard_origin_x + keys[column].x, keyboard_origin_y + keys[column].y, - &I_KeySave_24x11); + &I_KeySave_22x11); } } else if(keys[column].value == backspace_symbol) { canvas_set_color(canvas, ColorBlack); @@ -655,18 +655,18 @@ static void byte_input_view_draw_callback(Canvas* canvas, void* _model) { canvas, keyboard_origin_x + keys[column].x, keyboard_origin_y + keys[column].y, - &I_KeyBackspaceSelected_16x9); + &I_KeyBackspaceSelected_17x11); } else { canvas_draw_icon( canvas, keyboard_origin_x + keys[column].x, keyboard_origin_y + keys[column].y, - &I_KeyBackspace_16x9); + &I_KeyBackspace_17x11); } } else { if(model->selected_row == row && model->selected_column == column) { canvas_set_color(canvas, ColorBlack); - canvas_draw_box( + elements_slightly_rounded_box( canvas, keyboard_origin_x + keys[column].x - 3, keyboard_origin_y + keys[column].y - 10, @@ -677,7 +677,7 @@ static void byte_input_view_draw_callback(Canvas* canvas, void* _model) { model->selected_row == -1 && row == 0 && model->selected_column == column) { canvas_set_color(canvas, ColorBlack); - canvas_draw_frame( + elements_slightly_rounded_frame( canvas, keyboard_origin_x + keys[column].x - 3, keyboard_origin_y + keys[column].y - 10, diff --git a/applications/services/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c index 126d647ae..32229e9bb 100644 --- a/applications/services/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -64,9 +64,9 @@ static const TextInputKey keyboard_keys_row_1[] = { {'i', 64, 8}, {'o', 73, 8}, {'p', 82, 8}, - {'0', 91, 8}, - {'1', 100, 8}, - {'2', 110, 8}, + {'0', 92, 8}, + {'1', 102, 8}, + {'2', 111, 8}, {'3', 120, 8}, }; @@ -80,25 +80,25 @@ static const TextInputKey keyboard_keys_row_2[] = { {'j', 55, 20}, {'k', 64, 20}, {'l', 73, 20}, - {BACKSPACE_KEY, 82, 12}, - {'4', 100, 20}, - {'5', 110, 20}, + {BACKSPACE_KEY, 82, 11}, + {'4', 102, 20}, + {'5', 111, 20}, {'6', 120, 20}, }; static const TextInputKey keyboard_keys_row_3[] = { - {SWITCH_KEYBOARD_KEY, 1, 23}, + {SWITCH_KEYBOARD_KEY, 0, 23}, {'z', 13, 32}, {'x', 21, 32}, - {'c', 28, 32}, - {'v', 36, 32}, - {'b', 44, 32}, - {'n', 52, 32}, - {'m', 59, 32}, - {'_', 67, 32}, - {ENTER_KEY, 74, 23}, - {'7', 100, 32}, - {'8', 110, 32}, + {'c', 29, 32}, + {'v', 37, 32}, + {'b', 45, 32}, + {'n', 53, 32}, + {'m', 61, 32}, + {'_', 69, 32}, + {ENTER_KEY, 77, 23}, + {'7', 102, 32}, + {'8', 111, 32}, {'9', 120, 32}, }; @@ -112,9 +112,9 @@ static TextInputKey symbol_keyboard_keys_row_1[] = { {'&', 62, 8}, {'(', 71, 8}, {')', 81, 8}, - {'0', 91, 8}, - {'1', 100, 8}, - {'2', 110, 8}, + {'0', 92, 8}, + {'1', 102, 8}, + {'2', 111, 8}, {'3', 120, 8}, }; @@ -127,22 +127,22 @@ static TextInputKey symbol_keyboard_keys_row_2[] = { {']', 52, 20}, {'{', 62, 20}, {'}', 72, 20}, - {BACKSPACE_KEY, 82, 12}, - {'4', 100, 20}, - {'5', 110, 20}, + {BACKSPACE_KEY, 82, 11}, + {'4', 102, 20}, + {'5', 111, 20}, {'6', 120, 20}, }; static TextInputKey symbol_keyboard_keys_row_3[] = { - {SWITCH_KEYBOARD_KEY, 1, 23}, + {SWITCH_KEYBOARD_KEY, 0, 23}, {'.', 15, 32}, {',', 29, 32}, {';', 41, 32}, {'`', 53, 32}, {'\'', 65, 32}, - {ENTER_KEY, 74, 23}, - {'7', 100, 32}, - {'8', 110, 32}, + {ENTER_KEY, 77, 23}, + {'7', 102, 32}, + {'8', 111, 32}, {'9', 120, 32}, }; @@ -308,6 +308,8 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) { canvas_set_font(canvas, FontKeyboard); + bool uppercase = model->clear_default_text || text_length == 0; + bool symbols = model->selected_keyboard == symbol_keyboard.keyboard_index; for(uint8_t row = 0; row < keyboard_row_count; row++) { const uint8_t column_count = get_row_size(keyboards[model->selected_keyboard], row); const TextInputKey* keys = get_row(keyboards[model->selected_keyboard], row); @@ -317,11 +319,11 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) { model->selected_column == column; const Icon* icon = NULL; if(keys[column].text == ENTER_KEY) { - icon = selected ? &I_KeySaveSelected_24x11 : &I_KeySave_24x11; + icon = selected ? &I_KeySaveSelected_22x11 : &I_KeySave_22x11; } else if(keys[column].text == SWITCH_KEYBOARD_KEY) { icon = selected ? &I_KeyKeyboardSelected_10x11 : &I_KeyKeyboard_10x11; } else if(keys[column].text == BACKSPACE_KEY) { - icon = selected ? &I_KeyBackspaceSelected_16x9 : &I_KeyBackspace_16x9; + icon = selected ? &I_KeyBackspaceSelected_17x11 : &I_KeyBackspace_17x11; } canvas_set_color(canvas, ColorBlack); if(icon != NULL) { @@ -332,28 +334,28 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) { icon); } else { if(selected) { - canvas_draw_box( + elements_slightly_rounded_box( canvas, - keyboard_origin_x + keys[column].x - 1, - keyboard_origin_y + keys[column].y - 8, - 7, - 10); + keyboard_origin_x + keys[column].x - 2, + keyboard_origin_y + keys[column].y - 9, + 9, + 11); canvas_set_color(canvas, ColorWhite); } - if(model->selected_keyboard != symbol_keyboard.keyboard_index && - (model->clear_default_text || text_length == 0)) { + char glyph = keys[column].text; + if(uppercase && !symbols) { canvas_draw_glyph( canvas, keyboard_origin_x + keys[column].x, keyboard_origin_y + keys[column].y, - char_to_uppercase(keys[column].text)); + char_to_uppercase(glyph)); } else { canvas_draw_glyph( canvas, keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - keys[column].text); + keyboard_origin_y + keys[column].y - (glyph == '_' || char_is_lowercase(glyph)), + glyph); } } } @@ -406,7 +408,7 @@ static void text_input_handle_down(TextInput* text_input, TextInputModel* model) } if(model->selected_row == 2 && model->selected_keyboard == symbol_keyboard.keyboard_index) { - if(model->selected_column > 7) + if(model->selected_column > 6) model->selected_column -= 2; else if(model->selected_column > 1) model->selected_column -= 1; diff --git a/assets/icons/Keyboard/KeyBackspaceSelected_17x11.png b/assets/icons/Keyboard/KeyBackspaceSelected_17x11.png new file mode 100644 index 0000000000000000000000000000000000000000..5255f78ce80a23a8d946eb8e18483966d286be86 GIT binary patch literal 5078 zcmeHLeT)?48K33D!<9?qqhOB1PDe|w;OuQ6FoIc0fN1+6^;goyEV9`JN8Q!$%m)rjG{P_<*Z5;j12lD1Mw?5=O_R`kC50oc=esti+!M9c)T)nA1 zq`fzN>sJrGP`vc3LmwS{&3i1hD7>a|(Y$R7pSRd0dm28O*&7|P-kg8%=KVvj1bZHB z=sC0d2>Zy%t{)z1H)qCfldqp0ZF+9+c6TPKjl^Eu`P0$p{L9asd+fx%o%?65dT4rb zZ*%|X*}MOIc>R7h{D-gKH+#i}ZNJ;Jed;|Mo?cfNx}Y4_enfnlKD%1~_x}2g7kB@4 zaQ(JM*VNOm4fn0@ytw(-3pf7$jh*pRk6se)Tj?q;|B3#lEAq;U{M+Xayu9Q6Ix@0h zUvBf3$i`>dPMzEE!I_h%P9I6%H9AThIB&fAx}rTu5H~)nCD&SO<9A4kp7kJAm$9dq z&D$GBgq9ccNa?{ADdV)33sV;kAE8K14O3mdI2+GLaJSYrXyDGl_M|e{qlhZCe3?5` zlmH-$EkqWxnVcyV!<2(7fou;m6zQl~Jz;7sauYJtJ98SwUjI^H5TP@YwVfNr~}WdTc`xh!3M2(T#D*SpUpNFt>l8LE1D`* z$w){L5QjOI#$FN8K2DHnF%U#_P!?2G3?RRt_-g=TInzQp1>1mN!lMD0%wvU@MK3K2 z0f82L04Aq|0L>$Bko5-zua6aKAl4WfBsI#^aa7`if%{NiB;zEo6s|^NTF&3kag< z3-WBhH>PwaHcZG@8`G(<&Wx%^s{j!}-f3Bs#!Nn!b|%JR7|}Dj5!Y25ro2~7LBUOw z>TQ@ZJ6czgv6hIR6a9V~Y&g319!n4t*d=7279i-1LrA2Efsuuy(0~)mb2Q7-ESKa2 zi4!G3Si-RqTk^iDts6;Q&xEP!O;H7lLkUokg{pAnyCYe-JC?9~EgU$cr3OAv+dlAQ z2+TvawP~iM8w1WzsS0%B-qKU)F{3%hpCp}wEFq=ju;RF>I!pnrG^t%B)4p(eR8dSl zWfhQto6`{AFx70=Su#;MsU**Nc(SQW%c*+7{Kj|!g>G!8!ZpLrd;!l))Q_+5OX)_r zG=^GUE*}5QU#}2UkUxcKK@MO#AP7NPmIFM^DLy3dyr1(1OX>T6;;&z2Q$mUr=#*bT zw1B)mC`PhEr$j!*`@KG|td`V(z>jkxfnkxYm|>X%^}ee`V^Iw=~4qH&!Kg zL(FHhJ2ZCqD`l)1s-m6#W=;C9MCtKKvaEC=Us;5q#L2QBwixOgrbVBiLM`RJbPyq) z75QL*mvM*N5OWlWc^XA^PwCNv=Jrs>ao0CoN4DV`o z6XeWe?~Pu5=Wn+zF23l#=t8%vryp)hFL3?Q7~V2+{ufKyrV#h#cF iPJFWT@|;J}hVI?&?B3Vv4mjT#`ygj7_9^BgsNRpc^VWB} z=i9aKY`H45`6z(~2%!P$wvdV@DsiHs5{e=qh`1za(pE_jr700onx-mMXsarfS{(Xz z?|gSAq=}{Gk4nDP+`OH6^PBg6^XAQHx5V38>T2t234*ALwno~ao&)8kSvSD{UNTt& z)o<|HXfhhTiCf?8iHeur(61pDq+!{K-|9450lJ*lQKK@^6+zBAZ*dPT$NS33^2 z-$gB$)B95V`+s?&y`ksx56AC(vvx$-bKk#a#_AuPzp&-hk&744NM}!tuIsGn4Bc{t z=T~`TjkxjXb=$a|W|5G-J-L zz4+B=d+o+E=Ym5+$G86d>G$9Juwm?LZ%dojeDM+P^v||?BX~6`uv7NOz_<=Jur90<*n}wZJWM% zL2c8w!d*|ap1-v5?F;A5zjZRTer${wc|UjJMOpn0LEQ4BnpkVDjomHCdd4X#x`dsD zOx9X3BCx!W73Cgmk`hj-T9CT@{7H&bl_1sWjxn)p7tEnij} zC~z*~^&HqETya^>@RXP$HFxs;3b`~5Bkxe%g3gEj^KbWbijv-E1}O^q$#MHK*;uR$uNfs4fDcze%(_@7cAkr>Eg zS35TJzMPDk`>|#&u7u@m&O z-MXn8-Fmh>Y=VL1ZribHlT0;PVR^zBtLG!?VCVH`7$?of2CZ03i0E>kWoiq>z)Tw8Yb*nbdQcAa%E@^%W`|2{nT|Owpo__4paa z?R9f*#QRy^S5dkb=M0Ef3)9Z9c8?+pD*;i2xKlG?3cIpe%I>Ie7}nEzE~YCuNENxN zbV0(67xQh9GTK|3$Y^ue!}>iQ8s@NJtTh&Z6IdnD+AUz9-42up;T#rC9DxEhF^HuZ zL^EuHkMC3xu}(xbcB-19=Z!DhRF#M3yRj7tA4|LIQ+Q^G z{rDQcqQ(}47jq<|KI+K z43B&)mT9+#k!jeS5-lR^hjb!&ankRXWaOT>NZ0t=0?FLIACZlA0{FNk-z26c2FbGGfqZQe_CNxaJYEdmCUGeV z^N6E;qKFtj@_CVji$9H1O5#p-#>_7hGE@-(i+q%wxk7)C(;vn`7-wKU2W;E7Z^Ipw@`HL1)+aLTKG_8(C zLW#y-kG#&_Opvp}_pJK))!mo&FWJX*Zyw#^9dbmcF@3G|e_XxD(WTYBv-iHHH$6KY y&;C|h)cNj_E4TfQJJxXT=Jh9hzgqC;(VLH^$$3YQKld!a64BxlNC}1J*^1x+H0@Juc92XxdrrO))G=GReVWy80r}>f{5Z&! zIUREiZJ%N*fxa6W0(lnnKZd40oZYJrWb?1c`u9$;SsEjKZ7AG8ASX>Z85Y)4h~X(O zj}UF zo@4gR_R|eNd}m){McbD)HGK8W;sgAyyZ~T*QZfAP^WysDw{2xk{CuPL5$Okq``7H@USE1>>Du}# z^*7Tte&xu)%;i^({OQnf=7ciWzr14Z?9FqYHK_T!%l|r~Jvd;zR(9x?-tOnQwkOKl z&h0oxJwDj{{Ui1IjL_G`>7~KSXL`02$AaoW=%?GB9uAgWedglM)BCse&RDW_TBN7C zbNIr#zZ_lFOZoqJ`-aj*mp1=l?UsW3SMOb!?!F|QQlGM2iC$Q$eb8Id^8Sv0bgkN4 zVJ{duezId#)BEdxF{kCNSGR@FK5?1du-Kki_#^E#d*Jy+$uk!ZJoo4ug+yTW{>1tR z0xkRM&R$%7{@mc%p<~gzhKFqj-c9wrEUDkK*=BB1BP)y*;bpv}#hrqziP)KmC(Q%1 zRV~aU1*r`igovYR!tc0r^q7NCWxu1@9j3y`0B%+5x>C5Qt3D!iwMjnNv2a0gRfY$E zI5q?#6OScyKI3;-xID<_u**SMDn^^%u>#^KprtUuI$0-0)@0O9(B|B0vOGlPmIELc@sslfIoPM%Z zGc>(bOXio2BbcAI3>!(a4WN3wx1%ze6HwI#PN`;^nVq>|PP%=OXw9JVNBhzNsW#)!~{dpQgOdynVRUxj7~(cfB*(^6qg#(oEL%@h>e zhHSm{JM_ld#YCtk;GumU4+(o%y5<@4;1f6{!ORvQXpMtQ_&^E^1`a|4P86a^3Xv2Y zp;;c$JaW&cDW1w&pV!t>5lxHv9r-s!9xMzcKo$%k50`s)L`L2n^C>hI4h&M2HJ_wy zCOlCE+e5U~sk))1)>uQ?D$s=6vrpN_m};dzL0E~*3sTl#$ud*6m;zdMQoT;3ed_SY zqv)Dqq=gi&j)H&vj%u^c5)C7nN+8;ah{|R)A!}*a?AATc8eB+JN%^eKXmq}&SjVjnFb{F#{uRUBQL-8mDhT;@x8Bt5HKA5P$^ z(fT%0sjH#zn;EW;$?(NObbKBx$lf`web0C}EQ%g4CIzHm(&uJnQe+WBa)N*;AL6`7 z#92}?H3x4|9Ko-0eFC5C;xX3_K*^55bp~!nuKe{V#}{hE=lPdQ%g=KQf|%T7LjIj} z*QC29c=rBe`t9rbJIe;|?z{Otdqvr| zrVP@*4A0rqbMUF5SGGT0aHm+}-Fjlr3vV6lJF>5D*Pl05> X>5g|c-1p5FO_HIS`ryIEE#Lhw$w%_0 literal 0 HcmV?d00001 diff --git a/assets/icons/Keyboard/KeySaveSelected_24x11.png b/assets/icons/Keyboard/KeySaveSelected_24x11.png deleted file mode 100644 index 6e5c9ac076287ff9110788ee7000aa5fb864f174..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8011 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 diff --git a/assets/icons/Keyboard/KeySave_22x11.png b/assets/icons/Keyboard/KeySave_22x11.png new file mode 100644 index 0000000000000000000000000000000000000000..46fd148e580647b06b5bbd335cc0841642cebfcd GIT binary patch literal 5340 zcmeHLe{dAl9p3|DFcPN(3Y`$`_EaXC?%mrTx4-5N2zMcO=!I)?(*z-0il(h-X_+E+VEi$ZDL;x7RH&V5hM^XR{;+fghuDs_KP1w(dzZ@( z@keH~e{^!0m-pTGzVGwCzu%j;Dc00jSy5eqVOV7(9BM}WJk+k4c@_G9=cT*uM%`~< zTSSdSZoy`v55(!3fw>T6^SO%jHHe<(nvP9J{kKr7LbT0ew`y0J)Au8KL6LqC(X~Y$ zdkyKDhE<||05uBHb5Z|O)Uq@NK|E{ds+NKnmLIt5fk61^lA2>*Z`s*= zi+kSet`o8Ezx70OP3Pw~$G-Gh#UAmI+y7G*t=>9!e&dm6&z(D-7(8-pWovnB{pT)W zUEN*H)&o_SAD+AFg|*q=-=F*E^|>Kz$5*6B2j`SCXW3U@-0;Y$J)7@sodNpmXUyKV z9iEIdSFApMISn8}Fl!KC_AYj{MkjM|ywApIp9g`MM^* z_S>>eU)=w6{?f1Z|8?JC`lz}vu%c$+yuRz6vOwMT>c7qE3JqE>&EI$Z?t$m|&WEZy z&u%*e9z5Opz5Pw*tjL!WS6787ZV-6$rj1oghWh@ru7CQys~=yP8yJ$0Yd^r=Po7(@zqh+`&AZ#)S=-)M z`MNcKesN3m%tM!$jZ0nm#ZT%lxq{Cx$)38f=h^#TEyshacV^aq zGq~o7@RZMJr|9GFUZ<=F>Ll`E#79eMQ;;jJ?)VcJpn!Wbk=ql z=3ku8N^&Q(@B~b1nSgufz#%uTDFJt@FAAdBAnee>YYo`4wka;J?UV(@y?9ZDKQAJH zG_)iB|X5KPJ73$Fs+6j1X2{}iYv@`Zx(u+ zp{aKpGHmF98S93z5OxNY5Nwr_S~}|}g^V|DGes`(WxI`(!=uPvn1X2pY9jf_as1g1 z-O|ktJzH8fPQcQ%qu5xHEKMD?^0+nj%m>(!oLAmq#ApsS;)+JakS=%I(ndlfv7qR( zridkBL>kIGRG0*zGIWCAct#--3@s6WAxTA+XqNRcV*n!=(~>eWv;ol;9u0x9Kp{Dj z{55j>J-urRqjH;J!`EbmvDW;#wNESdwizk`(~( zajd{oGyps`%Jfxem?&OtOsB#+Gm0!OLx>WJJ1s3Gp*NdJIuoNd4C*P}i0TRqxakQ~ zsNlv5^)}!(n;Vznk%k~k3M@;YJse)!$0D)`@{(j{3lh*7M~e){VHXrvmQMNl^leq7tA;mQ;c(o*nU#v!f1BW8siOn%etu z+;+m_ezZM`wy?(W}K2w^L{y6R=vM9*~g=I%g#gP=D6(+SSMA|0~ zj}nTht5!}jV0{wVH{hnt7{$yA&oJrrKss$~>CXWl$sfLsT(L*YZs?)?OsnNkm& zpqJbsWs(rp@?!D$D1Bv)_K`k`Cm;y{K`IPDIYA2qi^7-UI3Gu=g<$zV(N{=F0`U20 zf~Q%UV4%bi0taaV@|=%UNl8{&dAyS*__q-ibLW19*E$8@!(2++nM5&hz=$a5X{HW1 zne;z!DbJELN$~<9(5S94iU0_n7ifY5DoZ6OS%ShxyL1vNas)+9%0@~2=9nEg75c!j68+KW3C+tr7(uBGw62YEnSa_@}iviEPusH_gQX%<5QbV z%Dz+PnljgE~H zM;Pqi!2|ao>gsHGrHS4N=h)4KJv#6OG+1s$q7CKe%jeClsk(NdVL#g>Bcb|u?JI*@ zk6e2gpBZfb<>kvpt}VO;Y)xMT-ir8Ztv5$*+-ruXy|S`>!L|*5cvAYukNR)=Bc8E+T?#75! Wi|c;&a`-)4$Vfv|=;@_vzVTn&=jkE< literal 0 HcmV?d00001 diff --git a/assets/icons/Keyboard/KeySave_24x11.png b/assets/icons/Keyboard/KeySave_24x11.png deleted file mode 100644 index 6945c7e8f8f935d790c5870b9ad28847680c2b6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8330 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 Q{(_69MpndY273?x4?FT~g#Z8m diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 327d884f4..9bfddd24c 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -3393,12 +3393,12 @@ Variable,+,I_InfraredArrowUp_4x8,Icon, Variable,+,I_InfraredLearnShort_128x31,Icon, Variable,+,I_Input_25x27,Icon, Variable,+,I_Input_hvr_25x27,Icon, -Variable,+,I_KeyBackspaceSelected_16x9,Icon, -Variable,+,I_KeyBackspace_16x9,Icon, +Variable,+,I_KeyBackspaceSelected_17x11,Icon, +Variable,+,I_KeyBackspace_17x11,Icon, Variable,+,I_KeyKeyboardSelected_10x11,Icon, Variable,+,I_KeyKeyboard_10x11,Icon, -Variable,+,I_KeySaveSelected_24x11,Icon, -Variable,+,I_KeySave_24x11,Icon, +Variable,+,I_KeySaveSelected_22x11,Icon, +Variable,+,I_KeySave_22x11,Icon, Variable,+,I_Keychain_39x36,Icon, Variable,+,I_Left_mouse_icon_9x9,Icon, Variable,+,I_Lock_7x8,Icon, From 1717fe9285fa1871d71d86bae4e5be4bb56da829 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sun, 23 Jul 2023 00:12:54 +0200 Subject: [PATCH 3/5] Format --- .../external/esp32cam_morseflasher/uart_terminal_app.c | 4 +--- applications/external/uart_terminal/uart_terminal_app.c | 4 +--- .../external/wifi_marauder_companion/wifi_marauder_app.c | 4 +--- applications/services/gui/modules/text_input.c | 3 ++- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/applications/external/esp32cam_morseflasher/uart_terminal_app.c b/applications/external/esp32cam_morseflasher/uart_terminal_app.c index 4c811b609..04267039f 100644 --- a/applications/external/esp32cam_morseflasher/uart_terminal_app.c +++ b/applications/external/esp32cam_morseflasher/uart_terminal_app.c @@ -58,9 +58,7 @@ UART_TerminalApp* uart_terminal_app_alloc() { app->text_input = text_input_alloc(); view_dispatcher_add_view( - app->view_dispatcher, - UART_TerminalAppViewTextInput, - text_input_get_view(app->text_input)); + app->view_dispatcher, UART_TerminalAppViewTextInput, text_input_get_view(app->text_input)); scene_manager_next_scene(app->scene_manager, UART_TerminalSceneStart); diff --git a/applications/external/uart_terminal/uart_terminal_app.c b/applications/external/uart_terminal/uart_terminal_app.c index fedab3f64..006cbaff4 100644 --- a/applications/external/uart_terminal/uart_terminal_app.c +++ b/applications/external/uart_terminal/uart_terminal_app.c @@ -58,9 +58,7 @@ UART_TerminalApp* uart_terminal_app_alloc() { app->text_input = text_input_alloc(); view_dispatcher_add_view( - app->view_dispatcher, - UART_TerminalAppViewTextInput, - text_input_get_view(app->text_input)); + app->view_dispatcher, UART_TerminalAppViewTextInput, text_input_get_view(app->text_input)); scene_manager_next_scene(app->scene_manager, UART_TerminalSceneStart); diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.c b/applications/external/wifi_marauder_companion/wifi_marauder_app.c index 87a923876..26092bdba 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.c +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.c @@ -68,9 +68,7 @@ WifiMarauderApp* wifi_marauder_app_alloc() { app->text_input = text_input_alloc(); view_dispatcher_add_view( - app->view_dispatcher, - WifiMarauderAppViewTextInput, - text_input_get_view(app->text_input)); + app->view_dispatcher, WifiMarauderAppViewTextInput, text_input_get_view(app->text_input)); app->widget = widget_alloc(); view_dispatcher_add_view( diff --git a/applications/services/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c index 32229e9bb..3da4d9c7c 100644 --- a/applications/services/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -354,7 +354,8 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) { canvas_draw_glyph( canvas, keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y - (glyph == '_' || char_is_lowercase(glyph)), + keyboard_origin_y + keys[column].y - + (glyph == '_' || char_is_lowercase(glyph)), glyph); } } From 5b9bb265e73623e204609f0dfe560742fe209a2e Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sun, 23 Jul 2023 00:28:36 +0200 Subject: [PATCH 4/5] Fix build --- .../scenes/wifi_marauder_scene_user_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_user_input.c b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_user_input.c index 17679a518..37e544cbe 100644 --- a/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_user_input.c +++ b/applications/external/wifi_marauder_companion/scenes/wifi_marauder_scene_user_input.c @@ -139,7 +139,7 @@ void wifi_marauder_scene_user_input_on_enter(void* context) { WIFI_MARAUDER_TEXT_INPUT_STORE_SIZE, false); - text_input_add_illegal_symbols(text_input); + text_input_add_illegal_symbols(app->text_input); view_dispatcher_switch_to_view(app->view_dispatcher, WifiMarauderAppViewTextInput); } From 7152846c083502c4cfba09b17cf39ae68f76b32e Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Sun, 23 Jul 2023 00:32:56 +0200 Subject: [PATCH 5/5] Fix archive switching menu index --- applications/main/archive/views/archive_browser_view.c | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 931c0c7a5..fd2a064da 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -392,6 +392,7 @@ static bool archive_view_input(InputEvent* event, void* context) { if(model->menu_can_switch) { if((event->key == InputKeyLeft && model->menu_manage) || (event->key == InputKeyRight && !model->menu_manage)) { + model->menu_idx = 0; model->menu_manage = !model->menu_manage; menu_array_reset(model->context_menu); }