From 2214533894256b393706b6ebed1618aa964eeace Mon Sep 17 00:00:00 2001 From: Kyle Reed <3761006+kallanreed@users.noreply.github.com> Date: Mon, 31 Jul 2023 21:44:05 -0700 Subject: [PATCH] Keyboard Shift Mode (#1333) * Add "shift" concept to keyboard * Better shift colors * Better keybaord layout for symbols * Start ShiftLocked for consistency with previous UX. * Fix number layout * PR and test-drive feedback --- firmware/application/bitmap.hpp | 38 +++++++++++++ firmware/application/ui/ui_alphanum.cpp | 67 +++++++++++++++++------ firmware/application/ui/ui_alphanum.hpp | 50 ++++++++++++----- firmware/application/ui/ui_textentry.cpp | 2 - firmware/application/ui/ui_textentry.hpp | 2 +- firmware/common/ui_widget.cpp | 17 +++--- firmware/graphics/icon_shift.png | Bin 0 -> 267 bytes 7 files changed, 132 insertions(+), 44 deletions(-) create mode 100644 firmware/graphics/icon_shift.png diff --git a/firmware/application/bitmap.hpp b/firmware/application/bitmap.hpp index 0db62ddaf..c8a9ddb18 100644 --- a/firmware/application/bitmap.hpp +++ b/firmware/application/bitmap.hpp @@ -5607,6 +5607,44 @@ static constexpr Bitmap bitmap_icon_speaker_and_headphones_mute{ {16, 16}, bitmap_icon_speaker_and_headphones_mute_data}; +static constexpr uint8_t bitmap_icon_shift_data[] = { + 0x00, + 0x00, + 0x80, + 0x00, + 0xC0, + 0x01, + 0xE0, + 0x03, + 0xF0, + 0x07, + 0xF8, + 0x0F, + 0xFC, + 0x1F, + 0xE0, + 0x03, + 0xE0, + 0x03, + 0xE0, + 0x03, + 0x20, + 0x02, + 0xE0, + 0x03, + 0x20, + 0x02, + 0xE0, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, +}; +static constexpr Bitmap bitmap_icon_shift{ + {16, 16}, + bitmap_icon_shift_data}; + } /* namespace ui */ #endif /*__BITMAP_HPP__*/ diff --git a/firmware/application/ui/ui_alphanum.cpp b/firmware/application/ui/ui_alphanum.cpp index 409909b3f..e54d92cfa 100644 --- a/firmware/application/ui/ui_alphanum.cpp +++ b/firmware/application/ui/ui_alphanum.cpp @@ -22,11 +22,10 @@ #include "ui_alphanum.hpp" -#include "portapack.hpp" #include "hackrf_hal.hpp" +#include "portapack.hpp" #include "portapack_shared_memory.hpp" - -#include +#include "utility.hpp" namespace ui { @@ -38,6 +37,7 @@ AlphanumView::AlphanumView( size_t n; add_children({ + &button_shift, &labels, &field_raw, &text_raw_to_char, @@ -49,6 +49,16 @@ AlphanumView::AlphanumView( this->on_button(button); }; + button_shift.set_vertical_center(true); + button_shift.on_select = [this]() { + incr(shift_mode); + + if (shift_mode > ShiftMode::ShiftLock) + shift_mode = ShiftMode::None; + + refresh_keys(); + }; + n = 0; for (auto& button : buttons) { button.id = n; @@ -56,9 +66,9 @@ AlphanumView::AlphanumView( focused_button = button.id; }; button.on_select = button_fn; - button.set_parent_rect({static_cast((n % 5) * (240 / 5)), + button.set_parent_rect({static_cast((n % 5) * (screen_width / 5)), static_cast((n / 5) * 38 + 24), - 240 / 5, 38}); + screen_width / 5, 38}); add_child(&button); n++; } @@ -78,38 +88,59 @@ AlphanumView::AlphanumView( char_add(field_raw.value()); }; - // make text_raw_to_char widget display the char value from field_raw field_raw.on_change = [this](auto) { text_raw_to_char.set(std::string{static_cast(field_raw.value())}); }; } -void AlphanumView::set_mode(const uint32_t new_mode) { - size_t n = 0; - - if (new_mode < 3) +void AlphanumView::set_mode(uint32_t new_mode, ShiftMode new_shift_mode) { + if (new_mode < std::size(key_sets)) mode = new_mode; else mode = 0; - const char* key_list = key_sets[mode].second; + shift_mode = new_shift_mode; + refresh_keys(); + if (mode + 1 < std::size(key_sets)) + button_mode.set_text(key_sets[mode + 1].name); + else + button_mode.set_text(key_sets[0].name); +} + +void AlphanumView::refresh_keys() { + auto key_list = shift_mode == ShiftMode::None + ? key_sets[mode].normal + : key_sets[mode].shifted; + + size_t n = 0; for (auto& button : buttons) { - const std::string label{ - key_list[n]}; - button.set_text(label); + button.set_text(std::string{key_list[n]}); n++; } - if (mode < 2) - button_mode.set_text(key_sets[mode + 1].first); - else - button_mode.set_text(key_sets[0].first); + switch (shift_mode) { + case ShiftMode::None: + button_shift.set_color(Color::dark_grey()); + break; + case ShiftMode::Shift: + button_shift.set_color(Color::black()); + break; + case ShiftMode::ShiftLock: + button_shift.set_color(Color::dark_blue()); + break; + } } void AlphanumView::on_button(Button& button) { const auto c = button.text()[0]; char_add(c); + + // TODO: Consolidate shift handling. + if (shift_mode == ShiftMode::Shift) { + shift_mode = ShiftMode::None; + refresh_keys(); + } } bool AlphanumView::on_encoder(const EncoderEvent delta) { diff --git a/firmware/application/ui/ui_alphanum.hpp b/firmware/application/ui/ui_alphanum.hpp index 051546b6f..21ab8ac41 100644 --- a/firmware/application/ui/ui_alphanum.hpp +++ b/firmware/application/ui/ui_alphanum.hpp @@ -29,6 +29,10 @@ #include "ui_textentry.hpp" #include "ui_menu.hpp" +// TODO: Building this as a custom widget instead of using +// all the Button controls would save a considerable amount of RAM. +// The Buttons each have a backing string but these only need one char. + namespace ui { class AlphanumView : public TextEntryView { @@ -43,22 +47,42 @@ class AlphanumView : public TextEntryView { bool on_encoder(const EncoderEvent delta) override; private: - const char* const keys_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ, ._"; - const char* const keys_lower = "abcdefghijklmnopqrstuvwxyz, ._"; - const char* const keys_digit = "0123456789!\"#'()*+-/:;=<>@[\\]?"; - - const std::pair key_sets[3] = { - {"ABC", keys_upper}, - {"abc", keys_lower}, - {"123", keys_digit}}; + enum class ShiftMode : uint8_t { + None, + Shift, + ShiftLock, + }; + + const char* const keys_lower = "abcdefghijklmnopqrstuvwxyz, ."; + const char* const keys_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ, ."; + const char* const keys_digit = "1234567890()'`\"+-*/=<>_\\!?, ."; + const char* const keys_symbl = "!@#$%^&*()[]'`\"{}|:;<>-_~?, ."; + + struct key_set_t { + const char* name; + const char* normal; + const char* shifted; + }; + + const key_set_t key_sets[2] = { + {"abc", keys_lower, keys_upper}, + {"123", keys_digit, keys_symbl}}; int16_t focused_button = 0; - uint32_t mode = 0; // Uppercase + uint32_t mode = 0; // Letters. + ShiftMode shift_mode = ShiftMode::None; - void set_mode(const uint32_t new_mode); + void set_mode(uint32_t new_mode, ShiftMode new_shift_mode = ShiftMode::None); + void refresh_keys(); void on_button(Button& button); - std::array buttons{}; + std::array buttons{}; + + NewButton button_shift{ + {192, 214, screen_width / 5, 38}, + {}, + &bitmap_icon_shift, + Color::dark_grey()}; Labels labels{ {{1 * 8, 33 * 8}, "Raw:", Color::light_grey()}, @@ -76,11 +100,11 @@ class AlphanumView : public TextEntryView { "0"}; Button button_delete{ - {9 * 8, 33 * 8, 6 * 8, 32}, + {9 * 8, 32 * 8 - 3, 7 * 8, 3 * 16 + 3}, "= char_count_) offset = cursor_pos_ - char_count_ + 1; - // Clear the control. - painter.fill_rectangle(rect, text_style.background); - // Draw the text starting at the offset. - for (uint32_t i = 0; i < char_count_ && i + offset < text_.length(); i++) { + for (uint32_t i = 0; i < char_count_; i++) { + // Using draw_char to blank the rest of the line with spaces produces less flicker. + auto c = (i + offset < text_.length()) ? text_[i + offset] : ' '; + painter.draw_char( {rect.location().x() + (static_cast(i) * char_width), rect.location().y()}, - text_style, - text_[i + offset]); + text_style, c); } // Determine cursor position on screen (either the cursor position or the last char). @@ -1698,7 +1695,7 @@ void TextEdit::paint(Painter& painter) { painter.draw_char(cursor_point, cursor_style, text_[cursor_pos_]); // Draw the cursor. - Rect cursor_box{cursor_point, {char_width, 16}}; + Rect cursor_box{cursor_point, {char_width, char_height}}; painter.draw_rectangle(cursor_box, cursor_style.background); } diff --git a/firmware/graphics/icon_shift.png b/firmware/graphics/icon_shift.png new file mode 100644 index 0000000000000000000000000000000000000000..20f65e5d98cfbb8f234da9e25be3fd5d0935f014 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uuz(rC1}QWNE&K$eNi+$CWYg^8re>}@F^m-0ggXBa}Eyjx?-{qz; z_?$Tx&!FaXRLh^p)3#zyoJkHoJ2D jSlj$by0&}u*N^%(73D^MYM9IbP0l+XkKWT{K@ literal 0 HcmV?d00001