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 7cc0759a8..eeb3569d3 100644 Binary files a/assets/icons/Keyboard/KeyBackspaceSelected_16x9.png and b/applications/external/brainfuck/icons/KeySaveSelected_24x11.png differ 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 9946232d9..e7dba987a 100644 Binary files a/assets/icons/Keyboard/KeyBackspace_16x9.png and b/applications/external/brainfuck/icons/KeySave_24x11.png differ 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..04267039f 100644 --- a/applications/external/esp32cam_morseflasher/uart_terminal_app.c +++ b/applications/external/esp32cam_morseflasher/uart_terminal_app.c @@ -56,11 +56,9 @@ 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)); + app->view_dispatcher, UART_TerminalAppViewTextInput, text_input_get_view(app->text_input)); scene_manager_next_scene(app->scene_manager, UART_TerminalSceneStart); @@ -76,7 +74,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..006cbaff4 100644 --- a/applications/external/uart_terminal/uart_terminal_app.c +++ b/applications/external/uart_terminal/uart_terminal_app.c @@ -56,11 +56,9 @@ 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)); + app->view_dispatcher, UART_TerminalAppViewTextInput, text_input_get_view(app->text_input)); scene_manager_next_scene(app->scene_manager, UART_TerminalSceneStart); @@ -76,7 +74,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..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 @@ -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(app->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..26092bdba 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.c +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.c @@ -66,11 +66,9 @@ 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)); + app->view_dispatcher, WifiMarauderAppViewTextInput, text_input_get_view(app->text_input)); app->widget = widget_alloc(); view_dispatcher_add_view( @@ -153,7 +151,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 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); } 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..3da4d9c7c 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,29 @@ 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 +409,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 000000000..5255f78ce Binary files /dev/null and b/assets/icons/Keyboard/KeyBackspaceSelected_17x11.png differ diff --git a/assets/icons/Keyboard/KeyBackspace_17x11.png b/assets/icons/Keyboard/KeyBackspace_17x11.png new file mode 100644 index 000000000..b78e81ea6 Binary files /dev/null and b/assets/icons/Keyboard/KeyBackspace_17x11.png differ diff --git a/assets/icons/Keyboard/KeySaveSelected_22x11.png b/assets/icons/Keyboard/KeySaveSelected_22x11.png new file mode 100644 index 000000000..ba911105a Binary files /dev/null and b/assets/icons/Keyboard/KeySaveSelected_22x11.png differ diff --git a/assets/icons/Keyboard/KeySaveSelected_24x11.png b/assets/icons/Keyboard/KeySaveSelected_24x11.png deleted file mode 100644 index 6e5c9ac07..000000000 Binary files a/assets/icons/Keyboard/KeySaveSelected_24x11.png and /dev/null differ diff --git a/assets/icons/Keyboard/KeySave_22x11.png b/assets/icons/Keyboard/KeySave_22x11.png new file mode 100644 index 000000000..46fd148e5 Binary files /dev/null and b/assets/icons/Keyboard/KeySave_22x11.png differ diff --git a/assets/icons/Keyboard/KeySave_24x11.png b/assets/icons/Keyboard/KeySave_24x11.png deleted file mode 100644 index 6945c7e8f..000000000 Binary files a/assets/icons/Keyboard/KeySave_24x11.png and /dev/null differ 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,