Merge pull request #146 from jpirnay/feat-resync-keyboard
refactor: resync to upstream keyboard
This commit is contained in:
@@ -583,3 +583,18 @@ STR_BTN_ACT_PREV_SECTION: "Previous Section / Chapter"
|
|||||||
STR_BTN_ACT_EXIT_READER: "Exit Reader"
|
STR_BTN_ACT_EXIT_READER: "Exit Reader"
|
||||||
STR_BTN_ACT_READER_MENU: "Reader Menu"
|
STR_BTN_ACT_READER_MENU: "Reader Menu"
|
||||||
STR_BTN_ACT_KOREADER_SYNC: "KOReader Sync"
|
STR_BTN_ACT_KOREADER_SYNC: "KOReader Sync"
|
||||||
|
STR_KB_HINT_MOVE_CURSOR: "Press LEFT or RIGHT to move cursor"
|
||||||
|
STR_KB_HINT_RETURN_CURSOR: "Press LEFT to return to cursor position"
|
||||||
|
STR_KB_HINT_HIDE_PASSWORD: "Hold RIGHT then press [***] to hide password"
|
||||||
|
STR_KB_HINT_SHOW_PASSWORD: "Hold RIGHT then press [abc] to show password"
|
||||||
|
STR_KB_HINT_TOGGLE_HIDE_PASSWORD: "Press [***] to hide password"
|
||||||
|
STR_KB_HINT_TOGGLE_SHOW_PASSWORD: "Press [abc] to show password"
|
||||||
|
STR_KB_HINT_EDIT_ENTRY: "Hold UP to edit entry"
|
||||||
|
STR_KB_TIPS: "Tips:"
|
||||||
|
STR_KB_HINT_RETURN_KEYBOARD: "Press DOWN to return to keyboard"
|
||||||
|
STR_KB_HINT_EXIT_URL_MODE: "Press ABC to exit URL mode"
|
||||||
|
STR_KB_HINT_CLEAR_TEXT: "Hold DEL to clear all text"
|
||||||
|
STR_KB_HINT_SECONDARY_CHAR: "Hold SELECT for secondary char"
|
||||||
|
STR_KB_HINT_UPPER_SECONDARY: "Hold SELECT for UPPERCASE or secondary char"
|
||||||
|
STR_KB_HINT_LOWER_SECONDARY: "Hold SELECT for lowercase or secondary char"
|
||||||
|
STR_KB_HINT_URL_SNIPPETS: "Press URL for snippets"
|
||||||
|
|||||||
@@ -1,31 +1,32 @@
|
|||||||
#include "KeyboardEntryActivity.h"
|
#include "KeyboardEntryActivity.h"
|
||||||
|
|
||||||
|
#include <HalGPIO.h>
|
||||||
#include <I18n.h>
|
#include <I18n.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "MappedInputManager.h"
|
#include "MappedInputManager.h"
|
||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
|
||||||
const char* KeyboardEntryActivity::shiftLabel(int shiftState) {
|
|
||||||
return shiftState ? tr(STR_SHIFT_CAPS) : tr(STR_SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardEntryActivity::onEnter() {
|
void KeyboardEntryActivity::onEnter() {
|
||||||
Activity::onEnter();
|
Activity::onEnter();
|
||||||
cursorPos = text.length();
|
cursorPos = text.length();
|
||||||
symMode = false;
|
symMode = false;
|
||||||
urlMode = false;
|
urlMode = false;
|
||||||
cursorMode = false;
|
cursorMode = false;
|
||||||
|
togglePos = false;
|
||||||
passwordVisible = false;
|
passwordVisible = false;
|
||||||
shiftState = 0;
|
shiftState = 0;
|
||||||
selectedRow = 0;
|
selectedRow = 0;
|
||||||
selectedCol = 0;
|
selectedCol = 0;
|
||||||
confirmHeld = false;
|
delPressCount = 0;
|
||||||
confirmLongHandled = false;
|
hintVisible = false;
|
||||||
upHeld = false;
|
hintShowTime = 0;
|
||||||
upLongHandled = false;
|
rightHeld = false;
|
||||||
downHeld = false;
|
rightLongHandled = false;
|
||||||
downLongHandled = false;
|
savedCursorPos = 0;
|
||||||
|
rightStartCursorPos = 0;
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ int KeyboardEntryActivity::getTotalRowCount() const { return getContentRowCount(
|
|||||||
bool KeyboardEntryActivity::isBottomRow(const int row) const { return row == getContentRowCount(); }
|
bool KeyboardEntryActivity::isBottomRow(const int row) const { return row == getContentRowCount(); }
|
||||||
|
|
||||||
char KeyboardEntryActivity::getSelectedChar() const {
|
char KeyboardEntryActivity::getSelectedChar() const {
|
||||||
const KeyDef(*layout)[COLS] = symMode ? symLayout : abcLayout;
|
const KeyDef(*layout)[COLS] = symMode ? symLayout : (inputType == InputType::Url ? urlLayout : abcLayout);
|
||||||
|
|
||||||
if (selectedRow < 0 || selectedRow >= getContentRowCount()) return '\0';
|
if (selectedRow < 0 || selectedRow >= getContentRowCount()) return '\0';
|
||||||
if (selectedCol < 0 || selectedCol >= COLS) return '\0';
|
if (selectedCol < 0 || selectedCol >= COLS) return '\0';
|
||||||
@@ -56,7 +57,8 @@ char KeyboardEntryActivity::getSelectedChar() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char KeyboardEntryActivity::getAlternativeChar() const {
|
char KeyboardEntryActivity::getAlternativeChar() const {
|
||||||
if (symMode) return '\0';
|
if (symMode || urlMode) return '\0';
|
||||||
|
if (inputType == InputType::Url && selectedRow > 0) return '\0';
|
||||||
|
|
||||||
const KeyDef(*layout)[COLS] = abcLayout;
|
const KeyDef(*layout)[COLS] = abcLayout;
|
||||||
|
|
||||||
@@ -92,15 +94,21 @@ void KeyboardEntryActivity::insertString(const std::string& str) {
|
|||||||
bool KeyboardEntryActivity::handleKeyPress() {
|
bool KeyboardEntryActivity::handleKeyPress() {
|
||||||
if (isBottomRow(selectedRow)) {
|
if (isBottomRow(selectedRow)) {
|
||||||
switch (static_cast<SpecialKeyType>(selectedCol)) {
|
switch (static_cast<SpecialKeyType>(selectedCol)) {
|
||||||
case SpecShift:
|
case SpecialKeyType::Shift:
|
||||||
if (urlMode) return true;
|
delPressCount = 0;
|
||||||
|
hintVisible = false;
|
||||||
|
if (urlMode || inputType == InputType::Url) return true;
|
||||||
if (symMode) return true;
|
if (symMode) return true;
|
||||||
shiftState = (shiftState + 1) % 2;
|
shiftState = (shiftState + 1) % 2;
|
||||||
return true;
|
return true;
|
||||||
case SpecMode: {
|
case SpecialKeyType::Mode: {
|
||||||
|
delPressCount = 0;
|
||||||
|
hintVisible = false;
|
||||||
if (urlMode) {
|
if (urlMode) {
|
||||||
urlMode = false;
|
urlMode = false;
|
||||||
symMode = false;
|
symMode = false;
|
||||||
|
selectedRow = getTotalRowCount() - 1;
|
||||||
|
selectedCol = static_cast<int>(SpecialKeyType::Mode);
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -114,26 +122,35 @@ bool KeyboardEntryActivity::handleKeyPress() {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case SpecSpace:
|
case SpecialKeyType::Space:
|
||||||
|
delPressCount = 0;
|
||||||
|
hintVisible = false;
|
||||||
if (inputType == InputType::Url) {
|
if (inputType == InputType::Url) {
|
||||||
urlMode = !urlMode;
|
urlMode = !urlMode;
|
||||||
if (urlMode) {
|
if (urlMode) {
|
||||||
symMode = false;
|
symMode = false;
|
||||||
}
|
}
|
||||||
selectedRow = getTotalRowCount() - 1;
|
selectedRow = getTotalRowCount() - 1;
|
||||||
selectedCol = SpecSpace;
|
selectedCol = static_cast<int>(SpecialKeyType::Space);
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
} else {
|
} else {
|
||||||
return insertChar(' ');
|
return insertChar(' ');
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case SpecDel:
|
case SpecialKeyType::Del:
|
||||||
|
delPressCount++;
|
||||||
|
if (delPressCount >= 2) {
|
||||||
|
hintVisible = true;
|
||||||
|
hintShowTime = millis();
|
||||||
|
}
|
||||||
if (cursorPos > 0 && !text.empty()) {
|
if (cursorPos > 0 && !text.empty()) {
|
||||||
text.erase(cursorPos - 1, 1);
|
text.erase(cursorPos - 1, 1);
|
||||||
cursorPos--;
|
cursorPos--;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case SpecOk:
|
case SpecialKeyType::Ok:
|
||||||
|
delPressCount = 0;
|
||||||
|
hintVisible = false;
|
||||||
onComplete(text);
|
onComplete(text);
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
@@ -142,6 +159,8 @@ bool KeyboardEntryActivity::handleKeyPress() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (urlMode) {
|
if (urlMode) {
|
||||||
|
delPressCount = 0;
|
||||||
|
hintVisible = false;
|
||||||
const int idx = selectedCol + selectedRow * 3;
|
const int idx = selectedCol + selectedRow * 3;
|
||||||
if (idx < URL_SNIPPET_COUNT) {
|
if (idx < URL_SNIPPET_COUNT) {
|
||||||
insertString(urlSnippets[idx]);
|
insertString(urlSnippets[idx]);
|
||||||
@@ -149,6 +168,9 @@ bool KeyboardEntryActivity::handleKeyPress() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delPressCount = 0;
|
||||||
|
hintVisible = false;
|
||||||
|
|
||||||
return insertChar(getSelectedChar());
|
return insertChar(getSelectedChar());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,6 +196,8 @@ void KeyboardEntryActivity::loop() {
|
|||||||
mappedInput.getHeldTime() > LONG_PRESS_MS) {
|
mappedInput.getHeldTime() > LONG_PRESS_MS) {
|
||||||
cursorMode = true;
|
cursorMode = true;
|
||||||
upLongHandled = true;
|
upLongHandled = true;
|
||||||
|
hintVisible = true;
|
||||||
|
hintShowTime = millis();
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,11 +222,10 @@ void KeyboardEntryActivity::loop() {
|
|||||||
if (mappedInput.wasPressed(MappedInputManager::Button::Down)) {
|
if (mappedInput.wasPressed(MappedInputManager::Button::Down)) {
|
||||||
downHeld = true;
|
downHeld = true;
|
||||||
if (cursorMode) {
|
if (cursorMode) {
|
||||||
if (cursorPos > text.length()) {
|
togglePos = false;
|
||||||
cursorPos = text.length();
|
|
||||||
}
|
|
||||||
passwordVisible = false;
|
passwordVisible = false;
|
||||||
cursorMode = false;
|
cursorMode = false;
|
||||||
|
hintVisible = false;
|
||||||
downLongHandled = true;
|
downLongHandled = true;
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
} else {
|
} else {
|
||||||
@@ -229,41 +252,72 @@ void KeyboardEntryActivity::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Left}, [this] {
|
buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Left}, [this] {
|
||||||
if (cursorMode) {
|
if (cursorMode) return;
|
||||||
if (cursorPos > 0) {
|
|
||||||
cursorPos--;
|
|
||||||
requestUpdate();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int maxCol = isBottomRow(selectedRow) ? BOTTOM_KEY_COUNT - 1 : getContentColCount() - 1;
|
int maxCol = isBottomRow(selectedRow) ? BOTTOM_KEY_COUNT - 1 : getContentColCount() - 1;
|
||||||
selectedCol = ButtonNavigator::previousIndex(selectedCol, maxCol + 1);
|
selectedCol = ButtonNavigator::previousIndex(selectedCol, maxCol + 1);
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Right}, [this] {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Left)) {
|
||||||
if (cursorMode) {
|
if (cursorMode) {
|
||||||
if (cursorPos < text.length()) {
|
if (togglePos) {
|
||||||
cursorPos++;
|
cursorPos = savedCursorPos;
|
||||||
|
togglePos = false;
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
} else if (cursorPos == text.length() && inputType == InputType::Password) {
|
} else if (cursorPos > 0) {
|
||||||
cursorPos = text.length() + 1;
|
cursorPos--;
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mappedInput.wasPressed(MappedInputManager::Button::Right)) {
|
||||||
|
if (cursorMode && inputType == InputType::Password && !togglePos) {
|
||||||
|
rightHeld = true;
|
||||||
|
rightLongHandled = false;
|
||||||
|
rightStartCursorPos = cursorPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Right}, [this] {
|
||||||
|
if (cursorMode) return;
|
||||||
int maxCol = isBottomRow(selectedRow) ? BOTTOM_KEY_COUNT - 1 : getContentColCount() - 1;
|
int maxCol = isBottomRow(selectedRow) ? BOTTOM_KEY_COUNT - 1 : getContentColCount() - 1;
|
||||||
selectedCol = ButtonNavigator::nextIndex(selectedCol, maxCol + 1);
|
selectedCol = ButtonNavigator::nextIndex(selectedCol, maxCol + 1);
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (rightHeld && !rightLongHandled && mappedInput.isPressed(MappedInputManager::Button::Right) &&
|
||||||
|
mappedInput.getHeldTime() > LONG_PRESS_MS) {
|
||||||
|
if (cursorMode && inputType == InputType::Password && !togglePos) {
|
||||||
|
savedCursorPos = rightStartCursorPos;
|
||||||
|
togglePos = true;
|
||||||
|
rightLongHandled = true;
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mappedInput.wasReleased(MappedInputManager::Button::Right)) {
|
||||||
|
if (cursorMode && inputType == InputType::Password) {
|
||||||
|
rightHeld = false;
|
||||||
|
rightLongHandled = false;
|
||||||
|
}
|
||||||
|
if (cursorMode && !togglePos && cursorPos < text.length()) {
|
||||||
|
cursorPos++;
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
|
if (cursorMode) return;
|
||||||
|
rightHeld = false;
|
||||||
|
rightLongHandled = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
|
||||||
confirmHeld = true;
|
confirmHeld = true;
|
||||||
confirmLongHandled = false;
|
confirmLongHandled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (confirmHeld && !confirmLongHandled && mappedInput.isPressed(MappedInputManager::Button::Confirm) &&
|
if (confirmHeld && !confirmLongHandled && mappedInput.isPressed(MappedInputManager::Button::Confirm) &&
|
||||||
mappedInput.getHeldTime() > DEL_LONG_PRESS_MS && isBottomRow(selectedRow) && selectedCol == SpecDel) {
|
mappedInput.getHeldTime() > DEL_LONG_PRESS_MS && isBottomRow(selectedRow) &&
|
||||||
|
selectedCol == static_cast<int>(SpecialKeyType::Del)) {
|
||||||
text.clear();
|
text.clear();
|
||||||
cursorPos = 0;
|
cursorPos = 0;
|
||||||
confirmLongHandled = true;
|
confirmLongHandled = true;
|
||||||
@@ -271,7 +325,7 @@ void KeyboardEntryActivity::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (confirmHeld && !confirmLongHandled && mappedInput.isPressed(MappedInputManager::Button::Confirm) &&
|
if (confirmHeld && !confirmLongHandled && mappedInput.isPressed(MappedInputManager::Button::Confirm) &&
|
||||||
mappedInput.getHeldTime() > LONG_PRESS_MS && !cursorMode && inputType == InputType::Text && !urlMode) {
|
mappedInput.getHeldTime() > LONG_PRESS_MS) {
|
||||||
char alt = getAlternativeChar();
|
char alt = getAlternativeChar();
|
||||||
if (alt != '\0') {
|
if (alt != '\0') {
|
||||||
insertChar(alt);
|
insertChar(alt);
|
||||||
@@ -285,8 +339,7 @@ void KeyboardEntryActivity::loop() {
|
|||||||
if (handleKeyPress()) {
|
if (handleKeyPress()) {
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
}
|
}
|
||||||
} else if (confirmHeld && !confirmLongHandled && cursorMode && inputType == InputType::Password &&
|
} else if (confirmHeld && !confirmLongHandled && cursorMode && inputType == InputType::Password && togglePos) {
|
||||||
cursorPos > text.length()) {
|
|
||||||
passwordVisible = !passwordVisible;
|
passwordVisible = !passwordVisible;
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
}
|
}
|
||||||
@@ -297,24 +350,28 @@ void KeyboardEntryActivity::loop() {
|
|||||||
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
|
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
|
||||||
onCancel();
|
onCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hintVisible && !cursorMode && millis() - hintShowTime > 4000) {
|
||||||
|
hintVisible = false;
|
||||||
|
requestUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardEntryActivity::render(RenderLock&&) {
|
void KeyboardEntryActivity::render(RenderLock&&) {
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
|
|
||||||
const Rect contentRect = UITheme::getContentRect(renderer, true, true);
|
const Rect contentRect = UITheme::getContentRect(renderer, true, gpio.deviceIsX3());
|
||||||
const int pageWidth = contentRect.width;
|
const int pageWidth = contentRect.width;
|
||||||
|
const int pageHeight = contentRect.height;
|
||||||
const int contentX = contentRect.x;
|
const int contentX = contentRect.x;
|
||||||
const int contentY = contentRect.y;
|
|
||||||
const auto& metrics = UITheme::getInstance().getMetrics();
|
const auto& metrics = UITheme::getInstance().getMetrics();
|
||||||
|
|
||||||
GUI.drawHeader(renderer, Rect{contentX, contentY + metrics.topPadding, pageWidth, metrics.headerHeight},
|
GUI.drawHeader(renderer, Rect{contentX, metrics.topPadding, pageWidth, metrics.headerHeight}, title.c_str());
|
||||||
title.c_str());
|
|
||||||
|
|
||||||
const int lineHeight = renderer.getLineHeight(UI_12_FONT_ID);
|
const int lineHeight = renderer.getLineHeight(UI_12_FONT_ID);
|
||||||
const int inputStartY = contentY + metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing +
|
const int inputStartY = contentRect.y + metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing +
|
||||||
metrics.verticalSpacing * 4 + metrics.keyboardVerticalOffset;
|
metrics.verticalSpacing * 4 + metrics.keyboardVerticalOffset;
|
||||||
int inputHeight = lineHeight;
|
int inputHeight = 0;
|
||||||
|
|
||||||
std::string displayText;
|
std::string displayText;
|
||||||
if (inputType == InputType::Password && !passwordVisible) {
|
if (inputType == InputType::Password && !passwordVisible) {
|
||||||
@@ -322,7 +379,7 @@ void KeyboardEntryActivity::render(RenderLock&&) {
|
|||||||
if (cursorMode) {
|
if (cursorMode) {
|
||||||
revealPos = text.length(); // no reveal in displayText; block draws actual char directly
|
revealPos = text.length(); // no reveal in displayText; block draws actual char directly
|
||||||
} else {
|
} else {
|
||||||
revealPos = (text.length() > 0 && cursorPos > 0) ? cursorPos - 1 : 0;
|
revealPos = (text.length() > 0 && cursorPos > 0) ? cursorPos - 1 : std::string::npos;
|
||||||
}
|
}
|
||||||
displayText = text;
|
displayText = text;
|
||||||
for (size_t i = 0; i < displayText.length(); i++) {
|
for (size_t i = 0; i < displayText.length(); i++) {
|
||||||
@@ -335,82 +392,33 @@ void KeyboardEntryActivity::render(RenderLock&&) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bool isPassword = (inputType == InputType::Password);
|
const bool isPassword = (inputType == InputType::Password);
|
||||||
const int margin = metrics.contentSidePadding;
|
const int usableWidth = pageWidth;
|
||||||
const int extraMargin = 10;
|
const int effectiveMargin = (pageWidth - usableWidth * metrics.keyboardTextFieldWidthPercent / 100) / 2;
|
||||||
const int effectiveMargin = margin + extraMargin;
|
const int toggleGap = isPassword ? 4 : 0;
|
||||||
const int toggleGap = isPassword ? 8 : 0;
|
|
||||||
const int toggleReserve = isPassword ? std::max(renderer.getTextWidth(UI_12_FONT_ID, "[abc]"),
|
const int toggleReserve = isPassword ? std::max(renderer.getTextWidth(UI_12_FONT_ID, "[abc]"),
|
||||||
renderer.getTextWidth(UI_12_FONT_ID, "[***]")) +
|
renderer.getTextWidth(UI_12_FONT_ID, "[***]")) +
|
||||||
toggleGap
|
toggleGap
|
||||||
: 0;
|
: 0;
|
||||||
const int textAreaWidth = pageWidth - 2 * effectiveMargin - toggleReserve;
|
const int textAreaWidth = usableWidth - 2 * effectiveMargin - toggleReserve;
|
||||||
const int maxLineWidth = textAreaWidth;
|
const int maxLineWidth = textAreaWidth;
|
||||||
const bool centerText = metrics.keyboardCenteredText;
|
const bool centerText = metrics.keyboardCenteredText;
|
||||||
|
|
||||||
const int keyHeight = metrics.keyboardKeyHeight;
|
int cursorCharWidth = 6;
|
||||||
const int bottomKeyHeight = metrics.keyboardBottomKeyHeight;
|
|
||||||
const int keySpacing = metrics.keyboardKeySpacing;
|
|
||||||
const int contentCols = getContentColCount();
|
|
||||||
const int keyWidth = (pageWidth * 95 / 100 - (contentCols - 1) * keySpacing) / contentCols;
|
|
||||||
const int leftMargin = contentX + (pageWidth - (contentCols * keyWidth + (contentCols - 1) * keySpacing)) / 2;
|
|
||||||
|
|
||||||
const int bottomRowGap = metrics.keyboardBottomKeySpacing > 0 ? 4 : 0;
|
|
||||||
const int keyboardStartY = metrics.keyboardBottomAligned
|
|
||||||
? contentY + contentRect.height - metrics.verticalSpacing -
|
|
||||||
(keyHeight + keySpacing) * getContentRowCount() - bottomKeyHeight -
|
|
||||||
bottomRowGap + metrics.keyboardVerticalOffset
|
|
||||||
: inputStartY + inputHeight + lineHeight + metrics.verticalSpacing;
|
|
||||||
|
|
||||||
const char* helpTexts[3];
|
|
||||||
if (inputType == InputType::Url) {
|
|
||||||
helpTexts[0] = tr(STR_KEYBOARD_HELP_URL_LINE_1);
|
|
||||||
helpTexts[1] = tr(STR_KEYBOARD_HELP_URL_LINE_2);
|
|
||||||
helpTexts[2] = tr(STR_KEYBOARD_HELP_URL_LINE_3);
|
|
||||||
} else if (cursorMode) {
|
|
||||||
helpTexts[0] = tr(STR_KEYBOARD_HELP_CURSOR_LINE_1);
|
|
||||||
helpTexts[1] = tr(STR_KEYBOARD_HELP_CURSOR_LINE_2);
|
|
||||||
helpTexts[2] = tr(STR_KEYBOARD_HELP_CURSOR_LINE_3);
|
|
||||||
} else if (inputType == InputType::Password) {
|
|
||||||
helpTexts[0] = tr(STR_KEYBOARD_HELP_PASSWORD_LINE_1);
|
|
||||||
helpTexts[1] = tr(STR_KEYBOARD_HELP_PASSWORD_LINE_2);
|
|
||||||
helpTexts[2] = tr(STR_KEYBOARD_HELP_PASSWORD_LINE_3);
|
|
||||||
} else {
|
|
||||||
helpTexts[0] = tr(STR_KEYBOARD_HELP_DEFAULT_LINE_1);
|
|
||||||
helpTexts[1] = tr(STR_KEYBOARD_HELP_DEFAULT_LINE_2);
|
|
||||||
helpTexts[2] = tr(STR_KEYBOARD_HELP_DEFAULT_LINE_3);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int helpGap = keyboardStartY - (inputStartY + inputHeight);
|
|
||||||
const int helpLineHeight = renderer.getLineHeight(SMALL_FONT_ID);
|
|
||||||
const int maxHelpLines = std::max(0, helpGap / helpLineHeight);
|
|
||||||
const int helpLineCount = std::min(3, maxHelpLines);
|
|
||||||
const int helpBodyHeight = helpLineCount * helpLineHeight;
|
|
||||||
const int helpTop = inputStartY + inputHeight + std::max(0, (helpGap - helpBodyHeight) / 2);
|
|
||||||
const int helpLineWidth = pageWidth - 2 * metrics.contentSidePadding;
|
|
||||||
for (int i = 0; i < helpLineCount; ++i) {
|
|
||||||
const char* helpText = helpTexts[i];
|
|
||||||
const std::string line = renderer.truncatedText(SMALL_FONT_ID, helpText, helpLineWidth, EpdFontFamily::ITALIC);
|
|
||||||
renderer.drawText(SMALL_FONT_ID, contentX + metrics.contentSidePadding, helpTop + i * helpLineHeight, line.c_str(),
|
|
||||||
true, EpdFontFamily::ITALIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cursorCharWidth;
|
|
||||||
if (cursorPos < text.length()) {
|
if (cursorPos < text.length()) {
|
||||||
cursorCharWidth = renderer.getTextWidth(UI_12_FONT_ID, text.substr(cursorPos, 1).c_str());
|
int w = renderer.getTextWidth(UI_12_FONT_ID, text.substr(cursorPos, 1).c_str());
|
||||||
} else {
|
if (w > cursorCharWidth) cursorCharWidth = w;
|
||||||
cursorCharWidth = 6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lineStartIdx = 0;
|
int lineStartIdx = 0;
|
||||||
int lineEndIdx = displayText.length();
|
int lineEndIdx = displayText.length();
|
||||||
int textWidth = 0;
|
int textWidth = 0;
|
||||||
int cursorPixelX = contentX + metrics.contentSidePadding;
|
int cursorPixelX = contentX + effectiveMargin;
|
||||||
int cursorLineY = inputStartY;
|
int cursorLineY = inputStartY;
|
||||||
bool cursorDrawn = false;
|
bool cursorDrawn = false;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std::string lineText = displayText.substr(lineStartIdx, lineEndIdx - lineStartIdx);
|
std::string lineText = displayText.substr(lineStartIdx, lineEndIdx - lineStartIdx);
|
||||||
textWidth = renderer.getTextWidth(UI_12_FONT_ID, lineText.c_str());
|
textWidth = renderer.getTextAdvanceX(UI_12_FONT_ID, lineText.c_str(), EpdFontFamily::REGULAR);
|
||||||
if (textWidth <= maxLineWidth) {
|
if (textWidth <= maxLineWidth) {
|
||||||
const bool isLastLine = (lineEndIdx == static_cast<int>(displayText.length()));
|
const bool isLastLine = (lineEndIdx == static_cast<int>(displayText.length()));
|
||||||
bool isCursorLine = false;
|
bool isCursorLine = false;
|
||||||
@@ -422,14 +430,20 @@ void KeyboardEntryActivity::render(RenderLock&&) {
|
|||||||
} else {
|
} else {
|
||||||
beforeCursor = displayText.substr(lineStartIdx, cursorPos - lineStartIdx);
|
beforeCursor = displayText.substr(lineStartIdx, cursorPos - lineStartIdx);
|
||||||
}
|
}
|
||||||
int beforeWidth = renderer.getTextWidth(UI_12_FONT_ID, beforeCursor.c_str());
|
int beforeWidth = renderer.getTextAdvanceX(UI_12_FONT_ID, beforeCursor.c_str(), EpdFontFamily::REGULAR);
|
||||||
if (centerText) {
|
int kernOffset = 0;
|
||||||
cursorPixelX = contentX + effectiveMargin + (maxLineWidth - textWidth) / 2 + beforeWidth;
|
if (cursorPos < displayText.length()) {
|
||||||
} else {
|
std::string beforeAndCursor = beforeCursor + displayText.substr(cursorPos, 1);
|
||||||
cursorPixelX = contentX + effectiveMargin + beforeWidth;
|
int beforeAndCursorWidth =
|
||||||
|
renderer.getTextAdvanceX(UI_12_FONT_ID, beforeAndCursor.c_str(), EpdFontFamily::REGULAR);
|
||||||
|
int charAdvance =
|
||||||
|
renderer.getTextAdvanceX(UI_12_FONT_ID, displayText.substr(cursorPos, 1).c_str(), EpdFontFamily::REGULAR);
|
||||||
|
kernOffset = beforeAndCursorWidth - beforeWidth - charAdvance;
|
||||||
}
|
}
|
||||||
if (cursorPos == static_cast<size_t>(lineEndIdx) && cursorPos == displayText.length()) {
|
if (centerText) {
|
||||||
cursorPixelX += 2;
|
cursorPixelX = contentX + effectiveMargin + (maxLineWidth - textWidth) / 2 + beforeWidth + kernOffset;
|
||||||
|
} else {
|
||||||
|
cursorPixelX = contentX + effectiveMargin + beforeWidth + kernOffset;
|
||||||
}
|
}
|
||||||
cursorLineY = inputStartY + inputHeight;
|
cursorLineY = inputStartY + inputHeight;
|
||||||
cursorDrawn = true;
|
cursorDrawn = true;
|
||||||
@@ -438,7 +452,7 @@ void KeyboardEntryActivity::render(RenderLock&&) {
|
|||||||
|
|
||||||
const int lineStartX =
|
const int lineStartX =
|
||||||
contentX + (centerText ? effectiveMargin + (maxLineWidth - textWidth) / 2 : effectiveMargin);
|
contentX + (centerText ? effectiveMargin + (maxLineWidth - textWidth) / 2 : effectiveMargin);
|
||||||
if (isCursorLine && cursorMode && isPassword && !passwordVisible) {
|
if (isCursorLine && cursorMode && isPassword && !passwordVisible && !togglePos) {
|
||||||
// Draw text in 3 parts to avoid block cursor overflowing onto next char.
|
// Draw text in 3 parts to avoid block cursor overflowing onto next char.
|
||||||
// displayText uses '*' for all chars; actual char may be wider than '*'.
|
// displayText uses '*' for all chars; actual char may be wider than '*'.
|
||||||
// Part 1: chars before cursor position
|
// Part 1: chars before cursor position
|
||||||
@@ -468,18 +482,18 @@ void KeyboardEntryActivity::render(RenderLock&&) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int fieldWidth = (inputHeight > 0) ? maxLineWidth : textWidth;
|
const int fieldWidth = (inputHeight > 0) ? maxLineWidth : textWidth;
|
||||||
const int lineMargin = margin + extraMargin - 5;
|
const int lineMargin = effectiveMargin;
|
||||||
GUI.drawTextField(renderer, Rect{contentX, inputStartY, pageWidth, inputHeight}, fieldWidth, cursorMode, lineMargin,
|
GUI.drawTextField(renderer, Rect{contentX, inputStartY, pageWidth, inputHeight}, fieldWidth, cursorMode, lineMargin,
|
||||||
pageWidth - 2 * lineMargin);
|
pageWidth - 2 * lineMargin);
|
||||||
|
|
||||||
if (cursorMode && cursorPos <= displayText.length()) {
|
if (cursorMode && !togglePos && cursorPos <= displayText.length()) {
|
||||||
static constexpr int blockPadding = 1;
|
static constexpr int blockPadding = 1;
|
||||||
renderer.fillRect(cursorPixelX - blockPadding, cursorLineY, cursorCharWidth + blockPadding * 2, lineHeight, true);
|
renderer.fillRect(cursorPixelX - blockPadding, cursorLineY, cursorCharWidth + blockPadding * 2, lineHeight, true);
|
||||||
if (cursorPos < text.length()) {
|
if (cursorPos < text.length()) {
|
||||||
const char buf[2] = {text[cursorPos], '\0'};
|
const char buf[2] = {text[cursorPos], '\0'};
|
||||||
renderer.drawText(UI_12_FONT_ID, cursorPixelX, cursorLineY, buf, false);
|
renderer.drawText(UI_12_FONT_ID, cursorPixelX, cursorLineY, buf, false);
|
||||||
}
|
}
|
||||||
} else if (!cursorMode && cursorPos <= displayText.length()) {
|
} else if (cursorPos <= displayText.length()) {
|
||||||
static constexpr int serifW = 3;
|
static constexpr int serifW = 3;
|
||||||
const int cX = cursorPixelX;
|
const int cX = cursorPixelX;
|
||||||
const int cY = cursorLineY;
|
const int cY = cursorLineY;
|
||||||
@@ -496,7 +510,7 @@ void KeyboardEntryActivity::render(RenderLock&&) {
|
|||||||
const int toggleWidth = renderer.getTextWidth(UI_12_FONT_ID, toggleLabel);
|
const int toggleWidth = renderer.getTextWidth(UI_12_FONT_ID, toggleLabel);
|
||||||
const int toggleX = contentX + pageWidth - effectiveMargin - toggleWidth;
|
const int toggleX = contentX + pageWidth - effectiveMargin - toggleWidth;
|
||||||
const int toggleY = inputStartY + inputHeight;
|
const int toggleY = inputStartY + inputHeight;
|
||||||
const bool toggleSelected = cursorMode && cursorPos > text.length();
|
const bool toggleSelected = cursorMode && togglePos;
|
||||||
|
|
||||||
if (toggleSelected) {
|
if (toggleSelected) {
|
||||||
renderer.fillRect(toggleX - 2, toggleY, toggleWidth + 5, lineHeight + 3, true);
|
renderer.fillRect(toggleX - 2, toggleY, toggleWidth + 5, lineHeight + 3, true);
|
||||||
@@ -506,9 +520,101 @@ void KeyboardEntryActivity::render(RenderLock&&) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hintVisible && !text.empty()) {
|
||||||
|
const int hintLh = renderer.getLineHeight(SMALL_FONT_ID);
|
||||||
|
const int underlineY = inputStartY + inputHeight + lineHeight + metrics.verticalSpacing;
|
||||||
|
const int hintY = underlineY + 4;
|
||||||
|
if (cursorMode) {
|
||||||
|
int hintLineY = hintY;
|
||||||
|
if (inputType == InputType::Password && togglePos) {
|
||||||
|
renderer.drawCenteredText(
|
||||||
|
SMALL_FONT_ID, hintLineY,
|
||||||
|
passwordVisible ? tr(STR_KB_HINT_TOGGLE_HIDE_PASSWORD) : tr(STR_KB_HINT_TOGGLE_SHOW_PASSWORD), true);
|
||||||
|
hintLineY += hintLh;
|
||||||
|
renderer.drawCenteredText(SMALL_FONT_ID, hintLineY, tr(STR_KB_HINT_RETURN_CURSOR), true);
|
||||||
|
} else {
|
||||||
|
renderer.drawCenteredText(SMALL_FONT_ID, hintLineY, tr(STR_KB_HINT_MOVE_CURSOR), true);
|
||||||
|
hintLineY += hintLh;
|
||||||
|
if (inputType == InputType::Password) {
|
||||||
|
const char* passTip = passwordVisible ? tr(STR_KB_HINT_HIDE_PASSWORD) : tr(STR_KB_HINT_SHOW_PASSWORD);
|
||||||
|
renderer.drawCenteredText(SMALL_FONT_ID, hintLineY, passTip, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
renderer.drawCenteredText(SMALL_FONT_ID, hintY, tr(STR_KB_HINT_EDIT_ENTRY), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int keyHeight = metrics.keyboardKeyHeight;
|
||||||
|
const int bottomKeyHeight = metrics.keyboardBottomKeyHeight;
|
||||||
|
const int keySpacing = metrics.keyboardKeySpacing;
|
||||||
|
const int contentCols = getContentColCount();
|
||||||
|
const int keyboardWidth = pageWidth * metrics.keyboardWidthPercent / 100;
|
||||||
|
const int keyWidth = (keyboardWidth - (contentCols - 1) * keySpacing) / contentCols;
|
||||||
|
const int leftMargin = contentX + (pageWidth - (contentCols * keyWidth + (contentCols - 1) * keySpacing)) / 2;
|
||||||
|
|
||||||
|
const int bottomRowGap = metrics.keyboardBottomKeySpacing > 0 ? 4 : 0;
|
||||||
|
const int keyboardStartY = metrics.keyboardBottomAligned
|
||||||
|
? contentRect.y + pageHeight - metrics.verticalSpacing -
|
||||||
|
(keyHeight + keySpacing) * getContentRowCount() - bottomKeyHeight -
|
||||||
|
bottomRowGap + metrics.keyboardVerticalOffset
|
||||||
|
: inputStartY + inputHeight + lineHeight + metrics.verticalSpacing;
|
||||||
|
|
||||||
|
const int tipsLh = renderer.getLineHeight(SMALL_FONT_ID);
|
||||||
|
const int underlineBottom = inputStartY + inputHeight + lineHeight + metrics.verticalSpacing + 4;
|
||||||
|
auto drawTip = [&](const char* tip, int y) { renderer.drawCenteredText(SMALL_FONT_ID, y, tip, true); };
|
||||||
|
|
||||||
|
int tipCount = 0;
|
||||||
|
if (cursorMode) {
|
||||||
|
tipCount = 1;
|
||||||
|
} else if (urlMode) {
|
||||||
|
tipCount = 1 + (!text.empty() ? 1 : 0);
|
||||||
|
} else if (symMode) {
|
||||||
|
tipCount = !text.empty() ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
tipCount = 1 + (inputType == InputType::Url ? 1 : 0) + (!text.empty() ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tipCount > 0) {
|
||||||
|
int y = (underlineBottom + keyboardStartY) / 2 - (tipCount + 1) * tipsLh / 2;
|
||||||
|
drawTip(tr(STR_KB_TIPS), y);
|
||||||
|
y += tipsLh;
|
||||||
|
if (cursorMode) {
|
||||||
|
drawTip(tr(STR_KB_HINT_RETURN_KEYBOARD), y);
|
||||||
|
} else if (urlMode) {
|
||||||
|
drawTip(tr(STR_KB_HINT_EXIT_URL_MODE), y);
|
||||||
|
y += tipsLh;
|
||||||
|
if (!text.empty()) {
|
||||||
|
drawTip(tr(STR_KB_HINT_CLEAR_TEXT), y);
|
||||||
|
}
|
||||||
|
} else if (symMode) {
|
||||||
|
if (!text.empty()) {
|
||||||
|
drawTip(tr(STR_KB_HINT_CLEAR_TEXT), y);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const char* altCharTip;
|
||||||
|
if (inputType == InputType::Url) {
|
||||||
|
altCharTip = tr(STR_KB_HINT_SECONDARY_CHAR);
|
||||||
|
} else if (shiftState > 0) {
|
||||||
|
altCharTip = tr(STR_KB_HINT_LOWER_SECONDARY);
|
||||||
|
} else {
|
||||||
|
altCharTip = tr(STR_KB_HINT_UPPER_SECONDARY);
|
||||||
|
}
|
||||||
|
drawTip(altCharTip, y);
|
||||||
|
y += tipsLh;
|
||||||
|
if (inputType == InputType::Url) {
|
||||||
|
drawTip(tr(STR_KB_HINT_URL_SNIPPETS), y);
|
||||||
|
y += tipsLh;
|
||||||
|
}
|
||||||
|
if (!text.empty()) {
|
||||||
|
drawTip(tr(STR_KB_HINT_CLEAR_TEXT), y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const int bkSpacing = metrics.keyboardBottomKeySpacing;
|
const int bkSpacing = metrics.keyboardBottomKeySpacing;
|
||||||
const int contentTotalWidth =
|
const int abcKeyWidth = (keyboardWidth - (COLS - 1) * keySpacing) / COLS;
|
||||||
COLS * ((pageWidth * 95 / 100 - (COLS - 1) * keySpacing) / COLS) + (COLS - 1) * keySpacing;
|
const int contentTotalWidth = COLS * abcKeyWidth + (COLS - 1) * keySpacing;
|
||||||
const int bottomKeyWidth = (contentTotalWidth - (BOTTOM_KEY_COUNT - 1) * bkSpacing) / BOTTOM_KEY_COUNT;
|
const int bottomKeyWidth = (contentTotalWidth - (BOTTOM_KEY_COUNT - 1) * bkSpacing) / BOTTOM_KEY_COUNT;
|
||||||
const int bottomLeftMargin =
|
const int bottomLeftMargin =
|
||||||
contentX + (pageWidth - (BOTTOM_KEY_COUNT * bottomKeyWidth + (BOTTOM_KEY_COUNT - 1) * bkSpacing)) / 2;
|
contentX + (pageWidth - (BOTTOM_KEY_COUNT * bottomKeyWidth + (BOTTOM_KEY_COUNT - 1) * bkSpacing)) / 2;
|
||||||
@@ -516,11 +622,12 @@ void KeyboardEntryActivity::render(RenderLock&&) {
|
|||||||
int urlLeftMargin = leftMargin;
|
int urlLeftMargin = leftMargin;
|
||||||
if (urlMode) {
|
if (urlMode) {
|
||||||
const int urlTotalWidth = 3 * keyWidth + 2 * keySpacing;
|
const int urlTotalWidth = 3 * keyWidth + 2 * keySpacing;
|
||||||
const int urlCenterX = bottomLeftMargin + SpecSpace * (bottomKeyWidth + bkSpacing) + bottomKeyWidth / 2;
|
const int urlCenterX =
|
||||||
|
bottomLeftMargin + static_cast<int>(SpecialKeyType::Space) * (bottomKeyWidth + bkSpacing) + bottomKeyWidth / 2;
|
||||||
urlLeftMargin = urlCenterX - urlTotalWidth / 2;
|
urlLeftMargin = urlCenterX - urlTotalWidth / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const KeyDef(*layout)[COLS] = symMode ? symLayout : abcLayout;
|
const KeyDef(*layout)[COLS] = symMode ? symLayout : (inputType == InputType::Url ? urlLayout : abcLayout);
|
||||||
const int contentRows = getContentRowCount();
|
const int contentRows = getContentRowCount();
|
||||||
|
|
||||||
for (int row = 0; row < contentRows; row++) {
|
for (int row = 0; row < contentRows; row++) {
|
||||||
@@ -566,7 +673,9 @@ void KeyboardEntryActivity::render(RenderLock&&) {
|
|||||||
const char* label;
|
const char* label;
|
||||||
};
|
};
|
||||||
const BottomKeyInfo bottomKeys[BOTTOM_KEY_COUNT] = {
|
const BottomKeyInfo bottomKeys[BOTTOM_KEY_COUNT] = {
|
||||||
{KeyboardKeyType::Shift, (symMode || urlMode) ? shiftLabel(0) : shiftLabel(shiftState)},
|
{(symMode || urlMode || inputType == InputType::Url) ? KeyboardKeyType::Disabled : KeyboardKeyType::Shift,
|
||||||
|
(symMode || urlMode || inputType == InputType::Url) ? tr(STR_SHIFT)
|
||||||
|
: (shiftState == 0 ? tr(STR_SHIFT) : tr(STR_SHIFT_CAPS))},
|
||||||
{KeyboardKeyType::Mode, urlMode ? "abc" : (symMode ? "abc" : "#@!")},
|
{KeyboardKeyType::Mode, urlMode ? "abc" : (symMode ? "abc" : "#@!")},
|
||||||
{inputType == InputType::Url ? KeyboardKeyType::Mode : KeyboardKeyType::Space,
|
{inputType == InputType::Url ? KeyboardKeyType::Mode : KeyboardKeyType::Space,
|
||||||
inputType == InputType::Url ? "URL" : nullptr},
|
inputType == InputType::Url ? "URL" : nullptr},
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ struct KeyDef {
|
|||||||
char secondary;
|
char secondary;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SpecialKeyType { SpecShift, SpecMode, SpecSpace, SpecDel, SpecOk };
|
enum class SpecialKeyType { Shift, Mode, Space, Del, Ok };
|
||||||
|
|
||||||
enum class InputType { Text, Password, Url };
|
enum class InputType { Text, Password, Url };
|
||||||
|
|
||||||
@@ -51,18 +51,26 @@ class KeyboardEntryActivity : public Activity {
|
|||||||
bool confirmLongHandled = false;
|
bool confirmLongHandled = false;
|
||||||
|
|
||||||
bool cursorMode = false;
|
bool cursorMode = false;
|
||||||
|
bool togglePos = false;
|
||||||
size_t cursorPos = 0;
|
size_t cursorPos = 0;
|
||||||
bool upHeld = false;
|
bool upHeld = false;
|
||||||
bool upLongHandled = false;
|
bool upLongHandled = false;
|
||||||
bool downHeld = false;
|
bool downHeld = false;
|
||||||
bool downLongHandled = false;
|
bool downLongHandled = false;
|
||||||
|
bool rightHeld = false;
|
||||||
|
bool rightLongHandled = false;
|
||||||
|
size_t savedCursorPos = 0;
|
||||||
|
size_t rightStartCursorPos = 0;
|
||||||
|
|
||||||
bool urlMode = false;
|
bool urlMode = false;
|
||||||
static const char* shiftLabel(int shiftState);
|
|
||||||
static constexpr int URL_SNIPPET_COUNT = 9;
|
static constexpr int URL_SNIPPET_COUNT = 9;
|
||||||
static constexpr const char* const urlSnippets[URL_SNIPPET_COUNT] = {
|
static constexpr const char* const urlSnippets[URL_SNIPPET_COUNT] = {
|
||||||
"https://", "www.", ".com", "http://", "192.168.", ".org", "/opds", ":8080", ".net"};
|
"https://", "www.", ".com", "http://", "192.168.", ".org", "/opds", ":8080", ".net"};
|
||||||
|
|
||||||
|
int delPressCount = 0;
|
||||||
|
bool hintVisible = false;
|
||||||
|
unsigned long hintShowTime = 0;
|
||||||
|
|
||||||
void onComplete(std::string text);
|
void onComplete(std::string text);
|
||||||
void onCancel();
|
void onCancel();
|
||||||
|
|
||||||
@@ -75,8 +83,7 @@ class KeyboardEntryActivity : public Activity {
|
|||||||
static constexpr int BOTTOM_KEY_COUNT = 5;
|
static constexpr int BOTTOM_KEY_COUNT = 5;
|
||||||
|
|
||||||
static constexpr KeyDef abcLayout[ABC_ROWS][COLS] = {
|
static constexpr KeyDef abcLayout[ABC_ROWS][COLS] = {
|
||||||
{{'0', ')'},
|
{{'1', '!'},
|
||||||
{'1', '!'},
|
|
||||||
{'2', '@'},
|
{'2', '@'},
|
||||||
{'3', '#'},
|
{'3', '#'},
|
||||||
{'4', '$'},
|
{'4', '$'},
|
||||||
@@ -84,7 +91,8 @@ class KeyboardEntryActivity : public Activity {
|
|||||||
{'6', '^'},
|
{'6', '^'},
|
||||||
{'7', '&'},
|
{'7', '&'},
|
||||||
{'8', '*'},
|
{'8', '*'},
|
||||||
{'9', '('}},
|
{'9', '('},
|
||||||
|
{'0', ')'}},
|
||||||
{{'q', 'Q'},
|
{{'q', 'Q'},
|
||||||
{'w', 'W'},
|
{'w', 'W'},
|
||||||
{'e', 'E'},
|
{'e', 'E'},
|
||||||
@@ -117,9 +125,51 @@ class KeyboardEntryActivity : public Activity {
|
|||||||
{',', '<'}},
|
{',', '<'}},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr KeyDef urlLayout[ABC_ROWS][COLS] = {
|
||||||
|
{{'1', '!'},
|
||||||
|
{'2', '@'},
|
||||||
|
{'3', '#'},
|
||||||
|
{'4', '$'},
|
||||||
|
{'5', '%'},
|
||||||
|
{'6', '^'},
|
||||||
|
{'7', '&'},
|
||||||
|
{'8', '*'},
|
||||||
|
{'9', '('},
|
||||||
|
{'0', ')'}},
|
||||||
|
{{'q', 'Q'},
|
||||||
|
{'w', 'W'},
|
||||||
|
{'e', 'E'},
|
||||||
|
{'r', 'R'},
|
||||||
|
{'t', 'T'},
|
||||||
|
{'y', 'Y'},
|
||||||
|
{'u', 'U'},
|
||||||
|
{'i', 'I'},
|
||||||
|
{'o', 'O'},
|
||||||
|
{'p', 'P'}},
|
||||||
|
{{'a', 'A'},
|
||||||
|
{'s', 'S'},
|
||||||
|
{'d', 'D'},
|
||||||
|
{'f', 'F'},
|
||||||
|
{'g', 'G'},
|
||||||
|
{'h', 'H'},
|
||||||
|
{'j', 'J'},
|
||||||
|
{'k', 'K'},
|
||||||
|
{'l', 'L'},
|
||||||
|
{'-', '_'}},
|
||||||
|
{{'z', 'Z'},
|
||||||
|
{'x', 'X'},
|
||||||
|
{'c', 'C'},
|
||||||
|
{'v', 'V'},
|
||||||
|
{'b', 'B'},
|
||||||
|
{'n', 'N'},
|
||||||
|
{'m', 'M'},
|
||||||
|
{':', '+'},
|
||||||
|
{'.', '>'},
|
||||||
|
{'/', '<'}},
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr KeyDef symLayout[SYM_ROWS][COLS] = {
|
static constexpr KeyDef symLayout[SYM_ROWS][COLS] = {
|
||||||
{{'0', '\0'},
|
{{'1', '\0'},
|
||||||
{'1', '\0'},
|
|
||||||
{'2', '\0'},
|
{'2', '\0'},
|
||||||
{'3', '\0'},
|
{'3', '\0'},
|
||||||
{'4', '\0'},
|
{'4', '\0'},
|
||||||
@@ -127,9 +177,9 @@ class KeyboardEntryActivity : public Activity {
|
|||||||
{'6', '\0'},
|
{'6', '\0'},
|
||||||
{'7', '\0'},
|
{'7', '\0'},
|
||||||
{'8', '\0'},
|
{'8', '\0'},
|
||||||
{'9', '\0'}},
|
{'9', '\0'},
|
||||||
{{')', '\0'},
|
{'0', '\0'}},
|
||||||
{'!', '\0'},
|
{{'!', '\0'},
|
||||||
{'@', '\0'},
|
{'@', '\0'},
|
||||||
{'#', '\0'},
|
{'#', '\0'},
|
||||||
{'$', '\0'},
|
{'$', '\0'},
|
||||||
@@ -137,7 +187,8 @@ class KeyboardEntryActivity : public Activity {
|
|||||||
{'^', '\0'},
|
{'^', '\0'},
|
||||||
{'&', '\0'},
|
{'&', '\0'},
|
||||||
{'*', '\0'},
|
{'*', '\0'},
|
||||||
{'(', '\0'}},
|
{'(', '\0'},
|
||||||
|
{')', '\0'}},
|
||||||
{{'-', '\0'},
|
{{'-', '\0'},
|
||||||
{'_', '\0'},
|
{'_', '\0'},
|
||||||
{'=', '\0'},
|
{'=', '\0'},
|
||||||
|
|||||||
@@ -907,15 +907,18 @@ void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const ch
|
|||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
if (inactiveSelection) {
|
if (inactiveSelection) {
|
||||||
renderer.drawRect(rect.x, rect.y, rect.width, rect.height, 2, true);
|
renderer.drawRect(rect.x, rect.y, rect.width, rect.height, 2, true);
|
||||||
|
} else if (keyType == KeyboardKeyType::Disabled) {
|
||||||
|
renderer.fillRectDither(rect.x, rect.y, rect.width, rect.height, Color::LightGray);
|
||||||
} else {
|
} else {
|
||||||
renderer.fillRect(rect.x, rect.y, rect.width, rect.height, true);
|
renderer.fillRect(rect.x, rect.y, rect.width, rect.height, true);
|
||||||
}
|
}
|
||||||
} else if (keyType == KeyboardKeyType::Shift || keyType == KeyboardKeyType::Mode || keyType == KeyboardKeyType::Del ||
|
} else if (keyType == KeyboardKeyType::Shift || keyType == KeyboardKeyType::Mode || keyType == KeyboardKeyType::Del ||
|
||||||
keyType == KeyboardKeyType::Space || keyType == KeyboardKeyType::Ok) {
|
keyType == KeyboardKeyType::Space || keyType == KeyboardKeyType::Ok ||
|
||||||
|
keyType == KeyboardKeyType::Disabled) {
|
||||||
renderer.drawRect(rect.x, rect.y, rect.width, rect.height);
|
renderer.drawRect(rect.x, rect.y, rect.width, rect.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool invert = isSelected && !inactiveSelection;
|
const bool invert = isSelected && !inactiveSelection && keyType != KeyboardKeyType::Disabled;
|
||||||
|
|
||||||
if (keyType == KeyboardKeyType::Space) {
|
if (keyType == KeyboardKeyType::Space) {
|
||||||
const int lineHalfWidth = rect.width * 3 / 10;
|
const int lineHalfWidth = rect.width * 3 / 10;
|
||||||
|
|||||||
@@ -65,11 +65,13 @@ struct ThemeMetrics {
|
|||||||
bool keyboardBottomAligned;
|
bool keyboardBottomAligned;
|
||||||
bool keyboardCenteredText;
|
bool keyboardCenteredText;
|
||||||
int keyboardVerticalOffset;
|
int keyboardVerticalOffset;
|
||||||
|
int keyboardTextFieldWidthPercent;
|
||||||
|
int keyboardWidthPercent;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum UIIcon { Folder, Text, Image, Book, File, Recent, Settings, Transfer, Library, Wifi, Hotspot, Weather };
|
enum UIIcon { Folder, Text, Image, Book, File, Recent, Settings, Transfer, Library, Wifi, Hotspot, Weather };
|
||||||
|
|
||||||
enum class KeyboardKeyType { Normal, Shift, Mode, Reveal, Space, Del, Ok };
|
enum class KeyboardKeyType { Normal, Shift, Mode, Reveal, Space, Del, Ok, Disabled };
|
||||||
|
|
||||||
// Default theme implementation (Classic Theme)
|
// Default theme implementation (Classic Theme)
|
||||||
// Additional themes can inherit from this and override methods as needed
|
// Additional themes can inherit from this and override methods as needed
|
||||||
@@ -107,7 +109,9 @@ constexpr ThemeMetrics values = {.batteryWidth = 15,
|
|||||||
.keyboardBottomKeySpacing = 5,
|
.keyboardBottomKeySpacing = 5,
|
||||||
.keyboardBottomAligned = true,
|
.keyboardBottomAligned = true,
|
||||||
.keyboardCenteredText = false,
|
.keyboardCenteredText = false,
|
||||||
.keyboardVerticalOffset = -13};
|
.keyboardVerticalOffset = -13,
|
||||||
|
.keyboardTextFieldWidthPercent = 85,
|
||||||
|
.keyboardWidthPercent = 90};
|
||||||
}
|
}
|
||||||
|
|
||||||
class BaseTheme {
|
class BaseTheme {
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ constexpr ThemeMetrics values = {.batteryWidth = 16,
|
|||||||
.keyboardBottomKeySpacing = 5,
|
.keyboardBottomKeySpacing = 5,
|
||||||
.keyboardBottomAligned = true,
|
.keyboardBottomAligned = true,
|
||||||
.keyboardCenteredText = false,
|
.keyboardCenteredText = false,
|
||||||
.keyboardVerticalOffset = -7};
|
.keyboardVerticalOffset = -7,
|
||||||
|
.keyboardTextFieldWidthPercent = 85,
|
||||||
|
.keyboardWidthPercent = 90};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Lyra3CoversTheme : public LyraTheme {
|
class Lyra3CoversTheme : public LyraTheme {
|
||||||
|
|||||||
@@ -759,15 +759,18 @@ void LyraTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const ch
|
|||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
if (inactiveSelection) {
|
if (inactiveSelection) {
|
||||||
renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, cornerRadius, Color::LightGray);
|
renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, cornerRadius, Color::LightGray);
|
||||||
|
} else if (keyType == KeyboardKeyType::Disabled) {
|
||||||
|
renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, cornerRadius, Color::LightGray);
|
||||||
} else {
|
} else {
|
||||||
renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, cornerRadius, Color::Black);
|
renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, cornerRadius, Color::Black);
|
||||||
}
|
}
|
||||||
} else if (keyType == KeyboardKeyType::Shift || keyType == KeyboardKeyType::Mode || keyType == KeyboardKeyType::Del ||
|
} else if (keyType == KeyboardKeyType::Shift || keyType == KeyboardKeyType::Mode || keyType == KeyboardKeyType::Del ||
|
||||||
keyType == KeyboardKeyType::Space || keyType == KeyboardKeyType::Ok) {
|
keyType == KeyboardKeyType::Space || keyType == KeyboardKeyType::Ok ||
|
||||||
|
keyType == KeyboardKeyType::Disabled) {
|
||||||
renderer.drawRoundedRect(rect.x, rect.y, rect.width, rect.height, 1, cornerRadius, true);
|
renderer.drawRoundedRect(rect.x, rect.y, rect.width, rect.height, 1, cornerRadius, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool invert = isSelected && !inactiveSelection;
|
const bool invert = isSelected && !inactiveSelection && keyType != KeyboardKeyType::Disabled;
|
||||||
|
|
||||||
if (keyType == KeyboardKeyType::Space) {
|
if (keyType == KeyboardKeyType::Space) {
|
||||||
const int lineHalfWidth = rect.width * 3 / 10;
|
const int lineHalfWidth = rect.width * 3 / 10;
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ constexpr ThemeMetrics values = {.batteryWidth = 16,
|
|||||||
.keyboardBottomKeySpacing = 5,
|
.keyboardBottomKeySpacing = 5,
|
||||||
.keyboardBottomAligned = true,
|
.keyboardBottomAligned = true,
|
||||||
.keyboardCenteredText = false,
|
.keyboardCenteredText = false,
|
||||||
.keyboardVerticalOffset = -7};
|
.keyboardVerticalOffset = -7,
|
||||||
|
.keyboardTextFieldWidthPercent = 85,
|
||||||
|
.keyboardWidthPercent = 90};
|
||||||
}
|
}
|
||||||
|
|
||||||
class LyraTheme : public BaseTheme {
|
class LyraTheme : public BaseTheme {
|
||||||
|
|||||||
Reference in New Issue
Block a user