From 3b473093ced3e77eaa3111081bb5cffecd920991 Mon Sep 17 00:00:00 2001 From: pymuzard <pymuzard@gmail.com> Date: Mon, 16 Sep 2024 16:31:36 +0200 Subject: [PATCH 1/3] correction centrage des textes dans une box --- lib/graphics/src/Surface.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/graphics/src/Surface.cpp b/lib/graphics/src/Surface.cpp index 4c15b761..b3e92490 100644 --- a/lib/graphics/src/Surface.cpp +++ b/lib/graphics/src/Surface.cpp @@ -530,14 +530,18 @@ namespace graphics void Surface::drawTextCentered(std::string &text, const int16_t x, const int16_t y, const uint16_t w, const uint16_t h, const bool horizontallyCentered, const bool verticallyCentered, const std::optional<color_t> color) { - const uint16_t textWidth = m_sprite.textWidth(text.c_str()); +// const uint16_t textWidth = m_sprite.textWidth(text.c_str()); + const uint16_t textWidth = getTextWidth(text.c_str()); + int16_t textPositionX; if (horizontallyCentered) { - if (w == (uint16_t)-1) + if (w == (uint16_t)-1) { textPositionX = x + (double)this->getWidth() * 0.5 - (double)textWidth * 0.5; - else + } + else { textPositionX = x + (double)w * 0.5 - (double)textWidth * 0.5; + } } else { From 3b80433871fece5b2aaa8d64bcc01936d4e7a01a Mon Sep 17 00:00:00 2001 From: pymuzard <pymuzard@gmail.com> Date: Tue, 17 Sep 2024 16:58:20 +0200 Subject: [PATCH 2/3] ajout keyboard 2 --- lib/gui/src/elements/Image.cpp | 2 +- lib/gui/src/elements/Keyboard2.cpp | 881 ++++++++++++++++++ lib/gui/src/elements/Keyboard2.hpp | 150 +++ lib/gui/src/gui.hpp | 1 + lib/lua/src/lua_file.cpp | 1 + lib/lua/src/lua_gui.cpp | 29 + lib/lua/src/lua_gui.hpp | 1 + storage/system/keyboard2/backspace_icon.png | Bin 0 -> 592 bytes storage/system/keyboard2/caps_icon_0.png | Bin 0 -> 630 bytes storage/system/keyboard2/caps_icon_1.png | Bin 0 -> 674 bytes storage/system/keyboard2/caps_icon_2.png | Bin 0 -> 767 bytes storage/system/keyboard2/confirm_icon.png | Bin 0 -> 877 bytes storage/system/keyboard2/exit_icon.png | Bin 0 -> 1470 bytes storage/system/keyboard2/layout_icon_0.png | Bin 0 -> 3149 bytes storage/system/keyboard2/layout_icon_1.png | Bin 0 -> 1051 bytes .../system/keyboard2/trackpad_active_icon.png | Bin 0 -> 865 bytes 16 files changed, 1064 insertions(+), 1 deletion(-) create mode 100644 lib/gui/src/elements/Keyboard2.cpp create mode 100644 lib/gui/src/elements/Keyboard2.hpp create mode 100644 storage/system/keyboard2/backspace_icon.png create mode 100644 storage/system/keyboard2/caps_icon_0.png create mode 100644 storage/system/keyboard2/caps_icon_1.png create mode 100644 storage/system/keyboard2/caps_icon_2.png create mode 100644 storage/system/keyboard2/confirm_icon.png create mode 100644 storage/system/keyboard2/exit_icon.png create mode 100644 storage/system/keyboard2/layout_icon_0.png create mode 100644 storage/system/keyboard2/layout_icon_1.png create mode 100644 storage/system/keyboard2/trackpad_active_icon.png diff --git a/lib/gui/src/elements/Image.cpp b/lib/gui/src/elements/Image.cpp index 1c9f4dac..e805fc42 100644 --- a/lib/gui/src/elements/Image.cpp +++ b/lib/gui/src/elements/Image.cpp @@ -58,7 +58,7 @@ namespace gui::ImagesList if (img->surface.use_count() == 1) { img = images.erase(img); - std::cout << "[Image] image deleted" << std::endl; + //std::cout << "[Image] image deleted" << std::endl; } else { diff --git a/lib/gui/src/elements/Keyboard2.cpp b/lib/gui/src/elements/Keyboard2.cpp new file mode 100644 index 00000000..171a6290 --- /dev/null +++ b/lib/gui/src/elements/Keyboard2.cpp @@ -0,0 +1,881 @@ +// +// Created by Charles on 13/03/2024. +// + +#include "Keyboard2.hpp" + +#include <iostream> +#include <graphics.hpp> +#include <libsystem.hpp> +#include <Surface.hpp> + +#include "Box.hpp" +#include "Filter.hpp" +#include "Image.hpp" + +// Layouts +constexpr char LAYOUT_LOWERCASE = 0; +constexpr char LAYOUT_UPPERCASE = 1; +constexpr char LAYOUT_NUMBERS = 2; + +// 0x0_ => Control chars +constexpr char KEY_NULL = 0x00; +constexpr char KEY_EXIT = 0x01; + +// 0x1_ => Special Chars +constexpr char KEY_SPACE = 0x10; +constexpr char KEY_BACKSPACE = 0x11; + +// 0x2_ => Modifiers +constexpr char KEY_CAPS = 0x20; + +// -0x1_ => Keyboard Layouts +constexpr char KEY_LAYOUT_STANDARD = -0x10; // Lowercase or Uppercase, based on context +constexpr char KEY_LAYOUT_LOWERCASE = -0x11; +constexpr char KEY_LAYOUT_UPPERCASE = -0x12; +constexpr char KEY_LAYOUT_NUMBERS = -0x13; + +// Caps +constexpr uint8_t CAPS_NONE = 0; +constexpr uint8_t CAPS_ONCE = 1; +constexpr uint8_t CAPS_LOCK = 2; + +namespace gui::elements { + Keyboard2::Keyboard2(const std::string &defaultText) { + m_buffer = defaultText; + m_defaultText = defaultText; + + // check with the graphics Orientation ... maybe add a parameter to choose ? + m_width = graphics::getScreenWidth(); + m_height = graphics::getScreenHeight(); + + m_x = 0; + m_y = 0; + + m_backgroundColor = graphics::packRGB565(255, 255, 255); + m_hasEvents = true; + m_caps = CAPS_NONE; + + boxHeight = 40; + hauteurKeyboard = boxHeight * 4; + offsetBord = 5; + keyZoomRatio = 1.5; + hauteurRetourZoom = 10; + + + int16_t largeur9 = (m_width - (9-1)) / static_cast<float>(9); + int largeurConfirmation = 40; + +// m_keysCanvas = new Canvas(30, 140, 420, 160); + m_keysCanvas = new Canvas(offsetBord, m_height - hauteurKeyboard -offsetBord, m_width-2*offsetBord, hauteurKeyboard); + addChild(m_keysCanvas); + + m_layoutLowercase = new char *[4]; + m_layoutLowercase[0] = new char[10]{'a', 'z', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'}; + m_layoutLowercase[1] = new char[10]{'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm'}; + m_layoutLowercase[2] = new char[9]{KEY_CAPS, 'w', 'x', 'c', 'v', 'b', 'n', '\'', KEY_BACKSPACE}; + m_layoutLowercase[3] = new char[3]{KEY_LAYOUT_NUMBERS, KEY_SPACE, KEY_EXIT}; + + m_layoutUppercase = new char *[4]; + m_layoutUppercase[0] = new char[10]{'A', 'Z', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'}; + m_layoutUppercase[1] = new char[10]{'Q', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M'}; + m_layoutUppercase[2] = new char[9]{KEY_CAPS, 'W', 'X', 'C', 'V', 'B', 'N', '\'', KEY_BACKSPACE}; + m_layoutUppercase[3] = new char[3]{KEY_LAYOUT_NUMBERS, KEY_SPACE, KEY_EXIT}; + + m_layoutNumbers = new char *[4]; + m_layoutNumbers[0] = new char[10]{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}; + m_layoutNumbers[1] = new char[10]{'+', '-', '*', '/', '(', ')', '[', ']', '<', '>'}; + m_layoutNumbers[2] = new char[9]{KEY_CAPS, '_', ',', '.', ':', ';', '!', '?', KEY_BACKSPACE}; + m_layoutNumbers[3] = new char[3]{KEY_LAYOUT_STANDARD, KEY_SPACE, KEY_EXIT}; + + m_currentLayout = LAYOUT_LOWERCASE; + + // Create label for text + m_label = new Label(offsetBord+1, offsetBord, m_width-2*offsetBord - largeurConfirmation, m_height - hauteurKeyboard-2*offsetBord); + // m_label->setFont(graphics::ARIAL); + m_label->setFontSize(24); + m_label->setCursorEnabled(true); + m_label->setText(m_buffer); + m_label->setCursorIndex(static_cast<int16_t>(m_buffer.length())); + addChild(m_label); + + // Create images box (for better performances ?) + + m_capsBox = new Box(offsetBord+1, m_height-hauteurKeyboard-offsetBord +boxHeight*2+1, largeur9-2, boxHeight-2); + m_backspaceBox = new Box(m_width-offsetBord-largeur9+2, m_height-hauteurKeyboard-offsetBord+boxHeight*2+1, largeur9-2, boxHeight-2); + + m_confirmBox = new Box(m_width-largeurConfirmation -offsetBord, offsetBord, largeurConfirmation, boxHeight); + + m_layoutBox = new Box(offsetBord+1, m_height-hauteurKeyboard-offsetBord+boxHeight*3+1, 60-2, boxHeight-2); + m_exitBox = new Box(m_width-offsetBord-60+1, m_height-hauteurKeyboard-offsetBord+boxHeight*3+1, 60-2, boxHeight-2); + + m_capsBox->setBackgroundColor(COLOR_LIGHT_GREY); + m_capsBox->setRadius(5); + m_layoutBox->setBackgroundColor(COLOR_LIGHT_GREY); + m_layoutBox->setRadius(5); + m_backspaceBox->setBackgroundColor(COLOR_LIGHT_GREY); + m_backspaceBox->setRadius(5); + m_exitBox->setBackgroundColor(COLOR_LIGHT_GREY); + m_exitBox->setRadius(5); + + + + // Gestion des key Zoom + const float keyWidth10 = (m_width - (10-1)) / 10 - 1; + const float keyWidth9 = (m_width - (9-1)) / 9 - 1; + + // ZoomKey Left 10 + m_boxdKeyPressed_Left10 = new Box (0, 0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio); + m_boxdKeyPressed_Left10-> disable(); + m_CanevasKeyPressed_Left10 = new Canvas(0,0,keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio); + m_CanevasKeyPressed_Left10->fillRect(0,0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio, COLOR_WHITE); + + std::vector<std::pair<int16_t, int16_t>> verticesLeft10; + verticesLeft10.push_back( {0 , 5} ); + verticesLeft10.push_back( {0 , boxHeight*keyZoomRatio} ); + verticesLeft10.push_back( {keyWidth10-2 , boxHeight*keyZoomRatio} ); + verticesLeft10.push_back( {keyWidth10*keyZoomRatio-1 , boxHeight*keyZoomRatio-hauteurRetourZoom }); + verticesLeft10.push_back( {keyWidth10*keyZoomRatio-1 , 5} ); + verticesLeft10.push_back( {keyWidth10*keyZoomRatio-5-1 , 0} ); + verticesLeft10.push_back( {5 , 0} ); + + m_CanevasKeyPressed_Left10->fillPolygon(verticesLeft10, COLOR_LIGHT_GREY); + m_CanevasKeyPressed_Left10->drawPolygon(verticesLeft10, COLOR_WHITE); + m_boxdKeyPressed_Left10->addChild(m_CanevasKeyPressed_Left10); + addChild(m_boxdKeyPressed_Left10); + + // ZoomKey Center 10 + m_boxdKeyPressed_Center10 = new Box (0, 0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio); + m_boxdKeyPressed_Center10-> disable(); + m_CanevasKeyPressed_Center10 = new Canvas(0,0,keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio); + m_CanevasKeyPressed_Center10->fillRect(0,0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio, COLOR_WHITE); + + std::vector<std::pair<int16_t, int16_t>> verticesCenter10; + verticesCenter10.push_back( {0 , 5} ); + verticesCenter10.push_back( {0 , boxHeight*keyZoomRatio-hauteurRetourZoom} ); + verticesCenter10.push_back( {(keyWidth10*keyZoomRatio - keyWidth10 ) /2 , boxHeight*keyZoomRatio} ); + verticesCenter10.push_back( {(keyWidth10*keyZoomRatio - keyWidth10 ) /2 +keyWidth10, boxHeight*keyZoomRatio} ); + verticesCenter10.push_back( {keyWidth10*keyZoomRatio-1 , boxHeight*keyZoomRatio-hauteurRetourZoom }); + verticesCenter10.push_back( {keyWidth10*keyZoomRatio-1 , 5} ); + verticesCenter10.push_back( {keyWidth10*keyZoomRatio-5-1 , 0} ); + verticesCenter10.push_back( {5 , 0} ); + + m_CanevasKeyPressed_Center10->fillPolygon(verticesCenter10, COLOR_LIGHT_GREY); + m_CanevasKeyPressed_Center10->drawPolygon(verticesCenter10, COLOR_WHITE); + m_boxdKeyPressed_Center10->addChild(m_CanevasKeyPressed_Center10); + addChild(m_boxdKeyPressed_Center10); + + // ZoomKey Right 10 + m_boxdKeyPressed_Right10 = new Box (0, 0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio); + m_boxdKeyPressed_Right10-> disable(); + m_CanevasKeyPressed_Right10 = new Canvas(0,0,keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio); + m_CanevasKeyPressed_Right10->fillRect(0,0, keyWidth10*keyZoomRatio, boxHeight*keyZoomRatio, COLOR_WHITE); + + std::vector<std::pair<int16_t, int16_t>> verticesRight10; + verticesRight10.push_back( {0 , 5} ); + verticesRight10.push_back( {0 , boxHeight*keyZoomRatio-hauteurRetourZoom} ); + verticesRight10.push_back( {keyWidth10*keyZoomRatio - keyWidth10+1 , boxHeight*keyZoomRatio} ); + verticesRight10.push_back( {keyWidth10*keyZoomRatio-1 , boxHeight*keyZoomRatio} ); + verticesRight10.push_back( {keyWidth10*keyZoomRatio-1 , 5 }); + verticesRight10.push_back( {keyWidth10*keyZoomRatio-5-1 , 0} ); + verticesRight10.push_back( {5 , 0} ); + + m_CanevasKeyPressed_Right10->fillPolygon(verticesRight10, COLOR_LIGHT_GREY); + m_CanevasKeyPressed_Right10->drawPolygon(verticesRight10, COLOR_WHITE); + m_boxdKeyPressed_Right10->addChild(m_CanevasKeyPressed_Right10); + addChild(m_boxdKeyPressed_Right10); + + // ZoomKey Center 9 + m_boxdKeyPressed_Center9 = new Box (0, 0, keyWidth9*keyZoomRatio, boxHeight*keyZoomRatio); + m_boxdKeyPressed_Center9-> disable(); + m_CanevasKeyPressed_Center9 = new Canvas(0,0,keyWidth9*keyZoomRatio, boxHeight*keyZoomRatio); + m_CanevasKeyPressed_Center9->fillRect(0,0, keyWidth9*keyZoomRatio, boxHeight*keyZoomRatio, COLOR_WHITE); + + std::vector<std::pair<int16_t, int16_t>> verticesCenter9; + verticesCenter9.push_back( {0 , 5} ); + verticesCenter9.push_back( {0 , boxHeight*keyZoomRatio-hauteurRetourZoom} ); + verticesCenter9.push_back( {(keyWidth9*keyZoomRatio - keyWidth9 ) /2 , boxHeight*keyZoomRatio} ); + verticesCenter9.push_back( {(keyWidth9*keyZoomRatio - keyWidth9 ) /2 +keyWidth9, boxHeight*keyZoomRatio} ); + verticesCenter9.push_back( {keyWidth9*keyZoomRatio-1 , boxHeight*keyZoomRatio-hauteurRetourZoom }); + verticesCenter9.push_back( {keyWidth9*keyZoomRatio-1 , 5} ); + verticesCenter9.push_back( {keyWidth9*keyZoomRatio-1-5 , 0} ); + verticesCenter9.push_back( {5 , 0} ); + + m_CanevasKeyPressed_Center9->fillPolygon(verticesCenter9, COLOR_LIGHT_GREY); + m_CanevasKeyPressed_Center9->drawPolygon(verticesCenter9, COLOR_WHITE); + m_boxdKeyPressed_Center9->addChild(m_CanevasKeyPressed_Center9); + addChild(m_boxdKeyPressed_Center9); +/* + m_pressedKey_Right10; + m_pressedKey_Left9; + m_pressedKey_Left9; + m_pressedKey_Center10; + m_pressedKey_Center9; +*/ + + // Create images + m_capsIcon0 = new Image(storage::Path("system/Keyboard2/caps_icon_0.png"), 3, 3, largeur9-7, boxHeight-7, COLOR_LIGHT_GREY); + m_capsIcon1 = new Image(storage::Path("system/Keyboard2/caps_icon_1.png"), 3, 3, largeur9-7, boxHeight-7, COLOR_LIGHT_GREY); + m_capsIcon2 = new Image(storage::Path("system/Keyboard2/caps_icon_2.png"), 3, 3, largeur9-7, boxHeight-7, COLOR_LIGHT_GREY); + m_backspaceIcon = new Image(storage::Path("system/Keyboard2/backspace_icon.png"), 3, 3, largeur9-7, boxHeight-7, COLOR_LIGHT_GREY); + + m_layoutIcon0 = new Image(storage::Path("system/Keyboard2/layout_icon_0.png"), 10, 3, 40, boxHeight-7, COLOR_LIGHT_GREY); + m_layoutIcon1 = new Image(storage::Path("system/Keyboard2/layout_icon_1.png"), 10, 3, 40, boxHeight-7, COLOR_LIGHT_GREY); + + m_exitIcon = new Image(storage::Path("system/Keyboard2/exit_icon.png"), 3, 3, 60-4, boxHeight-7, COLOR_LIGHT_GREY); + m_confirmIcon = new Image(storage::Path("system/Keyboard2/confirm_icon.png"), 0, 0, largeurConfirmation, boxHeight); + + // Load images into RAM + m_capsIcon0->load(); + m_capsIcon1->load(); + m_capsIcon2->load(); + m_backspaceIcon->load(); + m_layoutIcon0->load(); + m_layoutIcon1->load(); + m_exitIcon->load(); + m_confirmIcon->load(); + + // Add images to boxes + m_capsBox->addChild(m_capsIcon0); + m_capsBox->addChild(m_capsIcon1); + m_capsBox->addChild(m_capsIcon2); + m_backspaceBox->addChild(m_backspaceIcon); + m_layoutBox->addChild(m_layoutIcon0); + m_layoutBox->addChild(m_layoutIcon1); + m_exitBox->addChild(m_exitIcon); + m_confirmBox->addChild(m_confirmIcon); + + // Add boxes + addChild(m_capsBox); + addChild(m_layoutBox); + addChild(m_backspaceBox); + addChild(m_exitBox); + addChild(m_confirmBox); + + updateCapsIcon(); + updateLayoutIcon(); + +// m_trackpadActiveBox = new Box(192, 112, 96, 96); + m_trackpadActiveBox = new Box((m_width-96) /2, m_height-offsetBord-hauteurKeyboard+12, 96, 96); + m_trackpadActiveBox->setBackgroundColor(TFT_BLACK); + m_trackpadActiveBox->setRadius(8); + addChild(m_trackpadActiveBox); + + m_trackpadActiveIcon = new Image(storage::Path("system/Keyboard2/trackpad_active_icon.png"), 16, 16, 64, 64); + m_trackpadActiveIcon->load(TFT_BLACK); + m_trackpadActiveBox->addChild(m_trackpadActiveIcon); + + m_trackpadActiveBox->disable(); + + m_trackpadTicks = 0; + m_trackpadLastDeltaX = 0; + m_zoomKeyTicks = 0; + } + + + + Keyboard2::~Keyboard2() = default; + + + + void Keyboard2::render() { + m_surface->fillRect(0, 0, m_width, m_height, m_backgroundColor); + + // Input box + drawInputBox(); + + if (!isTrackpadActive()) { + // Draw keys + drawKeys(); + } + } + + void Keyboard2::widgetUpdate() { + if (isTouched()) { + // Get touch position + int16_t touchX, touchY; + getLastTouchPosRel(&touchX, &touchY); + + const char pressedKey = getKey(touchX, touchY); + if (pressedKey == KEY_NULL) { + return; + } + + //drawZoomKeyLeft10 (touchX, touchY, pressedKey, 10); + processKey(pressedKey); + } + + if (m_exitBox->isTouched()) { + m_buffer = m_defaultText; // Reset text + m_exit = true; + } + + if (m_confirmBox->isTouched()) { + m_exit = true; + } + + if (m_backspaceBox->isTouched()) { + removeChar(); + + // Redraw input box + drawInputBox(); + } + + if (m_capsBox->isTouched()) { + switch (m_caps) { + case CAPS_NONE: + default: + m_currentLayout = LAYOUT_UPPERCASE; + m_caps = CAPS_ONCE; + break; + case CAPS_ONCE: + m_currentLayout = LAYOUT_UPPERCASE; + m_caps = CAPS_LOCK; + break; + case CAPS_LOCK: + m_currentLayout = LAYOUT_LOWERCASE; + m_caps = CAPS_NONE; + break; + } + + updateCapsIcon(); + } + + if (m_layoutBox->isTouched()) { + if (m_currentLayout == LAYOUT_LOWERCASE || m_currentLayout == LAYOUT_UPPERCASE) { + m_currentLayout = LAYOUT_NUMBERS; + } else if (m_currentLayout == LAYOUT_NUMBERS) { + if (m_caps == CAPS_NONE) { + m_currentLayout = LAYOUT_LOWERCASE; + } else { + m_currentLayout = LAYOUT_UPPERCASE; + } + } + + drawKeys(); + updateLayoutIcon(); + } + + trackpadUpdate(); + zoomKeyUpdate(); + } + + std::string Keyboard2::getText() { + const std::string output = m_buffer; + + m_buffer = ""; + + return output; + } + + void Keyboard2::drawKeys() const { + // Reset default settings + m_keysCanvas->fillRect(0, 0, m_keysCanvas->getWidth(), m_keysCanvas->getHeight(), +// graphics::packRGB565(125, 126, 127)); + graphics::packRGB565(255, 255, 255)); + + // Draw every keys + drawKeyRow(0*boxHeight, getLayoutCharMap()[0]); + drawKeyRow(1*boxHeight, getLayoutCharMap()[1]); + drawKeyRow(2*boxHeight, getLayoutCharMap()[2]); + drawLastRow(3*boxHeight); + } + + void Keyboard2::drawKeyRow(const int16_t y, const char *keys) const { + + uint8_t count = strlen(keys); + // calcul de la largeur d'une touche (on laisse 1 entre chacune touche) + const float keyWidth = (m_width - (count-1)) / static_cast<float>(count); + + for (uint16_t i = 0; i < count; i++) { + drawKey( + static_cast<int16_t>(static_cast<float>(i) * keyWidth), // position X + y, // position Y + static_cast<int16_t>(keyWidth), // largeur touche + keys[i] // Texte de la touche + ); + } + } + + void Keyboard2::drawKey(const int16_t x, const int16_t y, const uint16_t w, const char key) const { + auto keyString = std::string(1, key); +// const float keyWidth = (m_width - (count-1)) / static_cast<float>(count); + + m_keysCanvas->fillRoundRect(x+1, y+1, w-2, boxHeight-2, 5, COLOR_LIGHT_GREY); + m_keysCanvas->drawTextCenteredInRect(x+1, y+1, w-2, boxHeight-2, keyString, COLOR_BLACK, true, true, 28); + } + + void Keyboard2::drawLastRow(const int16_t y) const { + // Draw spacebar + m_keysCanvas->fillRoundRect(60+1, y+1, m_width-2*60-2*offsetBord-2, boxHeight-2, 5, COLOR_LIGHT_GREY); + m_keysCanvas->fillRect(offsetBord+60+5, y+3*boxHeight/4, m_width-(2*60+2*offsetBord+20), 2, graphics::packRGB565(0, 0, 0)); + } + + uint8_t Keyboard2::getKeyCol(const int16_t x, const uint8_t keyCount) const { + float boxX = offsetBord; +// const float keyWidth = 420.0f / static_cast<float>(keyCount); + const float keyWidth = (m_width-2*offsetBord) / static_cast<float>(keyCount); + + for (uint8_t i = 0; i < keyCount; i++) { + if (static_cast<float>(x) >= boxX && static_cast<float>(x) <= boxX + keyWidth) { + return i; + } + boxX += keyWidth; + } + return -1; + } + + char Keyboard2::getKey(const int16_t x, const int16_t y) const { + // Check if the position is in the Keyboard2 box + + + Keyboard2::Coord result; + result = getRowColumn(x, y); + + if (result.row == -1 && result.column == -1) { + return KEY_NULL; + } + +/* + + std::cout << "x = " << x << " y = " << y << std::endl; + if (!(x >= offsetBord && x <= m_width-offsetBord && y >= m_height - hauteurKeyboard - offsetBord && y <= m_height - offsetBord)) { + std::cout << "NULL KEY"<< std::endl; + return KEY_NULL; + } + + int row; + int column; + + row = 3 - (int) (m_height - y - offsetBord)/boxHeight; + if (row <3) { + column = getKeyCol(x, strlen(getLayoutCharMap()[row])); + + } else { + // Get column of last row + if (x <= 60 + offsetBord) { + column = 0; + } else if (x > m_width - offsetBord-60) { + column = 2; + } else { + column = 1; + } + } +*/ + return getLayoutCharMap()[result.row][result.column]; + } + + + Keyboard2::Coord Keyboard2::getRowColumn(const int16_t x, const int16_t y) const { + // Check if the position is in the Keyboard2 box +// if (!(x >= 30 && x <= 450 && y >= 140 && y <= 300)) { + Coord result; + result.row = -1; + result.column = -1; +// std::cout << "[getRowColumn] x=" << x << " y=" << y << std::endl; + + + if (!(x >= offsetBord && x <= m_width-offsetBord && y >= m_height - hauteurKeyboard - offsetBord && y <= m_height - offsetBord)) { +// std::cout << "[getRowColumn] Hors Champs x=" << x << " y=" << y <<std::endl; + return result; + } + + uint16_t row; + uint16_t column; + + row = 3 - (uint16_t) (m_height - y - offsetBord)/boxHeight; +// std::cout << "[getRowColumn] row=" << row <<std:: endl; + + if (row <3) { + column = getKeyCol(x, strlen(getLayoutCharMap()[row])); + + } else { + // Get column of last row + if (x <= 60 + offsetBord) { + column = 0; + } else if (x > m_width - offsetBord-60) { + column = 2; + } else { + column = 1; + } + } +// std::cout << "[getRowColumn] column=" << column <<std:: endl; + + result.row = row; + result.column = column; + + return result; + } + + + + /** + * Execute the needed action for the key + * @param key The key to process + */ + void Keyboard2::processKey(const char key) { + switch (key) { + case KEY_NULL: + case KEY_EXIT: + case KEY_BACKSPACE: + case KEY_CAPS: + case KEY_LAYOUT_STANDARD: + case KEY_LAYOUT_NUMBERS: + // KEY_EXIT & KEY_BACKSPACE & KEY_CAPS & KEY_LAYOUT_STANDARD & KEY_LAYOUT_NUMBERS are handled directly in update function + return; + case KEY_SPACE: + addChar(' '); + break; + default: + addChar(key); + + // Disable caps if not locked + if (m_caps == CAPS_ONCE) { + m_currentLayout = LAYOUT_LOWERCASE; + m_caps = CAPS_NONE; + + drawKeys(); + updateCapsIcon(); // Fix bug + + return; + } + break; + } + // Redraw input box + drawInputBox(); // <= Useless, because "markDirty" redraws it + } + + void Keyboard2::drawInputBox() const { + if (m_buffer.empty()) { + if (m_placeholder.empty()) { + m_label->setText(""); + return; + } + + // Draw placeholder + m_label->setTextColor(graphics::packRGB565(200, 200, 200)); + m_label->setText(m_placeholder); + + m_label->setCursorEnabled(false); + } else { + // Draw text + m_label->setTextColor(graphics::packRGB565(0, 0, 0)); + m_label->setText(m_buffer); + + m_label->setCursorEnabled(true); + } + } + + + void Keyboard2::updateCapsIcon() const { + switch (m_caps) { + case CAPS_NONE: + m_capsIcon0->enable(); + m_capsIcon1->disable(); + m_capsIcon2->disable(); + break; + case CAPS_ONCE: + m_capsIcon0->disable(); + m_capsIcon1->enable(); + m_capsIcon2->disable(); + break; + case CAPS_LOCK: + m_capsIcon0->disable(); + m_capsIcon1->disable(); + m_capsIcon2->enable(); + break; + default: ; + } + } + + void Keyboard2::updateLayoutIcon() const { + switch (m_currentLayout) { + case LAYOUT_LOWERCASE: + case LAYOUT_UPPERCASE: + m_layoutIcon0->enable(); + m_layoutIcon1->disable(); + break; + case LAYOUT_NUMBERS: + m_layoutIcon0->disable(); + m_layoutIcon1->enable(); + break; + default: ; + } + } + + bool Keyboard2::hasExitKeyBeenPressed() const { + return m_exit; + } + + void Keyboard2::setPlaceholder(const std::string &placeholder) { + m_placeholder = placeholder; + } + + char **Keyboard2::getLayoutCharMap() const { + switch (m_currentLayout) { + case LAYOUT_LOWERCASE: + default: + return m_layoutLowercase; + case LAYOUT_UPPERCASE: + return m_layoutUppercase; + case LAYOUT_NUMBERS: + return m_layoutNumbers; + } + } + + void Keyboard2::trackpadUpdate() { + int16_t rawTouchX, rawTouchY; + graphics::getTouchPos(&rawTouchX, &rawTouchY); + + const bool wasTrackpadActive = isTrackpadActive(); + + // Check if finger is on screen + if ((rawTouchX != -1 && rawTouchY != -1) && isPointInTrackpad(originTouchX, originTouchY)) { + + if (m_trackpadTicks < UINT8_MAX) { + m_trackpadTicks++; + } + + if (isTrackpadActive()) { + if (m_trackpadTicks == 10) { + m_trackpadActiveBox->enable(); + m_trackpadLastDeltaX = 0; + localGraphicalUpdate(); + } + + const int32_t deltaX = rawTouchX - originTouchX; + std::string deltaXString = std::to_string(deltaX); + + constexpr int32_t stepsByChar = 8; + const int32_t toMove = (deltaX - m_trackpadLastDeltaX) / stepsByChar; + + if (toMove > 0) { + for (int i = 0; i < toMove; i++) { + m_label->setCursorIndex(static_cast<int16_t>(m_label->getCursorIndex() + 1)); + } + } else if (toMove < 0) { + for (int i = 0; i < -toMove; i++) { + m_label->setCursorIndex(static_cast<int16_t>(m_label->getCursorIndex() - 1)); + } + } + + if (abs(toMove) > 0) { + m_label->forceUpdate(); + // m_trackpadActiveBox->forceUpdate(); + } + + m_trackpadLastDeltaX += toMove * stepsByChar; + } + } else { + m_trackpadTicks = 0; + + if (wasTrackpadActive) { + // Do once + // m_trackpadFilter->disable(); + m_trackpadActiveBox->disable(); + localGraphicalUpdate(); + } + } + } + + bool Keyboard2::isPointInTrackpad(const int16_t x, const int16_t y) const { + + if (x < 60+1 || x > 60+1 + m_width-2*60-2*offsetBord-2) return false; + if (y< m_height -offsetBord- boxHeight || y > m_height - offsetBord) return false; + + return true; + } + + bool Keyboard2::isTrackpadActive() const { + return m_trackpadTicks >= 10; + } + + void Keyboard2::addChar(const char value) { + m_buffer.insert(m_label->getCursorIndex(), 1, value); + + // Update cursor position + // TODO: Remove m_buffer and use only label ? + m_label->setText(m_buffer); + m_label->setCursorIndex(m_label->getCursorIndex() + 1); + } + + void Keyboard2::removeChar() { + if (m_buffer.empty()) { + return; + } + if (m_label->getCursorIndex() <= 0) { + return; + } + + m_buffer.erase(m_label->getCursorIndex() - 1, 1); + m_label->setCursorIndex(static_cast<int16_t>(m_label->getCursorIndex() - 1)); + } + + + + void Keyboard2::drawZoomKeyLeft10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key) + { + + // Create Box for the current pressed key + m_boxdKeyPressed_Left10->enable(); + m_boxdKeyPressed_Left10->setX(x); + m_boxdKeyPressed_Left10->setY(y); + + auto keyString = std::string(1, key); + m_CanevasKeyPressed_Left10->fillRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, COLOR_LIGHT_GREY); + m_CanevasKeyPressed_Left10->drawTextCenteredInRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, keyString, COLOR_BLACK, true, true, 38); + + + } + + void Keyboard2::drawZoomKeyCenter10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key) + { + + // Create Box for the current pressed key + m_boxdKeyPressed_Center10->enable(); + m_boxdKeyPressed_Center10->setX(x); + m_boxdKeyPressed_Center10->setY(y); + + auto keyString = std::string(1, key); + m_CanevasKeyPressed_Center10->fillRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, COLOR_LIGHT_GREY); + m_CanevasKeyPressed_Center10->drawTextCenteredInRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, keyString, COLOR_BLACK, true, true, 38); + + } + + void Keyboard2::drawZoomKeyRight10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key) + { + + // Create Box for the current pressed key + m_boxdKeyPressed_Right10->enable(); + m_boxdKeyPressed_Right10->setX(x); + m_boxdKeyPressed_Right10->setY(y); + + auto keyString = std::string(1, key); + m_CanevasKeyPressed_Right10->fillRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, COLOR_LIGHT_GREY); + m_CanevasKeyPressed_Right10->drawTextCenteredInRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-hauteurRetourZoom, keyString, COLOR_BLACK, true, true, 38); + + } + + void Keyboard2::drawZoomKeyCenter9 (uint16_t x, uint16_t y,uint16_t keyWidth , char key) + { + + // Create Box for the current pressed key + m_boxdKeyPressed_Center9->enable(); + m_boxdKeyPressed_Center9->setX(x); + m_boxdKeyPressed_Center9->setY(y); + + auto keyString = std::string(1, key); + m_CanevasKeyPressed_Center9->fillRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-25, COLOR_LIGHT_GREY); + m_CanevasKeyPressed_Center9->drawTextCenteredInRect(3,3,keyWidth*keyZoomRatio-7, boxHeight*keyZoomRatio-25, keyString, COLOR_BLACK, true, true, 38); + + } + void Keyboard2::zoomKeyUpdate() { + + int16_t rawTouchX, rawTouchY; + graphics::getTouchPos(&rawTouchX, &rawTouchY); + + const bool wasZoomActive = isZoomdActive(); + + char pressedKey = KEY_NULL; + + // Check if finger is on screen and on a key + if (rawTouchX != -1 && rawTouchY != -1) { + //pressedKey = getKey(rawTouchX, rawTouchY); + + Keyboard2::Coord pressedKeyCoord = getRowColumn(rawTouchX, rawTouchY); + + if (pressedKeyCoord.row == -1 && pressedKeyCoord.column == -1) { + //repressedKeyCoordturn KEY_NULL; + return; + } + + oldCoord.row = pressedKeyCoord.row; + oldCoord.column = pressedKeyCoord.column; + + pressedKey= getLayoutCharMap()[pressedKeyCoord.row][pressedKeyCoord.column]; + + if (m_zoomKeyTicks < UINT8_MAX) { + m_zoomKeyTicks++; + } + + if (isZoomdActive()) { + if (m_zoomKeyTicks == 10) { + enableKeyZoom(pressedKeyCoord.row, pressedKeyCoord.column, pressedKey); + localGraphicalUpdate(); + } + } + } else { + m_zoomKeyTicks = 0; + + if (wasZoomActive) { + // Do once + // m_trackpadFilter->disable(); + disableKeyZoom(oldCoord.row , oldCoord.column); + localGraphicalUpdate(); + } + } + } + + + bool Keyboard2::isZoomdActive() const { + return m_zoomKeyTicks >= 10; + } + + + void Keyboard2::enableKeyZoom(uint16_t row, uint16_t column, char pressedKey) + { + + if (row >=0 and row <2) { + int count = 10; + const float keyWidth = (m_width - (count-1)) / static_cast<float>(count)-1; + int x = (keyWidth+1) * column + offsetBord +1; + int y = m_height - hauteurKeyboard -offsetBord - boxHeight*keyZoomRatio + row * boxHeight +1+5; + + if (column ==0 ){ + drawZoomKeyLeft10(x-1, y, keyWidth, pressedKey); + } else if (column <9) { + drawZoomKeyCenter10(x-(keyWidth*keyZoomRatio - keyWidth)/2, y, keyWidth, pressedKey); + } else if (column ==9) { + drawZoomKeyRight10(x-(keyWidth*keyZoomRatio - keyWidth)+1, y, keyWidth, pressedKey); + } + } + else if (row ==2 && column >0 && column<8) + { + int count = 9; + const float keyWidth = (m_width - (count-1)) / static_cast<float>(count)-1; + int x = (keyWidth+1) * column + offsetBord +1; + int y = m_height - hauteurKeyboard -offsetBord - boxHeight*keyZoomRatio + row * boxHeight +1+5; + drawZoomKeyCenter9(x-(keyWidth*keyZoomRatio - keyWidth)/2, y, keyWidth, pressedKey); + } + } + + void Keyboard2::disableKeyZoom(uint16_t row, uint16_t column) + { + if (row >=0 and row <2) { + if (column ==0 ){ + m_boxdKeyPressed_Left10->disable(); + } + else if (column<9) + { + m_boxdKeyPressed_Center10->disable(); + } + else if (column==9) + { + m_boxdKeyPressed_Right10->disable(); + } + } + else if (row == 2){ + if (column == 0 || column == 8) return; + { + m_boxdKeyPressed_Center9->disable(); + } + } + } + + + + + +} // gui::elements + + diff --git a/lib/gui/src/elements/Keyboard2.hpp b/lib/gui/src/elements/Keyboard2.hpp new file mode 100644 index 00000000..1cfa5ab0 --- /dev/null +++ b/lib/gui/src/elements/Keyboard2.hpp @@ -0,0 +1,150 @@ +// +// Created by Charles on 13/03/2024. +// + +#ifndef KEYBOARD2_HPP +#define KEYBOARD2_HPP + +#include "../ElementBase.hpp" +#include "Box.hpp" +#include "Canvas.hpp" +#include "Filter.hpp" +#include "Image.hpp" +#include "Label.hpp" + +namespace gui::elements { + class Keyboard2 final : public ElementBase { + public: + + struct Coord { + int16_t row; + int16_t column; + }; + + explicit Keyboard2(const std::string &defaultText = ""); + + ~Keyboard2() override; + + void render() override; + + void widgetUpdate() override; + + /** + * Returns the content of the Keyboard2's input AND CLEARS IT. + * @return the content of the Keyboard2's input + */ + std::string getText(); + + /** + * @deprecated Please use "hasExitKeyBeenPressed()" + */ + [[nodiscard]] bool quitting() const { return m_exit; } + + [[nodiscard]] bool hasExitKeyBeenPressed() const; + + void setPlaceholder(const std::string &placeholder); + + private: + std::string m_buffer; + std::string m_placeholder; + std::string m_defaultText; + + Label *m_label; + + bool m_exit = false; + + uint8_t m_currentLayout; + + char **m_layoutLowercase; + char **m_layoutUppercase; + char **m_layoutNumbers; + + uint8_t m_caps; + + Canvas *m_keysCanvas; + + Image *m_capsIcon0; + Image *m_capsIcon1; + Image *m_capsIcon2; + Image *m_backspaceIcon; + Image *m_layoutIcon0; + Image *m_layoutIcon1; + Image *m_exitIcon; + Image *m_confirmIcon; + Image* m_trackpadActiveIcon; + + Box *m_capsBox; + Box *m_layoutBox; + Box *m_backspaceBox; + Box *m_exitBox; + Box *m_confirmBox; + Box* m_trackpadActiveBox; + + Box* m_boxdKeyPressed_Left10; + Canvas *m_CanevasKeyPressed_Left10; + Box* m_boxdKeyPressed_Center10; + Canvas *m_CanevasKeyPressed_Center10; + Box* m_boxdKeyPressed_Right10; + Canvas *m_CanevasKeyPressed_Right10; + Box* m_boxdKeyPressed_Center9; + Canvas *m_CanevasKeyPressed_Center9; + + uint8_t m_trackpadTicks; + int32_t m_trackpadLastDeltaX; + + int32_t boxHeight; + int32_t hauteurKeyboard; + int32_t offsetBord; + float keyZoomRatio; + uint8_t hauteurRetourZoom; + + + uint8_t m_zoomKeyTicks; + Keyboard2::Coord oldCoord; + void drawZoomKeyLeft10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key); + void drawZoomKeyCenter10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key); + void drawZoomKeyRight10 (uint16_t x, uint16_t y,uint16_t keyWidth , char key); + void drawZoomKeyCenter9 (uint16_t x, uint16_t y,uint16_t keyWidth , char key); + Keyboard2::Coord getRowColumn(const int16_t x, const int16_t y) const; + void zoomKeyUpdate(); + bool isZoomdActive() const; + void enableKeyZoom(uint16_t row, uint16_t column, char pressedKey); + void disableKeyZoom(uint16_t row, uint16_t column); + + void drawKeys() const; + + void drawKeyRow(int16_t y, const char *keys) const; + + void drawKey(int16_t x, int16_t y, uint16_t w, char key) const; + + void drawLastRow(const int16_t y) const; + + [[nodiscard]] char getKey(int16_t x, int16_t y) const; + + [[nodiscard]] uint8_t getKeyCol(const int16_t x, const uint8_t keyCount) const; + + + void processKey(char key); + + void drawInputBox() const; + + void updateCapsIcon() const; + + void updateLayoutIcon() const; + + [[nodiscard]] char **getLayoutCharMap() const; + + void trackpadUpdate(); + + [[nodiscard]] bool isPointInTrackpad(int16_t x, int16_t y) const; + + [[nodiscard]] bool isTrackpadActive() const; + + void addChar(char value); + + void removeChar(); + + }; +} // gui::elements + +#endif //Keyboard2_HPP diff --git a/lib/gui/src/gui.hpp b/lib/gui/src/gui.hpp index a7c1c8a1..21c829d5 100644 --- a/lib/gui/src/gui.hpp +++ b/lib/gui/src/gui.hpp @@ -16,6 +16,7 @@ #include "elements/Button.hpp" #include "elements/Radio.hpp" #include "elements/Keyboard.hpp" +#include "elements/Keyboard2.hpp" #include "GuiManager.hpp" diff --git a/lib/lua/src/lua_file.cpp b/lib/lua/src/lua_file.cpp index e3617563..f97c9abd 100755 --- a/lib/lua/src/lua_file.cpp +++ b/lib/lua/src/lua_file.cpp @@ -381,6 +381,7 @@ void LuaFile::load() "setWindow", &LuaGui::setMainWindow, "getWindow", &LuaGui::getMainWindow, "keyboard", &LuaGui::keyboard, + "keyboard2", &LuaGui::keyboard2, "showInfoMessage", &LuaGui::showInfoMessage, "showWarningMessage", &LuaGui::showWarningMessage, "showErrorMessage", &LuaGui::showErrorMessage diff --git a/lib/lua/src/lua_gui.cpp b/lib/lua/src/lua_gui.cpp index bfe6d6ee..07497a2a 100644 --- a/lib/lua/src/lua_gui.cpp +++ b/lib/lua/src/lua_gui.cpp @@ -29,6 +29,9 @@ LuaGui::~LuaGui() } } + + + LuaBox* LuaGui::box(LuaWidget* parent, int x, int y, int width, int height) { LuaBox* w = new LuaBox(parent, x, y, width, height); @@ -176,6 +179,32 @@ std::string LuaGui::keyboard(const std::string& placeholder, const std::string& return o; } + +std::string LuaGui::keyboard2(const std::string& placeholder, const std::string& defaultText, bool rotate) +{ + if (rotate) { + graphics::setScreenOrientation(graphics::LANDSCAPE); + } + + auto key = new Keyboard2(defaultText); + key->setPlaceholder(placeholder); + + while (!hardware::getHomeButton() && !key->quitting()) + { + eventHandlerApp.update(); + key->updateAll(); + } + + if (rotate) { + graphics::setScreenOrientation(graphics::PORTRAIT); + } + + + std::string o = key->getText(); + + delete key; + return o; +} void LuaGui::setMainWindow(LuaWindow* window) { this->mainWindow = window; AppManager::askGui(this->lua); diff --git a/lib/lua/src/lua_gui.hpp b/lib/lua/src/lua_gui.hpp index db371ee2..dbdc5375 100644 --- a/lib/lua/src/lua_gui.hpp +++ b/lib/lua/src/lua_gui.hpp @@ -35,6 +35,7 @@ class LuaGui LuaWindow* window(); std::string keyboard(const std::string& placeholder, const std::string& defaultText); + std::string keyboard2(const std::string& placeholder, const std::string& defaultText, bool rotate = true); void del(LuaWidget* widget); diff --git a/storage/system/keyboard2/backspace_icon.png b/storage/system/keyboard2/backspace_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..278085518b26105f6270c9c960980448262adb19 GIT binary patch literal 592 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEoCO|{#S9F3${@^GvDChdfq{w1 z)5S3)qV?_djjL}tFdY9F|3zwcMx}_0j8|tVuM$`31wP%T3rg#n{Fbh^D6d+7;pEwa z^^RHXuMVGF$sze>$>s--QkHm!Eb3Ibelkx#X<fh79q~Lb3%i}W9h3sR3eU3sGk*{x zb3%%J)3L@ig$mhVX4zMVN2P@}a*OZ3cb=A-viaun&p-eCF0iP{m0*+VJ+|3t;fJiv zH(#87Dzq$9NnppDO5M{=R&(9-rhjH<VerySi4+T8eRX@;?$~RkvJVR+x)%LWX?eqY z_(0xvX2ta7pQb)vb1*?*l8WQ?uXW2WSFV3;#jqf5y|P^YeLuCyy$T!?R5<JGYGjXF z?tV4zz}vFw-Er&fOLyNDpO(tV;1bB9$TDl$UjyG_eU3v%Hw16XRi5a<aNsn1{-P;% z7N36Fuzpyv_-0O!e)IER^R|64wBF7<FFIyz*!#52H}7Vc9Qs(n!qDQRIK^w}{Y4si zGRG^0I9O`t+A|pV3eWU8W*;EXqQ5rm^uj6oE}Ohvn<%j%S9;Z|e_l(2<k_1K&Jth> z6scwO*IyVuFZ#_cJ)P6Ps)~z)S6$8eelbI2O3;_8z5EkBp7<^eax|KGq;7xvV+(Qq z>!lBOt*d{q^6<lgo})=ui+0+mw7lp(>NMYP`TWq(+BhAtg&L>sD}Puo{G;DG88a#l Z*jIj0zGIhZ-3m-144$rjF6*2UngEaK2h;!n literal 0 HcmV?d00001 diff --git a/storage/system/keyboard2/caps_icon_0.png b/storage/system/keyboard2/caps_icon_0.png new file mode 100644 index 0000000000000000000000000000000000000000..47c2be866890f46e5a987f6d8dd1a46593222ee8 GIT binary patch literal 630 zcmV-+0*U>JP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm001r{ z001r{0eGc9b^rhZC`m*?R9J=Wm%WSHU>wK4kHlz^fP$FCPA-`Qai{@7S|~!Nw1ayF zap*3HLhlfq{VPOT7Z1<D^@Oe&93+b`oN$GMQ;`H;;?v=J_9zDj{-8SK0}q5>UcMjl zyyOYvoa3DFoLb;DTtO<XAeFNh6eu@WDir{L$KwI#{9CixypUxX<#PE#lB7$=aR30B zOy=keMp*|9!vFyIe7;JtSgdwB9RPr?>$j0e<gIPnV2q(&uOFR3dV|$!6@I_pyI3qf z^m@HRz0qhy^ZER>EX$uQ%i2&fNMkS_kNbnc;E#U4|9-pO9_s7$8m(6AQz#Vro=hhF zlnijrk8ZlIUxmYA4&cQm%QCOkYFCsDlAs_6cK|qJjQf1PgP16ahhtS$?<g6hF5c~S zh{a+kl}gvyZ1(=Cp3mn|C=?I~1h7~vC=ujIa+^pbzOGiQ8`Cs@0tf?uqA2(2boz^? zX_w>i_}$3_HBI|C7z`fT?KT|8@jlfp%d!o_xJji_S~MDcL&+d@@q9ji7!HRJ1OXn; z-$yaVz!<}5G+Hi~%U>rG>~^~_O%tLh;@<^d5CqI-GfbybN(4=CGMPXW#TU>0ndPu7 zixNQ-^m@IoUh}-`kKychGp-;NSCEP;NW~ST;tEnB?FUz@6@bU@?ek5+X0yS1y~b|0 zquGHdn9Jn=JPO*j4MkDFIftsMkR%EF{hlmH`f>jsoc$Pd1*y1#RL)-THz-AU-q>wC Q1poj507*qoM6N<$g3B`-&j0`b literal 0 HcmV?d00001 diff --git a/storage/system/keyboard2/caps_icon_1.png b/storage/system/keyboard2/caps_icon_1.png new file mode 100644 index 0000000000000000000000000000000000000000..fe83bc825ae121cd2c6dff5368a73436237e1dac GIT binary patch literal 674 zcmV;T0$u%yP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm001r{ z001r{0eGc9b^rhZR7pfZR9J=Wm%WP`Q540`lW{bNpde0T(%4uDq7a1z$wClPO;T%N zAr|QcQOGWWwf}%13X3E*F0O^`3Ta%hun-$RSYZPTt0E&t<)u-xgbf<6L<<i*81B5e z=g0e+`xxgO$1K&M0XFFbNYx3Ds-p)KC?Ch;aR7iyr2^;tOFo~!kR%DQSnNWt*IzCc z3jl!E>)qLdQO?17y$%4-Xf*LiB$6nVN&tXhFnDh^n_o{R6EMb*N~L!8AdO%mk$_gK zRS$>5^Gc<%j$d6}Swf-EjU-7Q6-D_;@gS{1yWOre7!2R4)#|(1Y_^V1r&AOPg%3uf z@vGD6)KWaaIp4VjgTZT)$;1J?*d$5f$z<}H;z0rw1mOVyXN+-;MzaPJMREP?@pv96 z9;7Lr&*!jOt%ydWH$I>5aTO1RLI{V$(CKs-4u=#A@+P@=I2@nH<MC~))%p&=1OPUh z?eXmF?2|0Zmz_@M?ZE(LS$^MWG@gpZA{L8<dKFg`Wm2!#Z{2RUY_V8gQ9MXfJQxg~ zn$0EzL4Zp2I~8LLj4`y^?a^p7`f)J8a=DCFs|8UM@#ldr2m<>3K6<?##exRd?RFuG z;*0N=yBvz5P%LPGYPEV}pXXD*i;ljUIRR320;KBb0ZG5QmD1@n0KCcNa<yg1<@fuM z$z;g6_X7A#u07}5{!X$S9p|2W?*O<0fxzaT+Z2u2Y_^8KRL#4#Y&KilXTiF!k^ASI z+XCJZKu9^a-6XE%H1Bl{Zqt!;asMAW`h)reNYx3Ds-p+|1!eKYRqC7;Z2$lO07*qo IM6N<$g72m=+5i9m literal 0 HcmV?d00001 diff --git a/storage/system/keyboard2/caps_icon_2.png b/storage/system/keyboard2/caps_icon_2.png new file mode 100644 index 0000000000000000000000000000000000000000..62d34e38ba7e48cbd9f6d138a5778fc3e5d5c89b GIT binary patch literal 767 zcmV<b0s#GqP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm001r{ z001r{0eGc9b^rhZu}MThR9J=Wm%nQwK@`WoBkM1MpdfDJU1O6fAPT3DUAcopxN7g} zSXfAk>&2jO2}08P52V>Z2ss;ru}GN}j=%;iQb;NT5mE#aMOM5hbH%yhfzj15i5z}m zz@2&X-iLYnoVSEhiba;`tpO%!3COA?AgdN0kYm}L$z%WkCX)%2(jP}hN83ElBb`of zI~<OkUatoLh(sbY#~>{KgOy4J0ARIRGs$E!TPzj<0P%SI*5mQKYq#4Vgdms8%^ZX2 z1hd&JY&M&@(P(@+J3AZ9A08fh6N$tr&+}h3P5aFfgXtYyTU)a^oz9=-a{1%a)6-zS z)9E0e&wp{bT*rYxz{U~-l+u|;JRU!ByWJGP$ieeG-QC?iVTr*6$Z^~q07?j<R;zUY zX0ccXzr*419ZL+R6nDE__<TNWZEc-KqtSbPK9NXZb8{0bD=TO;8Z050i{#et_kVA- zTFUkH^)CQ!09ajJy<cBn|0YS&POVn^@MeILBz?ZRx_T%S3h4EEW_@1Mw05OZQ9_}R z<n?;(ZwC1I`1nw*R>5%`hO3wm0zwEbE-soLkEhveHjzrD)S<1x^YinU2P~CJsMTt) z+wIUa?O(^-U)S||9eaCws-h?XeN7MqRTM=-kW7F#H#e|YEF;(S8%maCRZ*0HAPATG zTL0M)BvTce&F0BQjAA;$aoX6}fGCQC)DEXue-;Em1rQwP=T+OSSsIg9?+2%ae6bXd z5+P*jJ^yz{Jx-!10zj}|2+wJ3fdF#?+~3~^fcFOn2Rh7f;E539H18A#`vXR92_rU! zze)P16PRddOqT$Hu~=-frIDslmSq*sbj`C4S(ep#HmvhHxv6~`1-zVWGPMl(G+M>M xewyd{4jM6J`fz^@E&NTg1Z33`kW~v0_y<Qq^+!N=1U3Kw002ovPDHLkV1k;@Qyu^S literal 0 HcmV?d00001 diff --git a/storage/system/keyboard2/confirm_icon.png b/storage/system/keyboard2/confirm_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bcb4b804c9579c4131eb993188d5e9732cc259fa GIT binary patch literal 877 zcmV-z1CsoSP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm001r{ z001r{0eGc9b^rhaA4x<(R9J=W*gr@cVHgJRC&!6M!JsICIAv-q6pKOxV_aHlU5up7 z(k|K|h;wi-iY}HGI(2Cwnx=)e1k!(lRdAA+NQYvSu9`&&f#70PNQS3F`hAdk)%>}5 zg1&H&+;LBSdGEXAO-v+lnM*Mma9&*lYpp8@d<Gx};3t5WHK&o(bBpkF{ir2VPuvrd z%x1H6xm@h+?PV&J63Fmn0KOr~@$qp2AOH>x4e{vcNFX0pldI<%BmkI9Cb?sIc^QE~ zKs@~j;AZ8i`gQQJxWqj@J+h06qHtkhL3A-`<Ru3G-XzInlI`v764}<)#&|p~kWnLn zAQ>mgNF>6hrY4E(>gr-9lM%>}kw7cSEJ+3e0SN>^kH^E4lM{iwYZMS9ACP1&m*ep8 za0zm5ZcYF*BrQe(LGm3*rqgNK?RE)NRh7|bR3KwU0zvW%Np5Ux&}=qKWJgB_x3{+i z^3z!vCQ@@?^#gDLuvPrIrCqld7Z))xF@bzO4*+mD99UUdK}$;u0DJ}D(L7T_?Pr~8 zYHF%vJq`>EFr7||!%xfYU<^S2$jAtGcXxGaAfPA;a=9FKc6LhkkByBX6bb>rX8@1N z=^$BDU&v;$Sj0<av^uD2yxDaC{nOLaNTpI$ckJI%6a@zd2UuNQmFo}yCMPGw!<goY z8tTD%t-<;Ec{VmS%I=Mhj<QfFh{KL@*B}54LchEC7Jxh9a2P(H4~0Sj0N`{wv9z=V zv)K#)K>)sTJE-UOjU*F^1e=?iW#_C`D>pYcMdv=8l~GUJdy?GW-)CoMr^GchG%ym8 zzYG%R<<tvzpCk_t59xNhOYYj)*;#?hvN%{=I8aVAGcz+KIIq{sd_FIL_sYqu2T;y~ zs;Wv{cXv1U_VxrWSZ<!)xaVYXqPAEp64%<=%C)sMf%{%bW?j1HbUI5eZ7>)VxZfld zBY_E$?Ca~3IKN-c9(j`XN;CBaz97l1tu5MYHhR5Y9v>eIpu3t(y@4RP&eQd_+PwdL z)zwlr0K5j!58xMyL%^$Q!|DOlwXWp<gSyr=u-5tm&-&O*C|AgS00000NkvXXu0mjf Dr^<ot literal 0 HcmV?d00001 diff --git a/storage/system/keyboard2/exit_icon.png b/storage/system/keyboard2/exit_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..283094d57e9cefc19ffa78f92896ff940898143d GIT binary patch literal 1470 zcmV;v1ws0WP)<h;3K|Lk000e1NJLTq002+`001Zm1^@s6X<&T;00009a7bBm001r{ z001r{0eGc9b^rhca7jc#RA_<ina^t!XBfvnnvzNaLgT>%DTtNXV55RUS_od&ZV$yC zdI(M}g0~hH{0|1b^w2{fl!%x0U_lb61fnhJs=-Uxprt`Z!9sBMCb||(kqL+xo*ri2 z@txV3{o#aeE%Sw!oqeBY-uL@_-*?{knRm8{2sz#!+j~vmT}LipM&tr!L@r=P<N{_y zE?`FF0%k-mU`F&xzyaVgPzTn5>%g8Kamj>jJ$e(F1<Y98@4zQL;F1Zwn1LgJxv{aq z@#DuS6bjVqb%1eTq6d63p%(%k18^LN+qZACwzkIV>T1OHF5$g4_5;8qeqhV^Yt}Jf zAFvwK{i^v-1oorA2l(sTGOz?Z41D$hJbwH*t<N36%UGMA@kZRFHWf~2{FZ?qWA<}e zEI$YLcN=3AB9d0dMC7%!$E=7P5RvOGd|r#lbkOEsA|lmlRR95`QmN>^Yk}XGh%9%| z_dvk+M2cO-b2ougH!-SyBBk&A`SWSo&I5aI+_=H?^faTRqxARpGcz;8l`B_x^5hAH zLV^DN{xRS?V02?+gKO8WarNp|=I7_RbLS4PUcF-f{{7p5Pk}?g=*r3p_wL=}=FOV` zc%H|=zyO<@o9y1bdspE1J+SxLvu7+WE^_hWMHUwq!!}1oMpWM=;5Yn@Y1gGomsnU> zV0?UB*;j$Dfp6;dI+kV8*Vm^w9qJ;+4}pblW}t{jI7=+cl5)8m{s*L3EQUi=tyaY_ zjEG$o(=?^gXh^)xq@qKgrSVcM7R7a4<$6~{#BrRYS^a~EEQv^jzvp>PeA>iVPtvJl z0h5Yh7$PF#x^AR?YHCVs+m4ViO*152sZ_)?%}6`ta#?KK4uh)IYE6NZ%jL)*8HS;Y z7!j~sF01OLBmo`A>1aSzj3Tn0SwJO%=Xp}CRznh&WraSv2(4@>!G<Uni;)3Q@H|hZ zrlu0_-3kHIVibRk&n954R%;5>^Sq?d3ejjZx(zlm`}Ac(**(vT%tW<3Y=wYHF^a#j z?Mc$9t32@V;lt|kW8hl=*L6etkt0XAfB$}@Jbn5!v|qSzp`(8E6z9~bQ|j_3{B-7* z!NEaJo;(@)JbLt~n=o1;A;!<~H=D$~t6d%#!QkMax_n5&yX)NC9CLGXsrMI)#csL- zVCT-A>hjOvcLn(J;K75TPm7$gYs6xV=b26DO2Bq741-dslxQ0o8sf~EGh5NkFu;o! zFSeqs%*Y~O9bkBPIIJj@O3cj6WaXsKIvzZDz~tm4z*qP=-4_5$OG}|op-^bm-21>7 zz^z-iGIMJ}H=BqC<x>}l?wESMr%<ca#4wD=ZrW-W);A^~lB&e-H4Gz6kMw$CxnA6s zwuvOf*s^35@UloW;WbS&B<Fda*tQ)>RMSML)oN0$R>NJeQmI7jDy4`g?D}h9TzJc} z67Tsh33xz)cS$`rODeIXcU?qM-&~X!da|8V^yFNE_vSPn>IwKa1zZ++lRIgT*>cS9 zv@+PXohXWBS^A@WSAv6wq?w`5QZ<9)K89h4ZQHtdvx<l3d6DE@3GKRWm|yCTeTOl= zm4N3|Yx-yf^>N?Rx`XSw;y8{tjuRm&B31Dd(s1T_o)`MY*3Vh}kMfCeQGSX?cu%9z z5XW(v)=$@U^?t$=qz+>2T0kY@TF~fPn}#O>LhJDe#UIhLG5@q9Fx@w;&Gn#uB7w(Q zX+8$~L;T}3{YXm<W;Zc5l}^5i?BLB|<I6U_3P*vV;CdB!-oke%@CQFNaua+M2Zc_! ze1v}}`aIyEbNf5i&)dWZ^zNh5{|5PY;f%-y%!pjTjK~Gdh+M#o$OX)ZT)>RT1<Z(l Y0FDWwU}1ymB>(^b07*qoM6N<$g6)joHUIzs literal 0 HcmV?d00001 diff --git a/storage/system/keyboard2/layout_icon_0.png b/storage/system/keyboard2/layout_icon_0.png new file mode 100644 index 0000000000000000000000000000000000000000..034cc5fcd5d8217fbd1708623a37a1ecbf7b5df7 GIT binary patch literal 3149 zcmbVO3piA1A3r0vP!vh1#u##+3xgSkE-F(Av1mTkj+ujDZk;ojCe^f-K1;QY&_)}Y ztuO0RLRuBOx``B_kV`BPa*2py&q$u#@7wR&=iBo<?|I+%yubJNzyF^T@3nL55;c7_ z005TI+}(B|vzdITDkJa2nG!BCEf%=%h5^9FSUymqA6z2=K=BRRH$WKRv4g_ob8Q$b zeh_FQ;tCKn064pf1Po?4C`1Q=A#5HMGgMlJL9<y@j6cZ(?;+R(hO*to5a=V`>B|&{ zGs!HBs|(s$L_r9+ppbzUaXCDgBBEmEcqzzQ{uzfs&q0LYRLlmsKy-kI7kU#P0?}j} zf;AJ5C!igWm7P7&kxaHi6Y)e_9Nr#BBv}*j6g+`KBBAFW3?dF<1ygppZJ8H_?5LPf zp-@1<;i96VY@%#!_)rLrKqixMcp{ESv_=rt@ByBXA+qMd#-AD7K$r=!1wuBThn6!k zg7^_aDh5&YlMP(K0xb`o_Y>kVoQNU75p3{so92Kl<^oO-0deMpvzR!L19Cy05Js?s z1*{;HFXY3a{Qp9|aQp`Wh;KbS7G(UXE?n+{2w1o|5;0@mA%BX7eGdpg+%6F2M?g$) zb0ngsvD_K~WfKH4gnY=C&*yxOl-FmK(L|DsE!xbV&13PSVDsNy0NofukcvT~W@n8@ zLT2wvut!2hA=p~ti4;8k6V!vxVh11i4=9l+hm!sXMRJD45HkJ}%wkf4`4E?Z7|iA} zLO`5=7lJ`AxRJ7n&*4LeU_?9HIW0UqC^Q}{Wbl|E&5epdY_?&uSroFpor66o*xowG z&cV*w7H{WZ?PyCPSQAMk7P2AOIR-g=zVF6oM#v-k`9ACayzdFIk<wyt{x*-i;N&Sm zac9Fwunx>ugb%oXe#K#<=dyspV9K+biebvb3bHWspV@!g1D|N4LP3P|e}wxJ4CV(5 zqZkmlAq4T(U#1fdQ649+!%ueL{@uj6v)|S1XE@Rb<jaK?glra?7|2697lgE^qYk6F z0HC5obKBq>5IcBg&ko;~759&X#O0&Zzgl+x6x+hcI}=;~V{$f0bk|ZhO@FyIshH4s zR`u$sX#ta0r_a|Xjb|QbGqZDP+C^hWTVz|-Sgn3?&|rnu>mTT(jB=S^vkU8tW*lR3 zg3*({6fRo(GSlUXlu8a6Dtb3FR5TMl6mjp{J1thlvksD3tUB<@^7q4>He?`Ky?)uS ze};C+l4{dF5NHQ1B+liFUZ7l5+EBNb>{#^psH?)!BQcC+S5^t`a$S_Ba=dB5)0wgn zcWhQ>rqO21GTP{N%Grz<>@k@p)<Y>~!|}vKGn=v$A-zuIXxLa?o!B(%L?hGSGu*4P zecK97o3y4DHq{eWTz3~!D3t8%Yzq(sFaPutoylZM$9C)r`$e{sHmj$n_vFNCCtokG zjJP;un*M1!M?5|Q0pAF;DJm>HlW^Oz(p@3dq|aYk-`IHZoKw{6`pZ6Q$}!Th%d#)x z0Z;e3%A|G4DJiDwCC+P3X4U?y(_p>Sqt2cd#^Dr>omlJ2<IesPs}4CDDhT`POrFkU z$WAK?_MJEwc<$Ue`Ymx0utG<tcWS&}`fHM}ab;)5610{oo=WA$whv9LgNhUbly0tE zdaSQMq4rKU<n8UvXc9(7E?0}qA*4N0ezLS0;B};xPuGTyooj6L3kwfFFg3;|;zCdr zfoB}QJCtV6eRw-^P(LOnhLF44(&4ryM=@P;@#4ka-d^C#N~uW>y+}=R>eRBhxHur- z24up!-cmTbMoS?~l0Oyg($#r4A>HNB*^!Zv8xLlRE>f3epq^*dn#GSZu*(VU6Ry#d z-&*?TX{joz#%>fjuTigm|Mt~>N5jMuC+Zp+R-`?_hjKVrW8;{ttSn89ijI-4`*tMK z{+{YpTefVu(!{aad-IHc{$7;U(qoGi6||g83?+Ae=F{{?Ma~vhR)r-E&COx^`+I9I z_|4ANEnQ8)mbK@%we9Wh>7jpo|Neb;etzoxuJ0}!=_p6RmFKaL0MIkDuz-4Ay?Q&) zWD7trY|Veua{c7XmkdBG7K?^EQ0C_5IxAQD(COP84KJ3Krmge*9=O75rKIm%mz<m| zyL2fjHFax51c^$e>gei11J4N$tE#MR%1rMRyJ@Dl|McwHvrD6+P`JayP`g7E?6XS{ z7G^;qlP^zAiBZsvKty$^tg@2U(9p2hi^t33y(lrF)rxf6Q|wl0D35pERkytsVp7>Z zUNh41J@sHU>9L7eprcn)Rb}ktWFT2$V1Gr}w@Y$3L)XmH({uI-K9PiE3cv~uE;#&A zoZzaht(`LQO+o@{hIg$g4^;;EIT@Z%J67SX7_IzbQL{#cC`rX9XKj%GDV(isQevV; z_(;hJ+~H7edj4_9S_6Zw#@v4Z&j%xQt?6#q<u7Y5Y<+P9R*|Hq8*=Ooq}wzqCRGC# zMXP=|jiu4PJJ?cFU0uESDw(o)ta&ifFDC#cX&JotQUL4#k{>;K^bUSiLm(1^JbK2( zm-F(1#p1KIwcZJ(6K`6(I)0APi~IRy#j!yWiKJ5Z^yx8)54N>x1Rjk5e6&#;2k@(@ z(60}q-BqdA4oyee(h5*?I(=B=9IvgVq09~o+ZL&|H-BaRGxha!x_+7i|K4C^nfeE- zRT-_k^Gt(yx9a<3Bjri$;pu{cg64t(;<X{8VU>)MygZw#!ASVs!0xH(>B<KWGKz~+ z5bHi1c108xMnrgfd6mCuEv<a~`2MT6-n)0lKkZYTR2)viRvI1l(KV2^rRp4dKl+2d zzJ7gM8_y5xkNs$N*wunWYIx}Db8~OLg@uJ;XiG6yf6bZ{nK{jf)-^&7oC+ctm$kdD zOR%)CsAeBY3$TjzsH>QnIXu`}>MwyHNI3rbi)#bfr|h1$w&oTV+O3Mq+*2C48)#{6 z&QS^r3#)!}(uA8@xcBPA?uc$bJ3WmWR0&w6`*bE7`(xJ3@{WQ2{tLHmt(L^cFMiW@ zYdc;~F+fFjcEYNB=Hqnkw`1?#(Lct<#`Z9`rrQtRyz%96Q&`Yc0QPhVgZ`<G-J_`- zL)qW?b^6Xr+qQ3yc-!LvJG3X)&wh9h=k6)>3vbM+Eiadlbq9NUy=b)fVqR-D;zin2 zU|m#ON70=|M<=Hrt5R`Q-4MI$-tnGpylJ0GywR4c7Vr2{9aTl7q>~@Sa%iq8zpBS> zREypC&D;KT*-5Oq;nHvjBG%p;*#~_1M&|msrY0;pI?(03r}Qi7VH<Ow<#9bTr9~Pd zO*7M!{pV5Ffql^*`q!IWwS8^>L_vmX>149++y-Y9G;SN^R7#Zwuzod4orRNM>#ZvT qhI5my&s>919ns+Y=+0G{^fY~tv^H{pI3@q#r)}QpmbdZCuYLp5xD+1% literal 0 HcmV?d00001 diff --git a/storage/system/keyboard2/layout_icon_1.png b/storage/system/keyboard2/layout_icon_1.png new file mode 100644 index 0000000000000000000000000000000000000000..a3aefaf545fd9709008e2f73bf6d0d4b51e61270 GIT binary patch literal 1051 zcmV+$1mydPP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm001r{ z001r{0eGc9b^rha%}GQ-R9J=Wm$7RjM-;|?cceJZs;)2`*EwX2598(_jg@9e8rjzb z4z{rK4+ySKBT}eHwQvDLFsLyp3@ThG%@)@fSq>N5#fEEquufwa!jMa`f)s%-#qO*} zyDQm2fw<5IgXNj`X1<y4&6~FmByped@c$-o8|DOO#hl=*m=l~8_nzP<6Z)S5UjR!$ z9~exqdjh<u=>G#ayJc;64Kn*a@Yk4?q+(l@bggmh7i^wM>S;PIB<)FhT=0FI^%vKW zqz{tbxb_bUPu(NnH{i45<72L_u4ptGEG#Sld;|QH+4X>zqtS>sj!Q>VtJPRqvIoPj zz}LVP@C-NrJ_oRC04y&rv$nQY_9^UcTauzE5+Fc95ZK-I9lMW`WQ@t}ip}#p#c^zX zdzs%mNs8lGp68W(eBXC{LP;fwdy*6c!I)!`B-ZJ<q$iS;B*{c_wi#nw-|sBBX&W=f zXgC~NpKX`iqe&+dhM{$Mo!LrhYzR=d+s%V0NfLFt-Kw#7lGJQA$HtN*Dfzgnxdb<h z@^(5M0cy2cMVTiOw6GGoV{sf$^>LN6aP#0RfRmFG09vgUD=RAiwA*b)qY*$IcwV{{ z6}Y^-EcKn8-DI9dqhWv6NiQH<TU+IcoD;mL+PRgxAoJ7{bmem5DVNvxecN^FtlyWU z!C;`lU{I2HU6O{wVQJ!4t5qfQ7{N)+*;L;p*lad!|67M(G5=mmTD20t0ysQ81i<q= z78e%*SYKbSlKD;;3<m$k=RNS&`TrN-qa|1eI5;=}U}Iw=x2o4~<~}+)s+>6p0-`9& zTc^{(7(=_=W_Ne@uKRfd_@mLtZt5lQBT94Io${I^^VAqD#-YuH_Lh2{XU#4giBBcT z_x-W_iL#&%!|+yu?qU-NeyfUf6-AMXYdDwZwdLU60sEpn1ipkcUI2XGACoJJBEm4d zRpt!e13v?tpP%QQwOS1r50{;t9sBc#tmS>i82gt0S$bEi<dSaEk1Mm?Z4d;Cq9||O zZa1H=AZMQZ?OfK!W(zxCh8{&ZoX7gBtnIlI8)HfYr!^<l>`7^?`@TQX-uHbsjJC1b z8)GH~@1`3cPLdrvjjDy5g!{MB%eZez77G%x{OFL|S60o0mVgtudm68D`cnFqx|igR zxK^5k?OgkIAW4#3V)w<7Qy|;wICKU>m8;-YWz~o?!KR#7r2?l)tK+AIxoq88<=a<U zmQ_~NpJso{CGrhk0Kb!dbNm-@ziBS2)-IO(_YU{|vvW>xR?G>`iaEhqF()`H{sAE; V$YbC5BF6v#002ovPDHLkV1np)^yB~l literal 0 HcmV?d00001 diff --git a/storage/system/keyboard2/trackpad_active_icon.png b/storage/system/keyboard2/trackpad_active_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..db876fbd32c5fc0939b6cca1a619c2856b720756 GIT binary patch literal 865 zcmV-n1D^beP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp) z=>Px&8%ab#RCr$Pn_*U?Fc8OQa4)d0isjSlNo-G|J&E=t>Pf_t$bO<y`}P8s*%xa2 zC=fCMN=OMGB@N7v`A;U35n<#Pj@*850GtPmoPd+S$Q{51K_>yO1mfiDfjid7IHU-^ ze?>v?JJNZ+(gWhp%_AZ_=}c;HY(zlIz`uOqzC$el%ZxwROh5}R1Sx<x{&#~H=?9nO zz{W+i_2wKo$N|{p`X&B^={&f)3RNFQ3jh&30n%U9q<!D_0PhIkC`fZ<AO-N5Y@SP# zGO6|rK&(&*_?&;P1HcS~&I4rb>Lk!(4A^NH?g?qxB%8B31{9MmZt%)`uGIim$%c+) zNa57Koa?M44uH+epz{DHfevE8dOh>VyU)js6w}vMdx5_4fG#AU6EKTojc0-!0B!Sx zIzWR5&_$kLH2{u>oV5fv0OIv}2B~)ksrSmM0_A}XUIHorC5dR(EUX8xN;aZyd9(kj z2=H?4PZnHRoC5&XULuo8#ks-R11N5kXzShP<HXqmC`v>Wc7yB5GAEg8wG1T_R0YAd z_s8G?wK2j0FkKXF>%wh+e^L(+OAiu0?jaLl2wwW0Uyf7;aMyF$IMw_o15g!2i?u%i zq<r+QUlXi@WCVcP__|lN96<Y?0^0%X`U>9i`MI8sEe9Zs{b{af2w}hg04PMjqb8&j z=)I~PMFAn}<pIJ!h%^I0v77tZ(G3JZ)oF{&m1W0SN(i|&7O`aRE4w<|S(UsRuL8Pm z+yw-cF-`6_29Rl4vrlMf5ULuziUkvOpJ0~Fd7}N~P<5$Y#U-5?I&x_8rK^5Zd1%Vr z4p&Ynsw#|2b|TX^gjMqO27pKJT<jiGdH};-ts#9ukjZ!IPmXNv9RMRwU^h9+H$det zFUA(DLE>*l05Bkk*Dd87Dpw-_;qJ0n6;1ugZE+4`0C*5oCiCyhI!BEH=nFz!+pKW_ z`)}B83oXr2L)u;}>W<3>10eH;Lj@_nH{iSZZsaa@v~G~leQej`vy&X1tHFPZ7+nQ) rY&+%HK}q10hRWu408CIH(lh@9kD>T(xa&(b00000NkvXXu0mjf4^M&% literal 0 HcmV?d00001 From 51dbdbd7736cdf2d9f3d55a15fd2541265dba147 Mon Sep 17 00:00:00 2001 From: pymuzard <pymuzard@gmail.com> Date: Sat, 21 Sep 2024 18:30:42 +0200 Subject: [PATCH 3/3] keyboard2 (horizontal ou vertical) --- lib/gui/src/elements/Keyboard2.cpp | 1 - lib/lua/src/lua_file.cpp | 34 ++++++++++++++++++++++++++++++ lib/lua/src/lua_gui.cpp | 8 ++++--- lib/lua/src/lua_gui.hpp | 2 +- storage/apps/alarme/app.lua | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/gui/src/elements/Keyboard2.cpp b/lib/gui/src/elements/Keyboard2.cpp index 171a6290..078543fd 100644 --- a/lib/gui/src/elements/Keyboard2.cpp +++ b/lib/gui/src/elements/Keyboard2.cpp @@ -428,7 +428,6 @@ namespace gui::elements { char Keyboard2::getKey(const int16_t x, const int16_t y) const { // Check if the position is in the Keyboard2 box - Keyboard2::Coord result; result = getRowColumn(x, y); diff --git a/lib/lua/src/lua_file.cpp b/lib/lua/src/lua_file.cpp index f97c9abd..1a382f93 100755 --- a/lib/lua/src/lua_file.cpp +++ b/lib/lua/src/lua_file.cpp @@ -1,3 +1,13 @@ +/** + * @file lua_file.cpp + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-09-19 + * + * @copyright Copyright (c) 2024 + * + */ #include "lua_file.hpp" #include <gui.hpp> @@ -10,6 +20,7 @@ #include <contacts.hpp> #include <libsystem.hpp> #include <standby.hpp> +#include <graphics.hpp> #include <fstream> #include <iostream> @@ -49,6 +60,12 @@ std::shared_ptr<LuaHttpClient> LuaNetwork::createHttpClient() return std::make_shared<LuaHttpClient>(lua); }*/ +/** + * @brief Construct a new Lua File:: Lua File object + * + * @param filename + * @param manifest + */ LuaFile::LuaFile(storage::Path filename, storage::Path manifest) :lua_gui(this), lua_storage(this), @@ -103,6 +120,12 @@ int sol_exception_handler(lua_State* L, sol::optional<const std::exception&> may return 0; } +/** + * @brief + * + * @param L + * @return int + */ int custom_panic_handler(lua_State* L) { std::shared_ptr<AppManager::App> app = AppManager::get(L); @@ -382,6 +405,14 @@ void LuaFile::load() "getWindow", &LuaGui::getMainWindow, "keyboard", &LuaGui::keyboard, "keyboard2", &LuaGui::keyboard2, +/* + "image", sol::overload( + [](LuaGui* gui, LuaWidget* parent, std::string path, int x, int y, int width, int height) -> LuaImage* { + return gui->image(parent, path, x, y, width, height, COLOR_WHITE); + }, + &LuaGui::image + ), + */ "showInfoMessage", &LuaGui::showInfoMessage, "showWarningMessage", &LuaGui::showWarningMessage, "showErrorMessage", &LuaGui::showErrorMessage @@ -503,6 +534,9 @@ void LuaFile::load() "setSpaceLine", &LuaHorizontalList::setSpaceLine, sol::base_classes, sol::bases<LuaWidget>()); + lua.set("LANDSCAPE",graphics::LANDSCAPE); + lua.set("PORTRAIT",graphics::PORTRAIT); + lua.set("SELECTION_UP", VerticalList::SelectionFocus::UP); lua.set("SELECTION_CENTER", VerticalList::SelectionFocus::CENTER); diff --git a/lib/lua/src/lua_gui.cpp b/lib/lua/src/lua_gui.cpp index 07497a2a..7d9cd556 100644 --- a/lib/lua/src/lua_gui.cpp +++ b/lib/lua/src/lua_gui.cpp @@ -180,9 +180,10 @@ std::string LuaGui::keyboard(const std::string& placeholder, const std::string& } -std::string LuaGui::keyboard2(const std::string& placeholder, const std::string& defaultText, bool rotate) +std::string LuaGui::keyboard2(const std::string& placeholder, const std::string& defaultText, const int orientation) { - if (rotate) { + // set keyboard to LANDSCAPE mode if set + if (orientation == graphics::LANDSCAPE) { graphics::setScreenOrientation(graphics::LANDSCAPE); } @@ -195,7 +196,8 @@ std::string LuaGui::keyboard2(const std::string& placeholder, const std::string& key->updateAll(); } - if (rotate) { + // set back to portrait when leaving keyboard + if (graphics::LANDSCAPE) { graphics::setScreenOrientation(graphics::PORTRAIT); } diff --git a/lib/lua/src/lua_gui.hpp b/lib/lua/src/lua_gui.hpp index dbdc5375..76e31a34 100644 --- a/lib/lua/src/lua_gui.hpp +++ b/lib/lua/src/lua_gui.hpp @@ -35,7 +35,7 @@ class LuaGui LuaWindow* window(); std::string keyboard(const std::string& placeholder, const std::string& defaultText); - std::string keyboard2(const std::string& placeholder, const std::string& defaultText, bool rotate = true); + std::string keyboard2(const std::string& placeholder, const std::string& defaultText, const int screenOrientation); void del(LuaWidget* widget); diff --git a/storage/apps/alarme/app.lua b/storage/apps/alarme/app.lua index a39aedc7..49ad85f7 100644 --- a/storage/apps/alarme/app.lua +++ b/storage/apps/alarme/app.lua @@ -172,7 +172,7 @@ end function changeName(label) - local keyboard = gui:keyboard("Placeholder", label:getText()) + local keyboard = gui:keyboard2("Placeholder", label:getText(), LANDSCAPE) label:setText(keyboard) end