diff --git a/firmware/application/apps/ui_settings.cpp b/firmware/application/apps/ui_settings.cpp index 3174c5a0a..16c9171f2 100644 --- a/firmware/application/apps/ui_settings.cpp +++ b/firmware/application/apps/ui_settings.cpp @@ -721,6 +721,36 @@ void SetEncoderDialView::focus() { button_save.focus(); } +/* SetButtonsView ************************************/ + +SetButtonsView::SetButtonsView(NavigationView& nav) { + add_children({&labels, + &button_save, + &button_cancel, + &field_repeat_delay, + &field_repeat_speed, + &field_long_press_delay}); + + field_repeat_delay.set_by_value(pmem::ui_button_repeat_delay()); + field_repeat_speed.set_by_value(pmem::ui_button_repeat_speed()); + field_long_press_delay.set_by_value(pmem::ui_button_long_press_delay()); + + button_save.on_select = [&nav, this](Button&) { + pmem::set_ui_button_repeat_delay(field_repeat_delay.selected_index_value()); + pmem::set_ui_button_repeat_speed(field_repeat_speed.selected_index_value()); + pmem::set_ui_button_long_press_delay(field_long_press_delay.selected_index_value()); + nav.pop(); + }; + + button_cancel.on_select = [&nav, this](Button&) { + nav.pop(); + }; +} + +void SetButtonsView::focus() { + button_save.focus(); +} + /* AppSettingsView ************************************/ AppSettingsView::AppSettingsView( @@ -1067,6 +1097,7 @@ void SettingsMenuView::on_populate() { {"Converter", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push(); }}, {"Date/Time", ui::Color::dark_cyan(), &bitmap_icon_options_datetime, [this]() { nav_.push(); }}, {"Encoder Dial", ui::Color::dark_cyan(), &bitmap_icon_setup, [this]() { nav_.push(); }}, + {"Button Speed", ui::Color::dark_cyan(), &bitmap_icon_controls, [this]() { nav_.push(); }}, {"Freq. Correct", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push(); }}, {"P.Memory Mgmt", ui::Color::dark_cyan(), &bitmap_icon_memory, [this]() { nav_.push(); }}, {"Radio", ui::Color::dark_cyan(), &bitmap_icon_options_radio, [this]() { nav_.push(); }}, diff --git a/firmware/application/apps/ui_settings.hpp b/firmware/application/apps/ui_settings.hpp index 201d6417e..9cb4f24b7 100644 --- a/firmware/application/apps/ui_settings.hpp +++ b/firmware/application/apps/ui_settings.hpp @@ -615,6 +615,49 @@ class SetEncoderDialView : public View { }; }; +class SetButtonsView : public View { + public: + SetButtonsView(NavigationView& nav); + void focus() override; + std::string title() const override { return "Button Speed"; }; + + private: + Labels labels{ + {{1 * 8, 1 * 16}, "Adjusts response time when a", Theme::getInstance()->fg_light->foreground}, + {{1 * 8, 2 * 16}, "button is held down.", Theme::getInstance()->fg_light->foreground}, + {{2 * 8, 5 * 16}, "Repeat delay:", Theme::getInstance()->fg_light->foreground}, + {{2 * 8, 7 * 16}, "Repeat speed:", Theme::getInstance()->fg_light->foreground}, + {{2 * 8, 9 * 16}, "Long press delay:", Theme::getInstance()->fg_light->foreground}, + }; + + OptionsField field_repeat_delay{ + {20 * 8, 5 * 16}, + 6, + {{"NORMAL", false}, + {"FAST", true}}}; + + OptionsField field_repeat_speed{ + {20 * 8, 7 * 16}, + 6, + {{"NORMAL", false}, + {"FAST", true}}}; + + OptionsField field_long_press_delay{ + {20 * 8, 9 * 16}, + 6, + {{"NORMAL", false}, + {"FAST", true}}}; + + Button button_save{ + {2 * 8, 16 * 16, 12 * 8, 32}, + "Save"}; + + Button button_cancel{ + {16 * 8, 16 * 16, 12 * 8, 32}, + "Cancel", + }; +}; + class SetPersistentMemoryView : public View { public: SetPersistentMemoryView(NavigationView& nav); diff --git a/firmware/application/hw/debounce.cpp b/firmware/application/hw/debounce.cpp index 31d812370..17905edb1 100644 --- a/firmware/application/hw/debounce.cpp +++ b/firmware/application/hw/debounce.cpp @@ -84,7 +84,7 @@ bool Debounce::feed(const uint8_t bit) { // (by toggling reported state every 1/2 of the delay time) if (--repeat_ctr_ == 0) { state_to_report_ = !state_to_report_; - repeat_ctr_ = REPEAT_SUBSEQUENT_DELAY / 2; + repeat_ctr_ = portapack::persistent_memory::ui_button_repeat_speed() ? REPEAT_SUBSEQUENT_DELAY_FAST / 2 : REPEAT_SUBSEQUENT_DELAY_NORMAL / 2; return true; } } @@ -96,7 +96,7 @@ bool Debounce::feed(const uint8_t bit) { // if LONG_PRESS_DELAY is reached then finally report that switch is pressed and set flag // indicating it was a LONG press // (note that repeat_support and long_press support are mutually exclusive) - if (held_time_ >= LONG_PRESS_DELAY) { + if (held_time_ >= (portapack::persistent_memory::ui_button_long_press_delay() ? LONG_PRESS_DELAY_FAST : LONG_PRESS_DELAY_NORMAL)) { pulse_upon_release_ = false; long_press_occurred_ = true; state_to_report_ = 1; @@ -104,7 +104,7 @@ bool Debounce::feed(const uint8_t bit) { } } else if (repeat_enabled_ && !long_press_enabled_) { // Repeat support -- 4 directional buttons only (unless long_press is enabled) - if (held_time_ >= REPEAT_INITIAL_DELAY) { + if (held_time_ >= (portapack::persistent_memory::ui_button_repeat_delay() ? REPEAT_INITIAL_DELAY_FAST : REPEAT_INITIAL_DELAY_NORMAL)) { // Delay reached; trigger repeat code on NEXT tick repeat_ctr_ = 1; held_time_ = 0; diff --git a/firmware/application/hw/debounce.hpp b/firmware/application/hw/debounce.hpp index 1d042b1da..b40475588 100644 --- a/firmware/application/hw/debounce.hpp +++ b/firmware/application/hw/debounce.hpp @@ -30,9 +30,13 @@ #define DEBOUNCE_MASK ((1 << DEBOUNCE_COUNT) - 1) // # of timer0 ticks before a held button starts being counted as repeated presses -#define REPEAT_INITIAL_DELAY 250 -#define REPEAT_SUBSEQUENT_DELAY 92 -#define LONG_PRESS_DELAY 800 +#define REPEAT_INITIAL_DELAY_NORMAL 250 +#define REPEAT_SUBSEQUENT_DELAY_NORMAL 92 +#define LONG_PRESS_DELAY_NORMAL 800 + +#define REPEAT_INITIAL_DELAY_FAST 188 +#define REPEAT_SUBSEQUENT_DELAY_FAST 66 +#define LONG_PRESS_DELAY_FAST 555 class Debounce { public: diff --git a/firmware/common/portapack_persistent_memory.cpp b/firmware/common/portapack_persistent_memory.cpp index a9c12c92a..8dacde860 100644 --- a/firmware/common/portapack_persistent_memory.cpp +++ b/firmware/common/portapack_persistent_memory.cpp @@ -103,7 +103,7 @@ struct ui_config_t { uint8_t show_gui_return_icon : 1; uint8_t load_app_settings : 1; uint8_t save_app_settings : 1; - uint8_t UNUSED_1 : 1; // Deprecated, but bit can be set by older firmware + uint8_t UNUSED_7 : 1; // Deprecated, but bit can be set by older firmware bool disable_touchscreen : 1; bool hide_clock : 1; @@ -134,9 +134,9 @@ struct ui_config2_t { bool hide_numeric_battery : 1; bool hide_battery_icon : 1; bool override_batt_calc : 1; - bool UNUSED_4 : 1; - bool UNUSED_5 : 1; - bool UNUSED_6 : 1; + bool button_repeat_delay : 1; + bool button_repeat_speed : 1; + bool button_long_press_delay : 1; uint8_t theme_id; uint8_t PLACEHOLDER_3; @@ -955,6 +955,15 @@ uint8_t ui_theme_id() { bool ui_override_batt_calc() { return data->ui_config2.override_batt_calc; } +bool ui_button_repeat_delay() { + return data->ui_config2.button_repeat_delay; +} +bool ui_button_repeat_speed() { + return data->ui_config2.button_repeat_speed; +} +bool ui_button_long_press_delay() { + return data->ui_config2.button_long_press_delay; +} void set_ui_hide_speaker(bool v) { data->ui_config2.hide_speaker = v; @@ -1000,6 +1009,15 @@ void set_ui_theme_id(uint8_t theme_id) { void set_ui_override_batt_calc(bool v) { data->ui_config2.override_batt_calc = v; } +void set_ui_button_repeat_delay(bool v) { + data->ui_config2.button_repeat_delay = v; +} +void set_ui_button_repeat_speed(bool v) { + data->ui_config2.button_repeat_speed = v; +} +void set_ui_button_long_press_delay(bool v) { + data->ui_config2.button_long_press_delay = v; +} /* Converter */ bool config_converter() { @@ -1262,7 +1280,6 @@ bool debug_dump() { pmem_dump_file.write_line("ui_config show_gui_return_icon: " + to_string_dec_uint(data->ui_config.show_gui_return_icon)); pmem_dump_file.write_line("ui_config load_app_settings: " + to_string_dec_uint(data->ui_config.load_app_settings)); pmem_dump_file.write_line("ui_config save_app_settings: " + to_string_dec_uint(data->ui_config.save_app_settings)); - // pmem_dump_file.write_line("ui_config show_bigger_qr_code: " + to_string_dec_uint(data->ui_config.show_large_qr_code)); pmem_dump_file.write_line("ui_config disable_touchscreen: " + to_string_dec_uint(data->ui_config.disable_touchscreen)); pmem_dump_file.write_line("ui_config hide_clock: " + to_string_dec_uint(data->ui_config.hide_clock)); pmem_dump_file.write_line("ui_config clock_with_date: " + to_string_dec_uint(data->ui_config.clock_show_date)); @@ -1287,6 +1304,9 @@ bool debug_dump() { pmem_dump_file.write_line("ui_config2 hide_numeric_battery: " + to_string_dec_uint(data->ui_config2.hide_numeric_battery)); pmem_dump_file.write_line("ui_config2 theme_id: " + to_string_dec_uint(data->ui_config2.theme_id)); pmem_dump_file.write_line("ui_config2 override_batt_calc: " + to_string_dec_uint(data->ui_config2.override_batt_calc)); + pmem_dump_file.write_line("ui_config2 button_repeat_delay: " + to_string_dec_uint(data->ui_config2.button_repeat_delay)); + pmem_dump_file.write_line("ui_config2 button_repeat_speed: " + to_string_dec_uint(data->ui_config2.button_repeat_speed)); + pmem_dump_file.write_line("ui_config2 button_long_press_delay: " + to_string_dec_uint(data->ui_config2.button_long_press_delay)); // misc_config bits pmem_dump_file.write_line("misc_config config_audio_mute: " + to_string_dec_int(config_audio_mute())); diff --git a/firmware/common/portapack_persistent_memory.hpp b/firmware/common/portapack_persistent_memory.hpp index 18395db2f..5248ae6a6 100644 --- a/firmware/common/portapack_persistent_memory.hpp +++ b/firmware/common/portapack_persistent_memory.hpp @@ -340,6 +340,9 @@ bool ui_hide_battery_icon(); bool ui_hide_sd_card(); uint8_t ui_theme_id(); bool ui_override_batt_calc(); +bool ui_button_repeat_delay(); +bool ui_button_repeat_speed(); +bool ui_button_long_press_delay(); void set_ui_hide_speaker(bool v); void set_ui_hide_mute(bool v); void set_ui_hide_converter(bool v); @@ -354,6 +357,9 @@ void set_ui_hide_battery_icon(bool v); void set_ui_hide_sd_card(bool v); void set_ui_theme_id(uint8_t v); void set_ui_override_batt_calc(bool v); +void set_ui_button_repeat_delay(bool v); +void set_ui_button_repeat_speed(bool v); +void set_ui_button_long_press_delay(bool v); // sd persisting settings bool should_use_sdcard_for_pmem();