[FL-1234] Keyboards redesign (#501)
* text input: keyboard redesign,; input: tune repeat keypress timing; archive: fix max string width when scrollbar is shown * byte input: redesign * byte/text input: long press back to activate backspace added * archive: pass absolute path to app * format sources * better keyboard timings Co-authored-by: SG <who.just.the.doctor@gmail.com>
This commit is contained in:
parent
7f16c9fe5a
commit
d5df0483a3
@ -130,7 +130,6 @@ static void set_file_type(ArchiveFile_t* file, FileInfo* file_info) {
|
|||||||
|
|
||||||
static bool archive_get_filenames(ArchiveApp* archive) {
|
static bool archive_get_filenames(ArchiveApp* archive) {
|
||||||
furi_assert(archive);
|
furi_assert(archive);
|
||||||
|
|
||||||
FS_Dir_Api* dir_api = &archive->fs_api->dir;
|
FS_Dir_Api* dir_api = &archive->fs_api->dir;
|
||||||
ArchiveFile_t item;
|
ArchiveFile_t item;
|
||||||
FileInfo file_info;
|
FileInfo file_info;
|
||||||
@ -169,7 +168,6 @@ static bool archive_get_filenames(ArchiveApp* archive) {
|
|||||||
files_array_push_back(model->files, item);
|
files_array_push_back(model->files, item);
|
||||||
ArchiveFile_t_clear(&item);
|
ArchiveFile_t_clear(&item);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
dir_api->close(&directory);
|
dir_api->close(&directory);
|
||||||
string_clear(name);
|
string_clear(name);
|
||||||
@ -329,8 +327,15 @@ static void archive_file_menu_callback(ArchiveApp* archive) {
|
|||||||
switch(model->menu_idx) {
|
switch(model->menu_idx) {
|
||||||
case 0:
|
case 0:
|
||||||
if((selected->type != ArchiveFileTypeFolder && selected->type != ArchiveFileTypeUnknown)) {
|
if((selected->type != ArchiveFileTypeFolder && selected->type != ArchiveFileTypeUnknown)) {
|
||||||
|
string_t full_path;
|
||||||
|
string_init_set(full_path, archive->browser.path);
|
||||||
|
string_cat(full_path, "/");
|
||||||
|
string_cat(full_path, selected->name);
|
||||||
|
|
||||||
archive_open_app(
|
archive_open_app(
|
||||||
archive, flipper_app_name[selected->type], string_get_cstr(selected->name));
|
archive, flipper_app_name[selected->type], string_get_cstr(full_path));
|
||||||
|
|
||||||
|
string_clear(full_path);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -89,7 +89,7 @@ static void draw_list(Canvas* canvas, ArchiveViewModel* model) {
|
|||||||
string_set(str_buff, file->name);
|
string_set(str_buff, file->name);
|
||||||
|
|
||||||
if(is_known_app(file->type)) trim_file_ext(str_buff);
|
if(is_known_app(file->type)) trim_file_ext(str_buff);
|
||||||
elements_string_fit_width(canvas, str_buff, MAX_LEN_PX);
|
elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
|
||||||
|
|
||||||
if(model->idx == idx) {
|
if(model->idx == idx) {
|
||||||
archive_draw_frame(canvas, i, scrollbar);
|
archive_draw_frame(canvas, i, scrollbar);
|
||||||
|
@ -150,10 +150,13 @@ static char byte_input_get_nibble_text(uint8_t byte, bool high_nibble) {
|
|||||||
* @param model
|
* @param model
|
||||||
*/
|
*/
|
||||||
static void byte_input_draw_input(Canvas* canvas, ByteInputModel* model) {
|
static void byte_input_draw_input(Canvas* canvas, ByteInputModel* model) {
|
||||||
const uint8_t text_x = 3;
|
const uint8_t text_x = 8;
|
||||||
const uint8_t text_y = 25;
|
const uint8_t text_y = 25;
|
||||||
|
|
||||||
elements_slightly_rounded_frame(canvas, 1, 14, 126, 15);
|
elements_slightly_rounded_frame(canvas, 6, 14, 116, 15);
|
||||||
|
|
||||||
|
canvas_draw_icon_name(canvas, 2, 19, I_ButtonLeftSmall_3x5);
|
||||||
|
canvas_draw_icon_name(canvas, 123, 19, I_ButtonRightSmall_3x5);
|
||||||
|
|
||||||
for(uint8_t i = model->first_visible_byte;
|
for(uint8_t i = model->first_visible_byte;
|
||||||
i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes);
|
i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes);
|
||||||
@ -234,12 +237,15 @@ static void byte_input_draw_input(Canvas* canvas, ByteInputModel* model) {
|
|||||||
* @param model
|
* @param model
|
||||||
*/
|
*/
|
||||||
static void byte_input_draw_input_selected(Canvas* canvas, ByteInputModel* model) {
|
static void byte_input_draw_input_selected(Canvas* canvas, ByteInputModel* model) {
|
||||||
const uint8_t text_x = 3;
|
const uint8_t text_x = 7;
|
||||||
const uint8_t text_y = 25;
|
const uint8_t text_y = 25;
|
||||||
|
|
||||||
canvas_draw_box(canvas, 0, 12, 128, 19);
|
canvas_draw_box(canvas, 0, 12, 127, 19);
|
||||||
canvas_invert_color(canvas);
|
canvas_invert_color(canvas);
|
||||||
elements_slightly_rounded_frame(canvas, 1, 14, 126, 15);
|
|
||||||
|
elements_slightly_rounded_frame(canvas, 6, 14, 115, 15);
|
||||||
|
canvas_draw_icon_name(canvas, 2, 19, I_ButtonLeftSmall_3x5);
|
||||||
|
canvas_draw_icon_name(canvas, 122, 19, I_ButtonRightSmall_3x5);
|
||||||
|
|
||||||
for(uint8_t i = model->first_visible_byte;
|
for(uint8_t i = model->first_visible_byte;
|
||||||
i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes);
|
i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes);
|
||||||
@ -247,7 +253,7 @@ static void byte_input_draw_input_selected(Canvas* canvas, ByteInputModel* model
|
|||||||
uint8_t byte_position = i - model->first_visible_byte;
|
uint8_t byte_position = i - model->first_visible_byte;
|
||||||
|
|
||||||
if(i == model->selected_byte) {
|
if(i == model->selected_byte) {
|
||||||
canvas_draw_box(canvas, text_x + byte_position * 14, text_y - 9, 15, 11);
|
canvas_draw_box(canvas, text_x + 1 + byte_position * 14, text_y - 9, 13, 11);
|
||||||
canvas_invert_color(canvas);
|
canvas_invert_color(canvas);
|
||||||
canvas_draw_glyph(
|
canvas_draw_glyph(
|
||||||
canvas,
|
canvas,
|
||||||
@ -406,6 +412,17 @@ static void byte_input_call_changed_callback(ByteInputModel* model) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear selected byte
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void byte_input_clear_selected_byte(ByteInputModel* model) {
|
||||||
|
model->bytes[model->selected_byte] = 0;
|
||||||
|
model->selected_high_nibble = true;
|
||||||
|
byte_input_dec_selected_byte(model);
|
||||||
|
byte_input_call_changed_callback(model);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handle up button
|
* @brief Handle up button
|
||||||
*
|
*
|
||||||
@ -478,10 +495,7 @@ static void byte_input_handle_ok(ByteInputModel* model) {
|
|||||||
if(value == enter_symbol) {
|
if(value == enter_symbol) {
|
||||||
byte_input_call_input_callback(model);
|
byte_input_call_input_callback(model);
|
||||||
} else if(value == backspace_symbol) {
|
} else if(value == backspace_symbol) {
|
||||||
model->bytes[model->selected_byte] = 0;
|
byte_input_clear_selected_byte(model);
|
||||||
model->selected_high_nibble = true;
|
|
||||||
byte_input_dec_selected_byte(model);
|
|
||||||
byte_input_call_changed_callback(model);
|
|
||||||
} else {
|
} else {
|
||||||
byte_input_set_nibble(
|
byte_input_set_nibble(
|
||||||
model->bytes, model->selected_byte, value, model->selected_high_nibble);
|
model->bytes, model->selected_byte, value, model->selected_high_nibble);
|
||||||
@ -647,6 +661,16 @@ static bool byte_input_view_input_callback(InputEvent* event, void* context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((event->type == InputTypeLong || event->type == InputTypeRepeat) &&
|
||||||
|
event->key == InputKeyBack) {
|
||||||
|
with_view_model(
|
||||||
|
byte_input->view, (ByteInputModel * model) {
|
||||||
|
byte_input_clear_selected_byte(model);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,10 +42,10 @@ static const TextInputKey keyboard_keys_row_1[] = {
|
|||||||
{'i', 64, 8},
|
{'i', 64, 8},
|
||||||
{'o', 73, 8},
|
{'o', 73, 8},
|
||||||
{'p', 82, 8},
|
{'p', 82, 8},
|
||||||
{'7', 91, 8},
|
{'0', 91, 8},
|
||||||
{'8', 100, 8},
|
{'1', 100, 8},
|
||||||
{'9', 109, 8},
|
{'2', 110, 8},
|
||||||
{'_', 118, 8},
|
{'3', 120, 8},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const TextInputKey keyboard_keys_row_2[] = {
|
static const TextInputKey keyboard_keys_row_2[] = {
|
||||||
@ -58,10 +58,10 @@ static const TextInputKey keyboard_keys_row_2[] = {
|
|||||||
{'j', 55, 20},
|
{'j', 55, 20},
|
||||||
{'k', 64, 20},
|
{'k', 64, 20},
|
||||||
{'l', 73, 20},
|
{'l', 73, 20},
|
||||||
{'4', 82, 20},
|
{BACKSPACE_KEY, 82, 12},
|
||||||
{'5', 91, 20},
|
{'4', 100, 20},
|
||||||
{'6', 100, 20},
|
{'5', 110, 20},
|
||||||
{BACKSPACE_KEY, 110, 12},
|
{'6', 120, 20},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const TextInputKey keyboard_keys_row_3[] = {
|
static const TextInputKey keyboard_keys_row_3[] = {
|
||||||
@ -72,11 +72,11 @@ static const TextInputKey keyboard_keys_row_3[] = {
|
|||||||
{'b', 37, 32},
|
{'b', 37, 32},
|
||||||
{'n', 46, 32},
|
{'n', 46, 32},
|
||||||
{'m', 55, 32},
|
{'m', 55, 32},
|
||||||
{'0', 64, 32},
|
{'_', 64, 32},
|
||||||
{'1', 73, 32},
|
{ENTER_KEY, 74, 23},
|
||||||
{'2', 82, 32},
|
{'7', 100, 32},
|
||||||
{'3', 91, 32},
|
{'8', 110, 32},
|
||||||
{ENTER_KEY, 102, 23},
|
{'9', 120, 32},
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint8_t get_row_size(uint8_t row_index) {
|
static uint8_t get_row_size(uint8_t row_index) {
|
||||||
@ -127,24 +127,41 @@ static const char char_to_uppercase(const char letter) {
|
|||||||
return (letter - 0x20);
|
return (letter - 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void text_input_backspace_cb(TextInputModel* model) {
|
||||||
|
uint8_t text_length = strlen(model->text);
|
||||||
|
if(text_length > 0) {
|
||||||
|
model->text[text_length - 1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void text_input_view_draw_callback(Canvas* canvas, void* _model) {
|
static void text_input_view_draw_callback(Canvas* canvas, void* _model) {
|
||||||
TextInputModel* model = _model;
|
TextInputModel* model = _model;
|
||||||
uint8_t text_length = strlen(model->text);
|
uint8_t text_length = strlen(model->text);
|
||||||
uint8_t needed_string_width = canvas_width(canvas) - 4 - 7 - 4;
|
uint8_t needed_string_width = canvas_width(canvas) - 8;
|
||||||
|
uint8_t start_pos = 4;
|
||||||
|
|
||||||
char* text = model->text;
|
char* text = model->text;
|
||||||
|
|
||||||
canvas_clear(canvas);
|
canvas_clear(canvas);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
|
||||||
canvas_draw_str(canvas, 2, 8, model->header);
|
canvas_draw_str(canvas, 2, 8, model->header);
|
||||||
elements_slightly_rounded_frame(canvas, 1, 12, 122, 15);
|
elements_slightly_rounded_frame(canvas, 1, 12, 126, 15);
|
||||||
|
|
||||||
|
if(canvas_string_width(canvas, text) > needed_string_width) {
|
||||||
|
canvas_draw_str(canvas, start_pos, 22, "...");
|
||||||
|
start_pos += 6;
|
||||||
|
needed_string_width -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
while(text != 0 && canvas_string_width(canvas, text) > needed_string_width) {
|
while(text != 0 && canvas_string_width(canvas, text) > needed_string_width) {
|
||||||
text++;
|
text++;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas_draw_str(canvas, 4, 22, text);
|
canvas_draw_str(canvas, start_pos, 22, text);
|
||||||
canvas_draw_str(canvas, 4 + canvas_string_width(canvas, text) + 1, 22, "|");
|
|
||||||
|
canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 1, 22, "|");
|
||||||
|
canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 2, 22, "|");
|
||||||
|
|
||||||
canvas_set_font(canvas, FontKeyboard);
|
canvas_set_font(canvas, FontKeyboard);
|
||||||
|
|
||||||
@ -220,6 +237,9 @@ static void text_input_handle_up(TextInput* text_input) {
|
|||||||
text_input->view, (TextInputModel * model) {
|
text_input->view, (TextInputModel * model) {
|
||||||
if(model->selected_row > 0) {
|
if(model->selected_row > 0) {
|
||||||
model->selected_row--;
|
model->selected_row--;
|
||||||
|
if(model->selected_column > get_row_size(model->selected_row) - 5) {
|
||||||
|
model->selected_column = model->selected_column + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@ -230,8 +250,8 @@ static void text_input_handle_down(TextInput* text_input) {
|
|||||||
text_input->view, (TextInputModel * model) {
|
text_input->view, (TextInputModel * model) {
|
||||||
if(model->selected_row < keyboard_row_count - 1) {
|
if(model->selected_row < keyboard_row_count - 1) {
|
||||||
model->selected_row++;
|
model->selected_row++;
|
||||||
if(model->selected_column > get_row_size(model->selected_row) - 1) {
|
if(model->selected_column > get_row_size(model->selected_row) - 4) {
|
||||||
model->selected_column = get_row_size(model->selected_row) - 1;
|
model->selected_column = model->selected_column - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -273,9 +293,7 @@ static void text_input_handle_ok(TextInput* text_input) {
|
|||||||
model->callback(model->callback_context, model->text);
|
model->callback(model->callback_context, model->text);
|
||||||
}
|
}
|
||||||
} else if(selected == BACKSPACE_KEY) {
|
} else if(selected == BACKSPACE_KEY) {
|
||||||
if(text_length > 0) {
|
text_input_backspace_cb(model);
|
||||||
model->text[text_length - 1] = 0;
|
|
||||||
}
|
|
||||||
} else if(text_length < model->max_text_length) {
|
} else if(text_length < model->max_text_length) {
|
||||||
if(text_length == 0 && char_is_lowercase(selected)) {
|
if(text_length == 0 && char_is_lowercase(selected)) {
|
||||||
selected = char_to_uppercase(selected);
|
selected = char_to_uppercase(selected);
|
||||||
@ -319,6 +337,17 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((event->type == InputTypeLong || event->type == InputTypeRepeat) &&
|
||||||
|
event->key == InputKeyBack) {
|
||||||
|
with_view_model(
|
||||||
|
text_input->view, (TextInputModel * model) {
|
||||||
|
text_input_backspace_cb(model);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
#include <api-hal-gpio.h>
|
#include <api-hal-gpio.h>
|
||||||
|
|
||||||
#define INPUT_DEBOUNCE_TICKS_HALF (INPUT_DEBOUNCE_TICKS / 2)
|
#define INPUT_DEBOUNCE_TICKS_HALF (INPUT_DEBOUNCE_TICKS / 2)
|
||||||
#define INPUT_PRESS_TICKS 200
|
#define INPUT_PRESS_TICKS 150
|
||||||
#define INPUT_LONG_PRESS_COUNTS 4
|
#define INPUT_LONG_PRESS_COUNTS 2
|
||||||
#define INPUT_THREAD_FLAG_ISR 0x00000001
|
#define INPUT_THREAD_FLAG_ISR 0x00000001
|
||||||
|
|
||||||
/* Input pin state */
|
/* Input pin state */
|
||||||
|
Loading…
Reference in New Issue
Block a user