From 1c1d5428394bb3cb683892d70a91e05b726e4259 Mon Sep 17 00:00:00 2001 From: "kkoenig1@optonline.com" Date: Wed, 25 Aug 2021 12:28:22 -0400 Subject: [PATCH] Updated software keyboard to center, and provice press indicators --- .../libopenui/src/keyboard_text.cpp | 173 +++++++++++++++--- .../thirdparty/libopenui/src/keyboard_text.h | 19 ++ .../src/thirdparty/libopenui/src/textedit.cpp | 3 + 3 files changed, 166 insertions(+), 29 deletions(-) diff --git a/radio/src/thirdparty/libopenui/src/keyboard_text.cpp b/radio/src/thirdparty/libopenui/src/keyboard_text.cpp index cbf3860a5..92553d743 100644 --- a/radio/src/thirdparty/libopenui/src/keyboard_text.cpp +++ b/radio/src/thirdparty/libopenui/src/keyboard_text.cpp @@ -79,7 +79,8 @@ const char * const KEYBOARD_NUMBERS[] = { KEYBOARD_SET_LETTERS KEYBOARD_SPACE KEYBOARD_ENTER }; -const char * const * const KEYBOARD_LAYOUTS[] = { +#define NUMBER_OF_KEYBOARD_LAYOUTS 4 +const char * const * const KEYBOARD_LAYOUTS[NUMBER_OF_KEYBOARD_LAYOUTS] = { KEYBOARD_UPPERCASE, KEYBOARD_LOWERCASE, KEYBOARD_LOWERCASE, @@ -97,70 +98,169 @@ TextKeyboard::~TextKeyboard() _instance = nullptr; } +int TextKeyboard::getCharWidth(const char c) +{ + if (int8_t(c) < 0) return KEYBOARD_BITMAP_WIDTH; + + switch (c) + { + case ' ': return 15; + case KEYBOARD_SPACE[0]: return KEYBOARD_SPACE_WIDTH; + case KEYBOARD_ENTER[0]: return KEYBOARD_ENTER_WIDTH; + default: return KEYBOARD_CHAR_WIDTH; + } +} + + +int TextKeyboard::calculateMaxWidth() +{ + int maxWidth = 0; + for (uint8_t i = 0; i < NUMBER_OF_KEYBOARD_LAYOUTS; i++) { + int lineWidth = 0; + const char * c = layout[i]; + while (*c) { + lineWidth += getCharWidth(*c); + maxWidth = max(lineWidth, maxWidth); + c++; + } + } + + return maxWidth; +} + void TextKeyboard::paint(BitmapBuffer * dc) { lcdSetColor(RGB(0xE0, 0xE0, 0xE0)); dc->clear(CUSTOM_COLOR); - for (uint8_t i=0; i<4; i++) { - coord_t y = 15 + i * 40; - coord_t x = 15; + // center the keyboard + coord_t start_x = (dc->width() - calculateMaxWidth()) / 2; + + for (uint8_t i = 0; i < NUMBER_OF_KEYBOARD_LAYOUTS; i++) { + coord_t y = KEYBOARD_OFFSET_Y + i * KEYBOARD_ROW_HEIGHT; + coord_t x = start_x; const char * c = layout[i]; + while (*c) { - if (*c == ' ') { - x += 15; - } - else if (*c == KEYBOARD_SPACE[0]) { + if (*c == KEYBOARD_SPACE[0]) { // spacebar dc->drawBitmapPattern(x, y, LBM_KEY_SPACEBAR, COLOR_THEME_SECONDARY1); - x += 135; } else if (*c == KEYBOARD_ENTER[0]) { // enter - dc->drawSolidFilledRect(x, y-2, 80, 25, COLOR_THEME_DISABLED); - dc->drawText(x+40, y, "ENTER", CENTERED); - x += 80; + dc->drawSolidFilledRect(x, y - 2, KEYBOARD_ENTER_WIDTH, 25, COLOR_THEME_DISABLED); + dc->drawText(x + KEYBOARD_ENTER_WIDTH / 2, y + 2, "ENTER", CENTERED); } else if (int8_t(*c) < 0) { - dc->drawBitmapPattern(x, y, LBM_SPECIAL_KEYS[uint8_t(*c - 128)], COLOR_THEME_SECONDARY1); - x += 45; + const uint8_t *pBitmap = LBM_SPECIAL_KEYS[uint8_t(*c - 128)]; + uint8_t bitmapWidth = *pBitmap, bitmapHeight = *(pBitmap + 2); + if (touched && *c == touch_key) { + dc->drawSolidFilledRect(x - 2, y + 3, bitmapWidth + 4, bitmapHeight + 4, COLOR_THEME_SECONDARY2); + } + + dc->drawBitmapPattern(x, y + 5, pBitmap, COLOR_THEME_SECONDARY1); } else { - dc->drawSizedText(x, y, c, 1); - x += 30; + if (touched && *c == touch_key) { + dc->drawSolidFilledRect(x - KEYBOARD_CHAR_WIDTH / 2, y - ((KEYBOARD_ROW_HEIGHT - 16) / 2), KEYBOARD_CHAR_WIDTH, KEYBOARD_ROW_HEIGHT, COLOR_THEME_FOCUS); + } + dc->drawSizedText(x, y, c, 1, CENTERED); } + x += getCharWidth(*c); c++; } } } +bool TextKeyboard::onTouchStart(coord_t x, coord_t y) +{ + // remove the centering. If x < 0 then this is an invalid touch event + x -= (this->width() - calculateMaxWidth()) / 2; + if (x < 0) { + if (touched) { + touched = false; + invalidate(); + } + return true; + } + + touched = false; + + uint8_t row = max(0, y - 5) / KEYBOARD_ROW_HEIGHT; + const char * key = layout[row]; + + while(*key) { + if (*key == KEYBOARD_SPACE[0] && x <= KEYBOARD_SPACE_WIDTH) { + touch_key = KEYBOARD_SPACE[0]; + touched = true; + break; + } + else if (*key == KEYBOARD_ENTER[0] && x <= KEYBOARD_ENTER_WIDTH) { + touch_key = KEYBOARD_ENTER[0]; + touched = true; + break; + } + else if (int8_t(*key) < 0 && x <= KEYBOARD_BITMAP_WIDTH) { + if (uint8_t(*key) == 128) { + touch_key = KEYBOARD_BACKSPACE[0]; + touched = true; + break; + } else { + touched = false; + break; + } + } + else if (*key != ' ' && (x >= -(KEYBOARD_CHAR_WIDTH / 2) && x <= KEYBOARD_CHAR_WIDTH / 2)) { + touch_key = *key; + touched = true; + break; + } + + x -= getCharWidth(*key); + key++; + + if (touched) { + invalidate(); + break; + } + } + return true; +} + bool TextKeyboard::onTouchEnd(coord_t x, coord_t y) { + // remove the centering width, if x < 0 then this is an invalid touch on a centered keyboard. + x -= (this->width() - calculateMaxWidth()) / 2; + if (x < 0) { + touched = false; + return true; + } + onKeyPress(); - uint8_t row = max(0, y - 5) / 40; + if (touched) + invalidate(); + touched = false; + + uint8_t row = max(0, y - 5) / KEYBOARD_ROW_HEIGHT; + const char * key = layout[row]; while (*key) { - if (*key == ' ') { - x -= 15; - } - else if (*key == KEYBOARD_SPACE[0]) { - if (x <= 135) { + if (*key == KEYBOARD_SPACE[0]) { + if (x <= KEYBOARD_SPACE_WIDTH) { pushEvent(EVT_VIRTUAL_KEY(' ')); return true; } - x -= 135; } else if (*key == KEYBOARD_ENTER[0]) { - if (x <= 80) { + if (x <= KEYBOARD_ENTER_WIDTH) { // enter hide(); return true; } - x -= 80; } else if (int8_t(*key) < 0) { - if (x <= 45) { + if (x <= KEYBOARD_BITMAP_WIDTH) { uint8_t specialKey = *key; if (specialKey == 128) { // backspace @@ -172,17 +272,32 @@ bool TextKeyboard::onTouchEnd(coord_t x, coord_t y) } break; } - x -= 45; } else { - if (x <= 30) { + if (x <= KEYBOARD_CHAR_WIDTH && *key != ' ') { pushEvent(EVT_VIRTUAL_KEY(*key)); return true; } - x -= 30; } + x -= getCharWidth(*key); key++; } return true; } + +bool TextKeyboard::onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) +{ + if (touched) + invalidate(); + + touched = false; + return false; +} + +#if defined(HARDWARE_KEYS) +void TextKeyboard::onEvent(event_t event) +{ + +} +#endif diff --git a/radio/src/thirdparty/libopenui/src/keyboard_text.h b/radio/src/thirdparty/libopenui/src/keyboard_text.h index afc8cfef2..732e6e2c3 100644 --- a/radio/src/thirdparty/libopenui/src/keyboard_text.h +++ b/radio/src/thirdparty/libopenui/src/keyboard_text.h @@ -29,6 +29,13 @@ #define KEYBOARD_SET_LETTERS "\203" #define KEYBOARD_SET_NUMBERS "\204" +#define KEYBOARD_OFFSET_Y 15 +#define KEYBOARD_ROW_HEIGHT 40 +#define KEYBOARD_CHAR_WIDTH 30 +#define KEYBOARD_SPACE_WIDTH 135 +#define KEYBOARD_ENTER_WIDTH 80 +#define KEYBOARD_BITMAP_WIDTH 45 + class TextKeyboard : public Keyboard { public: TextKeyboard(); @@ -53,10 +60,22 @@ class TextKeyboard : public Keyboard { #if defined(HARDWARE_TOUCH) bool onTouchEnd(coord_t x, coord_t y) override; + bool onTouchStart(coord_t x, coord_t y) override; + bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override; #endif protected: +#if defined(HARDWARE_KEYS) + void onEvent(event_t event) override; +#endif + static TextKeyboard * _instance; const char * const * layout; + private: + int calculateMaxWidth(); + int getCharWidth(const char c); + + char touch_key = -128; + bool touched = false; }; diff --git a/radio/src/thirdparty/libopenui/src/textedit.cpp b/radio/src/thirdparty/libopenui/src/textedit.cpp index 45d4997dd..0e023d354 100644 --- a/radio/src/thirdparty/libopenui/src/textedit.cpp +++ b/radio/src/thirdparty/libopenui/src/textedit.cpp @@ -170,6 +170,9 @@ void TextEdit::onEvent(event_t event) case EVT_KEY_BREAK(KEY_EXIT): changeEnd(); +#if defined(SOFTWARE_KEYBOARD) + Keyboard::hide(); +#endif FormField::onEvent(event); break;