mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-06-13 01:58:35 +00:00
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
This commit is contained in:
parent
06b7a0419e
commit
2214533894
@ -5607,6 +5607,44 @@ static constexpr Bitmap bitmap_icon_speaker_and_headphones_mute{
|
|||||||
{16, 16},
|
{16, 16},
|
||||||
bitmap_icon_speaker_and_headphones_mute_data};
|
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 */
|
} /* namespace ui */
|
||||||
|
|
||||||
#endif /*__BITMAP_HPP__*/
|
#endif /*__BITMAP_HPP__*/
|
||||||
|
@ -22,11 +22,10 @@
|
|||||||
|
|
||||||
#include "ui_alphanum.hpp"
|
#include "ui_alphanum.hpp"
|
||||||
|
|
||||||
#include "portapack.hpp"
|
|
||||||
#include "hackrf_hal.hpp"
|
#include "hackrf_hal.hpp"
|
||||||
|
#include "portapack.hpp"
|
||||||
#include "portapack_shared_memory.hpp"
|
#include "portapack_shared_memory.hpp"
|
||||||
|
#include "utility.hpp"
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
@ -38,6 +37,7 @@ AlphanumView::AlphanumView(
|
|||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
add_children({
|
add_children({
|
||||||
|
&button_shift,
|
||||||
&labels,
|
&labels,
|
||||||
&field_raw,
|
&field_raw,
|
||||||
&text_raw_to_char,
|
&text_raw_to_char,
|
||||||
@ -49,6 +49,16 @@ AlphanumView::AlphanumView(
|
|||||||
this->on_button(button);
|
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;
|
n = 0;
|
||||||
for (auto& button : buttons) {
|
for (auto& button : buttons) {
|
||||||
button.id = n;
|
button.id = n;
|
||||||
@ -56,9 +66,9 @@ AlphanumView::AlphanumView(
|
|||||||
focused_button = button.id;
|
focused_button = button.id;
|
||||||
};
|
};
|
||||||
button.on_select = button_fn;
|
button.on_select = button_fn;
|
||||||
button.set_parent_rect({static_cast<Coord>((n % 5) * (240 / 5)),
|
button.set_parent_rect({static_cast<Coord>((n % 5) * (screen_width / 5)),
|
||||||
static_cast<Coord>((n / 5) * 38 + 24),
|
static_cast<Coord>((n / 5) * 38 + 24),
|
||||||
240 / 5, 38});
|
screen_width / 5, 38});
|
||||||
add_child(&button);
|
add_child(&button);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
@ -78,38 +88,59 @@ AlphanumView::AlphanumView(
|
|||||||
char_add(field_raw.value());
|
char_add(field_raw.value());
|
||||||
};
|
};
|
||||||
|
|
||||||
// make text_raw_to_char widget display the char value from field_raw
|
|
||||||
field_raw.on_change = [this](auto) {
|
field_raw.on_change = [this](auto) {
|
||||||
text_raw_to_char.set(std::string{static_cast<char>(field_raw.value())});
|
text_raw_to_char.set(std::string{static_cast<char>(field_raw.value())});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlphanumView::set_mode(const uint32_t new_mode) {
|
void AlphanumView::set_mode(uint32_t new_mode, ShiftMode new_shift_mode) {
|
||||||
size_t n = 0;
|
if (new_mode < std::size(key_sets))
|
||||||
|
|
||||||
if (new_mode < 3)
|
|
||||||
mode = new_mode;
|
mode = new_mode;
|
||||||
else
|
else
|
||||||
mode = 0;
|
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) {
|
for (auto& button : buttons) {
|
||||||
const std::string label{
|
button.set_text(std::string{key_list[n]});
|
||||||
key_list[n]};
|
|
||||||
button.set_text(label);
|
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode < 2)
|
switch (shift_mode) {
|
||||||
button_mode.set_text(key_sets[mode + 1].first);
|
case ShiftMode::None:
|
||||||
else
|
button_shift.set_color(Color::dark_grey());
|
||||||
button_mode.set_text(key_sets[0].first);
|
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) {
|
void AlphanumView::on_button(Button& button) {
|
||||||
const auto c = button.text()[0];
|
const auto c = button.text()[0];
|
||||||
char_add(c);
|
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) {
|
bool AlphanumView::on_encoder(const EncoderEvent delta) {
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
#include "ui_textentry.hpp"
|
#include "ui_textentry.hpp"
|
||||||
#include "ui_menu.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 {
|
namespace ui {
|
||||||
|
|
||||||
class AlphanumView : public TextEntryView {
|
class AlphanumView : public TextEntryView {
|
||||||
@ -43,22 +47,42 @@ class AlphanumView : public TextEntryView {
|
|||||||
bool on_encoder(const EncoderEvent delta) override;
|
bool on_encoder(const EncoderEvent delta) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char* const keys_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ, ._";
|
enum class ShiftMode : uint8_t {
|
||||||
const char* const keys_lower = "abcdefghijklmnopqrstuvwxyz, ._";
|
None,
|
||||||
const char* const keys_digit = "0123456789!\"#'()*+-/:;=<>@[\\]?";
|
Shift,
|
||||||
|
ShiftLock,
|
||||||
|
};
|
||||||
|
|
||||||
const std::pair<std::string, const char*> key_sets[3] = {
|
const char* const keys_lower = "abcdefghijklmnopqrstuvwxyz, .";
|
||||||
{"ABC", keys_upper},
|
const char* const keys_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ, .";
|
||||||
{"abc", keys_lower},
|
const char* const keys_digit = "1234567890()'`\"+-*/=<>_\\!?, .";
|
||||||
{"123", keys_digit}};
|
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;
|
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);
|
void on_button(Button& button);
|
||||||
|
|
||||||
std::array<Button, 30> buttons{};
|
std::array<Button, 29> buttons{};
|
||||||
|
|
||||||
|
NewButton button_shift{
|
||||||
|
{192, 214, screen_width / 5, 38},
|
||||||
|
{},
|
||||||
|
&bitmap_icon_shift,
|
||||||
|
Color::dark_grey()};
|
||||||
|
|
||||||
Labels labels{
|
Labels labels{
|
||||||
{{1 * 8, 33 * 8}, "Raw:", Color::light_grey()},
|
{{1 * 8, 33 * 8}, "Raw:", Color::light_grey()},
|
||||||
@ -76,11 +100,11 @@ class AlphanumView : public TextEntryView {
|
|||||||
"0"};
|
"0"};
|
||||||
|
|
||||||
Button button_delete{
|
Button button_delete{
|
||||||
{9 * 8, 33 * 8, 6 * 8, 32},
|
{9 * 8, 32 * 8 - 3, 7 * 8, 3 * 16 + 3},
|
||||||
"<DEL"};
|
"<DEL"};
|
||||||
|
|
||||||
Button button_mode{
|
Button button_mode{
|
||||||
{16 * 8, 33 * 8, 5 * 8, 32},
|
{16 * 8, 32 * 8 - 3, 5 * 8, 3 * 16 + 3},
|
||||||
""};
|
""};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,9 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui_textentry.hpp"
|
#include "ui_textentry.hpp"
|
||||||
//#include "portapack_persistent_memory.hpp"
|
|
||||||
#include "ui_alphanum.hpp"
|
#include "ui_alphanum.hpp"
|
||||||
//#include "ui_handwrite.hpp"
|
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ class TextEntryView : public View {
|
|||||||
|
|
||||||
TextEdit text_input;
|
TextEdit text_input;
|
||||||
Button button_ok{
|
Button button_ok{
|
||||||
{22 * 8, 33 * 8, 7 * 8, 32},
|
{21 * 8, 32 * 8 - 3, 9 * 8, 3 * 16 + 3},
|
||||||
"OK"};
|
"OK"};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1188,7 +1188,7 @@ void NewButton::paint(Painter& painter) {
|
|||||||
painter.draw_bitmap(
|
painter.draw_bitmap(
|
||||||
bmp_pos,
|
bmp_pos,
|
||||||
*bitmap_,
|
*bitmap_,
|
||||||
color_, // Color::green(), //fg,
|
color_,
|
||||||
bg);
|
bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1667,8 +1667,6 @@ void TextEdit::char_delete() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextEdit::paint(Painter& painter) {
|
void TextEdit::paint(Painter& painter) {
|
||||||
constexpr int char_width = 8;
|
|
||||||
|
|
||||||
auto rect = screen_rect();
|
auto rect = screen_rect();
|
||||||
auto text_style = has_focus() ? style().invert() : style();
|
auto text_style = has_focus() ? style().invert() : style();
|
||||||
auto offset = 0;
|
auto offset = 0;
|
||||||
@ -1677,15 +1675,14 @@ void TextEdit::paint(Painter& painter) {
|
|||||||
if (cursor_pos_ >= char_count_)
|
if (cursor_pos_ >= char_count_)
|
||||||
offset = cursor_pos_ - char_count_ + 1;
|
offset = cursor_pos_ - char_count_ + 1;
|
||||||
|
|
||||||
// Clear the control.
|
|
||||||
painter.fill_rectangle(rect, text_style.background);
|
|
||||||
|
|
||||||
// Draw the text starting at the offset.
|
// 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(
|
painter.draw_char(
|
||||||
{rect.location().x() + (static_cast<int>(i) * char_width), rect.location().y()},
|
{rect.location().x() + (static_cast<int>(i) * char_width), rect.location().y()},
|
||||||
text_style,
|
text_style, c);
|
||||||
text_[i + offset]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine cursor position on screen (either the cursor position or the last char).
|
// 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_]);
|
painter.draw_char(cursor_point, cursor_style, text_[cursor_pos_]);
|
||||||
|
|
||||||
// Draw the cursor.
|
// 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);
|
painter.draw_rectangle(cursor_box, cursor_style.background);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
firmware/graphics/icon_shift.png
Normal file
BIN
firmware/graphics/icon_shift.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 267 B |
Loading…
x
Reference in New Issue
Block a user