Skip to content

Commit 6e87d5c

Browse files
author
Chris Warren-Smith
committed
UI: refactoring to allow alternative keypad layouts
1 parent 4fbdec5 commit 6e87d5c

File tree

4 files changed

+150
-95
lines changed

4 files changed

+150
-95
lines changed

src/ui/image_codec.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,22 +84,24 @@ bool ImageCodec::encode(uint8_t **data, size_t *size) const {
8484
void ImageCodec::resize(unsigned width, unsigned height) {
8585
auto *pixels = new uint8_t[width * height * 4];
8686

87-
for (int y = 0; y < height; y++) {
87+
for (unsigned y = 0; y < height; y++) {
8888
float gy = ((float)y + 0.5f) * _height / height - 0.5f;
89-
int y0 = (int)gy, y1 = y0 + 1;
89+
unsigned y0 = (unsigned)gy;
90+
unsigned y1 = y0 + 1;
9091
float fy = gy - y0;
9192
y0 = y0 < 0 ? 0 : (y0 >= _height ? _height - 1 : y0);
9293
y1 = y1 < 0 ? 0 : (y1 >= _height ? _height - 1 : y1);
9394

94-
for (int x = 0; x < width; x++) {
95+
for (unsigned x = 0; x < width; x++) {
9596
float gx = ((float)x + 0.5f) * _width / width - 0.5f;
96-
int x0 = (int)gx, x1 = x0 + 1;
97+
unsigned x0 = (unsigned)gx;
98+
unsigned x1 = x0 + 1;
9799
float fx = gx - x0;
98100
x0 = x0 < 0 ? 0 : (x0 >= _width ? _width - 1 : x0);
99101
x1 = x1 < 0 ? 0 : (x1 >= _width ? _width - 1 : x1);
100102

101103
int offset = 4 * (y * width + x);
102-
for (int c = 0; c < 4; c++) {
104+
for (unsigned c = 0; c < 4; c++) {
103105
// A, R, G, B
104106
float tl = _pixels[4 * (y0 * _width + x0) + c];
105107
float tr = _pixels[4 * (y0 * _width + x1) + c];

src/ui/keypad.cpp

Lines changed: 124 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,10 @@
1414
#include "ui/keypad_icons.h"
1515
#include "keypad.h"
1616

17-
constexpr int ROW_LENGTHS[] = {7, 10, 9, 9, 9};
18-
constexpr int MAX_ROWS = 5;
19-
constexpr int MAX_COLS = 10;
20-
constexpr int QWERTY_ROW = 1;
21-
constexpr int ASDF_ROW = 2;
22-
constexpr int SPACE_COLS = 3;
17+
// the size of PNGs as defined in keypad/build.sh
2318
constexpr int IMAGE_SIZE = 30;
19+
20+
// PI
2421
constexpr double PI = 3.14159;
2522

2623
// padding size based on character height
@@ -49,74 +46,111 @@ KeypadTheme MODERN_DARK_THEME = {
4946
._funcKeyHighlight = 0x90a4ae, // Blue Grey 300 (matching accent highlight)
5047
};
5148

52-
constexpr RawKey KEYS[MAX_ROWS][MAX_COLS] = {
53-
// Toolbar
54-
{
55-
{K_CUT, K_CUT, K_CUT, K_CUT},
56-
{K_COPY, K_COPY, K_COPY, K_COPY},
57-
{K_PASTE, K_PASTE, K_PASTE, K_PASTE},
58-
{K_SEARCH, K_SEARCH, K_SEARCH, K_SEARCH},
59-
{K_SAVE, K_SAVE, K_SAVE, K_SAVE},
60-
{K_RUN, K_RUN, K_RUN, K_RUN},
61-
{K_HELP, K_HELP, K_HELP, K_HELP},
62-
{K_NULL},
63-
{K_NULL},
64-
{K_NULL}
65-
},
66-
// QWERTY
67-
{
68-
{K_q, K_1, K_1, K_Q},
69-
{K_w, K_2, K_2, K_W},
70-
{K_e, K_3, K_3, K_E},
71-
{K_r, K_4, K_4, K_R},
72-
{K_t, K_5, K_5, K_T},
73-
{K_y, K_6, K_6, K_Y},
74-
{K_u, K_7, K_7, K_U},
75-
{K_i, K_8, K_8, K_I},
76-
{K_o, K_9, K_9, K_O},
77-
{K_p, K_0, K_0, K_P}
78-
},
79-
// ASDF
80-
{
81-
{K_a, K_COMMA, K_HASH, K_A},
82-
{K_s, K_EQUALS, K_SEMICOLON, K_S},
83-
{K_d, K_LPAREN, K_QUESTION, K_D},
84-
{K_f, K_RPAREN, K_AMPERSAND, K_F},
85-
{K_g, K_QUOTE, K_DOLLAR, K_G},
86-
{K_h, K_APOSTROPHE, K_EXCLAIM, K_H},
87-
{K_j, K_PERIOD, K_AT, K_J},
88-
{K_k, K_MINUS, K_SLASH, K_K},
89-
{K_l, K_ASTERISK, K_BACKSLASH, K_L},
90-
{K_NULL}
91-
},
92-
// ZXC
93-
{
94-
{K_TOGGLE, K_TOGGLE, K_TOGGLE, K_TOGGLE},
95-
{K_z, K_UNDERSCORE, K_CARET, K_Z},
96-
{K_x, K_PLUS, K_LBRACE, K_X},
97-
{K_c, K_COLON, K_RBRACE, K_C},
98-
{K_v, K_LBRACKET, K_PIPE, K_V},
99-
{K_b, K_RBRACKET, K_PERCENT, K_B},
100-
{K_n, K_LESS, K_BACKTICK, K_N},
101-
{K_m, K_GREATER, K_TILDE, K_M},
102-
{K_BACKSPACE, K_BACKSPACE, K_BACKSPACE, K_BACKSPACE},
103-
{K_NULL}
104-
},
105-
// FUNCs, SPACE
106-
{
107-
{K_LINE_UP, K_PAGE_UP, K_LINE_UP, K_PAGE_UP},
108-
{K_LINE_DOWN, K_PAGE_DOWN, K_LINE_DOWN, K_PAGE_DOWN},
109-
{K_LPAREN, K_SLASH, K_COMMA, K_LBRACKET},
110-
{K_SPACE, K_SPACE, K_SPACE, K_SPACE},
111-
{K_RPAREN, K_HASH, K_EQUALS, K_RBRACKET},
112-
{K_TAG, K_TAG, K_TAG, K_TAG},
113-
{K_ENTER, K_ENTER, K_ENTER, K_ENTER},
114-
{K_NULL},
115-
{K_NULL},
116-
{K_NULL},
117-
}
49+
// compact layout for mobile devices in portrait mode
50+
namespace MobileKeypadLayout {
51+
constexpr int ROW_LENGTHS[] = {7, 10, 9, 9, 9};
52+
constexpr int MAX_ROWS = 5;
53+
constexpr int MAX_COLS = 10;
54+
constexpr int QWERTY_ROW = 1;
55+
constexpr int ASDF_ROW = 2;
56+
constexpr int SPACE_COLS = 3;
57+
constexpr RawKey KEYS[MAX_ROWS][MAX_COLS] = {
58+
// Toolbar
59+
{
60+
{K_CUT, K_CUT, K_CUT, K_CUT},
61+
{K_COPY, K_COPY, K_COPY, K_COPY},
62+
{K_PASTE, K_PASTE, K_PASTE, K_PASTE},
63+
{K_SEARCH, K_SEARCH, K_SEARCH, K_SEARCH},
64+
{K_SAVE, K_SAVE, K_SAVE, K_SAVE},
65+
{K_RUN, K_RUN, K_RUN, K_RUN},
66+
{K_HELP, K_HELP, K_HELP, K_HELP},
67+
{K_NULL},
68+
{K_NULL},
69+
{K_NULL}
70+
},
71+
// QWERTY
72+
{
73+
{K_q, K_1, K_1, K_Q},
74+
{K_w, K_2, K_2, K_W},
75+
{K_e, K_3, K_3, K_E},
76+
{K_r, K_4, K_4, K_R},
77+
{K_t, K_5, K_5, K_T},
78+
{K_y, K_6, K_6, K_Y},
79+
{K_u, K_7, K_7, K_U},
80+
{K_i, K_8, K_8, K_I},
81+
{K_o, K_9, K_9, K_O},
82+
{K_p, K_0, K_0, K_P}
83+
},
84+
// ASDF
85+
{
86+
{K_a, K_COMMA, K_HASH, K_A},
87+
{K_s, K_EQUALS, K_SEMICOLON, K_S},
88+
{K_d, K_LPAREN, K_QUESTION, K_D},
89+
{K_f, K_RPAREN, K_AMPERSAND, K_F},
90+
{K_g, K_QUOTE, K_DOLLAR, K_G},
91+
{K_h, K_APOSTROPHE, K_EXCLAIM, K_H},
92+
{K_j, K_PERIOD, K_AT, K_J},
93+
{K_k, K_MINUS, K_SLASH, K_K},
94+
{K_l, K_ASTERISK, K_BACKSLASH, K_L},
95+
{K_NULL}
96+
},
97+
// ZXC
98+
{
99+
{K_TOGGLE, K_TOGGLE, K_TOGGLE, K_TOGGLE},
100+
{K_z, K_UNDERSCORE, K_CARET, K_Z},
101+
{K_x, K_PLUS, K_LBRACE, K_X},
102+
{K_c, K_COLON, K_RBRACE, K_C},
103+
{K_v, K_LBRACKET, K_PIPE, K_V},
104+
{K_b, K_RBRACKET, K_PERCENT, K_B},
105+
{K_n, K_LESS, K_BACKTICK, K_N},
106+
{K_m, K_GREATER, K_TILDE, K_M},
107+
{K_BACKSPACE, K_BACKSPACE, K_BACKSPACE, K_BACKSPACE},
108+
{K_NULL}
109+
},
110+
// FUNCs, SPACE
111+
{
112+
{K_LINE_UP, K_PAGE_UP, K_LINE_UP, K_PAGE_UP},
113+
{K_LINE_DOWN, K_PAGE_DOWN, K_LINE_DOWN, K_PAGE_DOWN},
114+
{K_LPAREN, K_SLASH, K_COMMA, K_LBRACKET},
115+
{K_SPACE, K_SPACE, K_SPACE, K_SPACE},
116+
{K_RPAREN, K_HASH, K_EQUALS, K_RBRACKET},
117+
{K_TAG, K_TAG, K_TAG, K_TAG},
118+
{K_ENTER, K_ENTER, K_ENTER, K_ENTER},
119+
{K_NULL},
120+
{K_NULL},
121+
{K_NULL},
122+
}
123+
};
124+
125+
struct Impl : public KeypadLayout {
126+
RawKey getRawKey(int row, int col) const override {
127+
return KEYS[row][col];
128+
}
129+
130+
int getMaxRowLength() const override {
131+
return ROW_LENGTHS[QWERTY_ROW];
132+
}
133+
134+
int getMaxRows() const override {
135+
return MAX_ROWS;
136+
}
137+
138+
int getRowLength(int row) const override {
139+
return ROW_LENGTHS[row];
140+
};
141+
142+
int getSpaceCols() const override {
143+
return SPACE_COLS;
144+
}
145+
146+
bool isWideRow(int row) const override {
147+
return row == QWERTY_ROW || row == ASDF_ROW;
148+
}
149+
};
118150
};
119151

152+
KeypadLayout::~KeypadLayout() = default;
153+
120154
//
121155
// KeypadImage
122156
//
@@ -202,6 +236,7 @@ KeyCode KeypadDrawContext::getKey(RawKey key) const {
202236
case kNumber: keyCode = key._number; break;
203237
case kSymbol: keyCode = key._symbol; break;
204238
case kSize: keyCode = K_NULL; break;
239+
default: keyCode = K_NULL; break;
205240
}
206241
return keyCode;
207242
}
@@ -414,46 +449,51 @@ Keypad::Keypad(int charWidth, int charHeight, bool toolbar)
414449
_width(0),
415450
_height(0),
416451
_padding(static_cast<int>(charHeight * PADDING_FACTOR)),
417-
_theme(&MODERN_DARK_THEME),
418-
_context(charWidth, charHeight),
419452
_toolbar(toolbar),
420-
_pressed(nullptr) {
453+
_pressed(nullptr),
454+
_theme(&MODERN_DARK_THEME),
455+
_context(charWidth, charHeight) {
456+
selectLayout();
421457
generateKeys();
422458
}
423459

424460
void Keypad::generateKeys() {
425461
_keys.clear();
426462

427-
const int rows = _toolbar ? 1 : MAX_ROWS;
463+
const int rows = _toolbar ? 1 : _layout->getMaxRows();
428464
for (int row = 0; row < rows; ++row) {
429-
int cols = ROW_LENGTHS[row];
465+
int cols = _layout->getRowLength(row);
430466
for (int col = 0; col < cols; col++) {
431-
const RawKey &k = KEYS[row][col];
467+
const RawKey &k = _layout->getRawKey(row, col);
432468
if (k._lower != K_NULL) {
433469
_keys.add(new Key(k));
434470
}
435471
}
436472
}
437473
}
438474

475+
void Keypad::selectLayout() {
476+
_layout = std::make_unique<MobileKeypadLayout::Impl>();
477+
}
478+
439479
void Keypad::layout(int x, int y, int w, int h) {
440480
_posX = x;
441481
_posY = y;
442482
_width = w;
443483
_height = h;
444484

445485
const int width = _width - _padding;
446-
const int keyW = width / ROW_LENGTHS[QWERTY_ROW];
486+
const int keyW = width / _layout->getMaxRowLength();
447487
const int keyH = _context._charHeight + _padding * 2;
448488
const int xStart = _posX + ((w - _width) / 2);
449-
const int rows = _toolbar ? 1 : MAX_ROWS;
489+
const int rows = _toolbar ? 1 : _layout->getMaxRows();
450490
int yPos = _posY;
451491
int index = 0;
452492

453493
for (int row = 0; row < rows; ++row) {
454-
const int cols = ROW_LENGTHS[row];
494+
const int cols = _layout->getRowLength(row);
455495
int xPos = xStart;
456-
if (row == QWERTY_ROW || row == ASDF_ROW) {
496+
if (_layout->isWideRow(row)) {
457497
const int rowWidth = keyW * cols;
458498
xPos += (_width - rowWidth) / 2;
459499
}
@@ -473,7 +513,7 @@ void Keypad::layout(int x, int y, int w, int h) {
473513
const int numKeys = 2;
474514
keyWidth = (_width - ((cols - numKeys) * keyW)) / numKeys;
475515
} else if (key->_key._lower == K_SPACE) {
476-
keyWidth = (SPACE_COLS * keyW);
516+
keyWidth = (_layout->getSpaceCols() * keyW);
477517
}
478518
key->_x = xPos;
479519
key->_y = yPos;
@@ -491,7 +531,7 @@ int Keypad::layoutHeight(int screenHeight) {
491531
int charHeight = _context._charHeight;
492532
int maxHeight = static_cast<int>(screenHeight * MAX_HEIGHT_FACTOR);
493533
int padding = static_cast<int>(charHeight * PADDING_FACTOR);
494-
int rows = _toolbar ? 1 : MAX_ROWS;
534+
int rows = _toolbar ? 1 : _layout->getMaxRows();
495535
int height = rows * ((padding * 2) + charHeight);
496536
if (height > maxHeight) {
497537
// h = r(ch + 2p) -> p = (h - r * ch) / (r * 2)

src/ui/keypad.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#pragma once
1010

11+
#include <memory>
1112
#include "ui/strlib.h"
1213
#include "ui/inputs.h"
1314
#include "ui/image_codec.h"
@@ -100,6 +101,16 @@ struct Key {
100101
bool _printable;
101102
};
102103

104+
struct KeypadLayout {
105+
virtual ~KeypadLayout();
106+
virtual RawKey getRawKey(int row, int col) const = 0;
107+
virtual int getMaxRowLength() const = 0;
108+
virtual int getMaxRows() const = 0;
109+
virtual int getRowLength(int row) const = 0;
110+
virtual int getSpaceCols() const = 0;
111+
virtual bool isWideRow(int row) const = 0;
112+
};
113+
103114
struct Keypad {
104115
Keypad(int charWidth, int charHeight, bool toolbar);
105116
~Keypad() = default;
@@ -108,6 +119,7 @@ struct Keypad {
108119
void draw() const;
109120
void layout(int x, int y, int w, int h);
110121
int layoutHeight(int screenHeight);
122+
void selectLayout();
111123

112124
private:
113125
void generateKeys();
@@ -122,6 +134,7 @@ struct Keypad {
122134
strlib::List<Key *> _keys;
123135
KeypadTheme *_theme;
124136
KeypadDrawContext _context;
137+
std::unique_ptr<KeypadLayout> _layout;
125138
};
126139

127140
struct KeypadInput : public FormInput {

0 commit comments

Comments
 (0)