Merge pull request #54 from badgeteam/update_gfx

Update graphics
This commit is contained in:
Renze Nicolai 2022-06-02 21:54:02 +02:00 committed by GitHub
commit 1412a86108
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 36 additions and 962 deletions

3
.gitmodules vendored
View file

@ -37,3 +37,6 @@
[submodule "components/pax-codecs"] [submodule "components/pax-codecs"]
path = components/pax-codecs path = components/pax-codecs
url = https://github.com/robotman2412/pax-codecs.git url = https://github.com/robotman2412/pax-codecs.git
[submodule "main/pax-keyboard"]
path = components/pax-keyboard
url = https://github.com/robotman2412/pax-keyboard

View file

@ -16,6 +16,7 @@ Source code included as submodules is licensed separately, please check the foll
| components/i2c-bno055 | MIT | Nicolai Electronics | | components/i2c-bno055 | MIT | Nicolai Electronics |
| components/mch2022-rp2040 | MIT | Renze Nicolai | | components/mch2022-rp2040 | MIT | Renze Nicolai |
| components/pax-graphics | MIT | Julian Scheffers | | components/pax-graphics | MIT | Julian Scheffers |
| components/pax-keyboard | MIT | Julian Scheffers |
| components/sdcard | MIT | Nicolai Electronics | | components/sdcard | MIT | Nicolai Electronics |
| components/spi-ice40 | MIT | Nicolai Electronics | | components/spi-ice40 | MIT | Nicolai Electronics |
| components/spi-ili9341 | MIT | Nicolai Electronics | | components/spi-ili9341 | MIT | Nicolai Electronics |

@ -1 +1 @@
Subproject commit 8e603e9ca73a282a80e45e74160ab6c7c7fa4fff Subproject commit 36049d7deb159c835eee6a5aa021b654bd3dd83b

@ -0,0 +1 @@
Subproject commit adad199c55e91f68d3e162b48f4e37816ef95c9a

View file

@ -4,7 +4,6 @@ idf_component_register(
"fpga_test.c" "fpga_test.c"
"graphics_wrapper.c" "graphics_wrapper.c"
"menu.c" "menu.c"
"pax_keyboard.c"
"rp2040_updater.c" "rp2040_updater.c"
"settings.c" "settings.c"
"system_wrapper.c" "system_wrapper.c"

View file

@ -9,6 +9,8 @@ extern const uint8_t mch2022_logo_png_start[] asm("_binary_mch2022_logo_png_star
extern const uint8_t mch2022_logo_png_end[] asm("_binary_mch2022_logo_png_end"); extern const uint8_t mch2022_logo_png_end[] asm("_binary_mch2022_logo_png_end");
void display_boot_screen(pax_buf_t* pax_buffer, ILI9341* ili9341, const char* text) { void display_boot_screen(pax_buf_t* pax_buffer, ILI9341* ili9341, const char* text) {
const pax_font_t *font = pax_get_font("saira regular");
pax_noclip(pax_buffer); pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xFFFFFF); pax_background(pax_buffer, 0xFFFFFF);
pax_buf_t logo; pax_buf_t logo;
@ -16,7 +18,7 @@ void display_boot_screen(pax_buf_t* pax_buffer, ILI9341* ili9341, const char* te
pax_draw_image(pax_buffer, &logo, (320 / 2) - (212 / 2), ((240 - 32 - 10) / 2) - (160 / 2)); pax_draw_image(pax_buffer, &logo, (320 / 2) - (212 / 2), ((240 - 32 - 10) / 2) - (160 / 2));
pax_buf_destroy(&logo); pax_buf_destroy(&logo);
pax_vec1_t size = pax_text_size(NULL, 18, text); pax_vec1_t size = pax_text_size(font, 18, text);
pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, (320 / 2) - (size.x / 2), 240 - 32, text); pax_draw_text(pax_buffer, 0xFF000000, font, 18, (320 / 2) - (size.x / 2), 240 - 32, text);
ili9341_write(ili9341, pax_buffer->buf); ili9341_write(ili9341, pax_buffer->buf);
} }

View file

@ -29,9 +29,13 @@ esp_err_t graphics_task(pax_buf_t* pax_buffer, ILI9341* ili9341, menu_t* menu,
} }
bool keyboard(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, float aPosX, float aPosY, float aWidth, float aHeight, const char* aTitle, const char* aHint, char* aOutput, size_t aOutputSize) { bool keyboard(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, float aPosX, float aPosY, float aWidth, float aHeight, const char* aTitle, const char* aHint, char* aOutput, size_t aOutputSize) {
const pax_font_t *font = pax_get_font("saira regular");
bool accepted = false; bool accepted = false;
pkb_ctx_t kb_ctx; pkb_ctx_t kb_ctx;
pkb_init(pax_buffer, &kb_ctx, aOutput); pkb_init(pax_buffer, &kb_ctx, 1024);
pkb_set_content(&kb_ctx, aOutput);
kb_ctx.kb_font = font;
kb_ctx.text_font = font;
pax_col_t fgColor = 0xFF000000; pax_col_t fgColor = 0xFF000000;
pax_col_t bgColor = 0xFFFFFFFF; pax_col_t bgColor = 0xFFFFFFFF;
@ -42,7 +46,7 @@ bool keyboard(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341,
pax_col_t selColor = 0xff007fff; pax_col_t selColor = 0xff007fff;
kb_ctx.text_col = borderColor; kb_ctx.text_col = borderColor;
kb_ctx.sel_text_col = selColor; kb_ctx.sel_text_col = bgColor;
kb_ctx.sel_col = selColor; kb_ctx.sel_col = selColor;
kb_ctx.bg_col = bgColor; kb_ctx.bg_col = bgColor;
@ -58,9 +62,9 @@ bool keyboard(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341,
pax_simple_rect(pax_buffer, titleBgColor, aPosX, aPosY, aWidth, titleHeight); pax_simple_rect(pax_buffer, titleBgColor, aPosX, aPosY, aWidth, titleHeight);
pax_simple_line(pax_buffer, titleColor, aPosX + 1, aPosY + titleHeight, aPosX + aWidth - 2, aPosY + titleHeight - 1); pax_simple_line(pax_buffer, titleColor, aPosX + 1, aPosY + titleHeight, aPosX + aWidth - 2, aPosY + titleHeight - 1);
pax_clip(pax_buffer, aPosX + 1, aPosY + 1, aWidth - 2, titleHeight - 2); pax_clip(pax_buffer, aPosX + 1, aPosY + 1, aWidth - 2, titleHeight - 2);
pax_draw_text(pax_buffer, titleColor, NULL, titleHeight - 2, aPosX + 1, aPosY + 1, aTitle); pax_draw_text(pax_buffer, titleColor, font, titleHeight - 2, aPosX + 1, aPosY + 1, aTitle);
pax_clip(pax_buffer, aPosX + 1, aPosY + aHeight - hintHeight, aWidth - 2, hintHeight); pax_clip(pax_buffer, aPosX + 1, aPosY + aHeight - hintHeight, aWidth - 2, hintHeight);
pax_draw_text(pax_buffer, borderColor, NULL, hintHeight - 2, aPosX + 1, aPosY + aHeight - hintHeight, aHint); pax_draw_text(pax_buffer, borderColor, font, hintHeight - 2, aPosX + 1, aPosY + aHeight - hintHeight, aHint);
pax_noclip(pax_buffer); pax_noclip(pax_buffer);
kb_ctx.x = aPosX + 1; kb_ctx.x = aPosX + 1;

View file

@ -1,147 +0,0 @@
/*
MIT License
Copyright (c) 2022 Julian Scheffers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef PAX_KEYBOARD_H
#define PAX_KEYBOARD_H
#include <pax_gfx.h>
#include <pax_shapes.h>
#include <pax_fonts.h>
// A number of inputs supported by the PAX keyboard.
typedef enum {
// Represents no input being pressed.
PKB_NO_INPUT,
// Movement of the cursor.
PKB_UP, PKB_DOWN, PKB_LEFT, PKB_RIGHT,
// Delete to the left or the selection. Backspace key.
PKB_DELETE_BEFORE,
// Delete to the right or the selection. Delete key.
PKB_DELETE_AFTER,
// Switch between lower case, upper case and symbols.
PKB_MODESELECT,
// Enter a character.
PKB_CHARSELECT,
// The same thing as the shift key.
// Goes between PKB_LOWERCASE and PKB_UPPERCASE or PKB_NUMBERS and PKB_SYMBOLS.
PKB_SHIFT,
} pkb_input_t;
// The type of keyboard currently selected.
typedef enum {
// Lowercase and .,
PKB_LOWERCASE,
// Uppercase and <>
PBK_UPPERCASE,
// Numbers and symbols 1/2
PKB_NUMBERS,
// Symbols 2/2
PKB_SYMBOLS,
} pkb_keyboard_t;
// The PAX keyboard context used for drawing and alike.
typedef struct {
// Position on screen of the keyboard.
int x, y;
// Maximum size of the keyboard.
int width, height;
// Content of the keyboard.
char *content;
// Size in bytes of capacity of the content buffer.
size_t content_cap;
// Starting position of the selection in the text box.
int selection;
// Cursor position of the text box.
int cursor;
// Cursor position of the keyboard.
int key_x, key_y;
// The currently held input.
pkb_input_t held;
// The time that holding the input started.
int64_t hold_start;
// The last time pkb_press was called.
int64_t last_press;
// Whether the keyboard is multi-line.
bool multiline;
// Whether the keyboard is in insert mode.
bool insert;
// The board that is currently selected.
pkb_keyboard_t board_sel;
// The font to use for the keyboard.
pax_font_t *kb_font;
// The font size to use for the keyboard.
float kb_font_size;
// The font to use for the text.
pax_font_t *text_font;
// The font size to use for the text.
float text_font_size;
// The text color to use.
pax_col_t text_col;
// The text color to use when a character is being held down.
pax_col_t sel_text_col;
// The selection color to use.
pax_col_t sel_col;
// The background color to use.
pax_col_t bg_col;
// Whether something has changed since last draw.
bool dirty;
// Whether the text has changed since last draw.
bool text_dirty;
// Whether the keyboard has changed since last draw.
bool kb_dirty;
// Whether just the selected character has changed since last draw.
bool sel_dirty;
// Previous cursor position of the keyboard.
// Used for sel_dirty.
int last_key_x, last_key_y;
// Indicates that the input has been accepted.
bool input_accepted;
} pkb_ctx_t;
// Initialise the context with default settings.
void pkb_init (pax_buf_t *buf, pkb_ctx_t *ctx, char* data);
// Free any memory associated with the context.
void pkb_destroy(pkb_ctx_t *ctx);
// Redraw the complete on-screen keyboard.
void pkb_render (pax_buf_t *buf, pkb_ctx_t *ctx);
// Redraw only the changed parts of the on-screen keyboard.
void pkb_redraw (pax_buf_t *buf, pkb_ctx_t *ctx);
// The loop that allows input repeating.
void pkb_loop (pkb_ctx_t *ctx);
// A pressing of the input.
void pkb_press (pkb_ctx_t *ctx, pkb_input_t input);
// A relealing of the input.
void pkb_release(pkb_ctx_t *ctx, pkb_input_t input);
#endif //PAX_KEYBOARD_H

View file

@ -183,6 +183,7 @@ void menu_render(pax_buf_t *aBuffer, menu_t* aMenu, float aPosX, float aPosY, fl
pax_col_t titleBgColor = aColor; pax_col_t titleBgColor = aColor;
pax_col_t scrollbarBgColor = 0xFFCCCCCC; pax_col_t scrollbarBgColor = 0xFFCCCCCC;
pax_col_t scrollbarFgColor = 0xFF555555; pax_col_t scrollbarFgColor = 0xFF555555;
const pax_font_t *font = pax_get_font("saira regular");
float entry_height = 18 + 2; float entry_height = 18 + 2;
size_t maxItems = aHeight / entry_height; size_t maxItems = aHeight / entry_height;
@ -196,7 +197,7 @@ void menu_render(pax_buf_t *aBuffer, menu_t* aMenu, float aPosX, float aPosY, fl
pax_simple_rect(aBuffer, titleBgColor, aPosX, posY, aWidth, entry_height); pax_simple_rect(aBuffer, titleBgColor, aPosX, posY, aWidth, entry_height);
pax_simple_line(aBuffer, titleColor, aPosX + 1, aPosY + entry_height, aPosX + aWidth - 2, aPosY + entry_height - 1); pax_simple_line(aBuffer, titleColor, aPosX + 1, aPosY + entry_height, aPosX + aWidth - 2, aPosY + entry_height - 1);
pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 2, entry_height - 2); pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 2, entry_height - 2);
pax_draw_text(aBuffer, titleColor, NULL, entry_height - 2, aPosX + 1, posY + 1, aMenu->title); pax_draw_text(aBuffer, titleColor, font, entry_height - 2, aPosX + 1, posY + 1, aMenu->title);
pax_noclip(aBuffer); pax_noclip(aBuffer);
posY += entry_height; posY += entry_height;
} }
@ -219,12 +220,12 @@ void menu_render(pax_buf_t *aBuffer, menu_t* aMenu, float aPosX, float aPosY, fl
if (index == aMenu->position) { if (index == aMenu->position) {
pax_simple_rect(aBuffer, fgColor, aPosX + 1, posY, aWidth - 2, entry_height); pax_simple_rect(aBuffer, fgColor, aPosX + 1, posY, aWidth - 2, entry_height);
pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 4, entry_height - 2); pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 4, entry_height - 2);
pax_draw_text(aBuffer, bgTextColor, NULL, entry_height - 2, aPosX + 1, posY + 1, item->label); pax_draw_text(aBuffer, bgTextColor, font, entry_height - 2, aPosX + 1, posY + 1, item->label);
pax_noclip(aBuffer); pax_noclip(aBuffer);
} else { } else {
pax_simple_rect(aBuffer, bgColor, aPosX + 1, posY, aWidth - 2, entry_height); pax_simple_rect(aBuffer, bgColor, aPosX + 1, posY, aWidth - 2, entry_height);
pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 4, entry_height - 2); pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 4, entry_height - 2);
pax_draw_text(aBuffer, fgColor, NULL, entry_height - 2, aPosX + 1, posY + 1, item->label); pax_draw_text(aBuffer, fgColor, font, entry_height - 2, aPosX + 1, posY + 1, item->label);
pax_noclip(aBuffer); pax_noclip(aBuffer);
} }
posY += entry_height; posY += entry_height;

View file

@ -30,9 +30,10 @@ typedef enum action {
} menu_dev_action_t; } menu_dev_action_t;
void render_dev_help(pax_buf_t* pax_buffer) { void render_dev_help(pax_buf_t* pax_buffer) {
const pax_font_t *font = pax_get_font("saira regular");
pax_background(pax_buffer, 0xFFFFFF); pax_background(pax_buffer, 0xFFFFFF);
pax_noclip(pax_buffer); pax_noclip(pax_buffer);
pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] accept [B] back"); pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] accept [B] back");
} }
void menu_dev(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { void menu_dev(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {

View file

@ -27,7 +27,8 @@ typedef struct {
void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {
menu_t* menu = menu_alloc("Apps"); menu_t* menu = menu_alloc("Apps");
const pax_font_t *font = pax_get_font("saira regular");
appfs_handle_t appfs_fd = APPFS_INVALID_FD; appfs_handle_t appfs_fd = APPFS_INVALID_FD;
while (1) { while (1) {
appfs_fd = appfsNextEntry(appfs_fd); appfs_fd = appfsNextEntry(appfs_fd);
@ -45,7 +46,7 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili
pax_background(pax_buffer, 0xFFFFFF); pax_background(pax_buffer, 0xFFFFFF);
pax_noclip(pax_buffer); pax_noclip(pax_buffer);
pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] start app [B] back"); pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] start app [B] back");
bool quit = false; bool quit = false;

View file

@ -31,9 +31,10 @@ typedef enum action {
} menu_settings_action_t; } menu_settings_action_t;
void render_settings_help(pax_buf_t* pax_buffer) { void render_settings_help(pax_buf_t* pax_buffer) {
const pax_font_t *font = pax_get_font("saira regular");
pax_background(pax_buffer, 0xFFFFFF); pax_background(pax_buffer, 0xFFFFFF);
pax_noclip(pax_buffer); pax_noclip(pax_buffer);
pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] accept [B] back"); pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] accept [B] back");
} }
void menu_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { void menu_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {

View file

@ -24,9 +24,10 @@ typedef enum action {
} menu_start_action_t; } menu_start_action_t;
void render_start_help(pax_buf_t* pax_buffer) { void render_start_help(pax_buf_t* pax_buffer) {
const pax_font_t *font = pax_get_font("saira regular");
pax_background(pax_buffer, 0xFFFFFF); pax_background(pax_buffer, 0xFFFFFF);
pax_noclip(pax_buffer); pax_noclip(pax_buffer);
pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] accept"); pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] accept");
} }
void menu_start(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { void menu_start(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {

View file

@ -60,9 +60,10 @@ typedef enum action {
} menu_wifi_action_t; } menu_wifi_action_t;
void render_wifi_help(pax_buf_t* pax_buffer) { void render_wifi_help(pax_buf_t* pax_buffer) {
const pax_font_t *font = pax_get_font("saira regular");
pax_background(pax_buffer, 0xFFFFFF); pax_background(pax_buffer, 0xFFFFFF);
pax_noclip(pax_buffer); pax_noclip(pax_buffer);
pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] accept [B] back"); pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] accept [B] back");
} }
void wifi_show(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341); void wifi_show(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341);
@ -440,12 +441,7 @@ void wifi_setup(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili934
/* ==== scanning phase ==== */ /* ==== scanning phase ==== */
if (scan) { if (scan) {
// Show a little bit of text. // Show a little bit of text.
char *text = "Scanning..."; display_boot_screen(pax_buffer, ili9341, "Scanning WiFi networks...");
pax_vec1_t dims = pax_text_size(NULL, 1, text);
float scale = pax_buffer->width / dims.x;
pax_background(pax_buffer, 0xffffffff);
pax_draw_text(pax_buffer, 0xff000000, NULL, scale, 0, (pax_buffer->height - dims.y*scale)/2, text);
ili9341_write(ili9341, pax_buffer->buf);
// Scan for networks. // Scan for networks.
wifi_ap_record_t *aps; wifi_ap_record_t *aps;

View file

@ -1,791 +0,0 @@
/*
MIT License
Copyright (c) 2022 Julian Scheffers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <pax_keyboard.h>
#include <esp_timer.h>
#include <string.h>
#include <malloc.h>
/* ==== Miscellaneous ==== */
// Initialise the context with default settings.
void pkb_init(pax_buf_t *buf, pkb_ctx_t *ctx, char* data) {
// Allocate a bufffer.
char *buffer = NULL;
if (data == NULL) {
buffer = malloc(4);
memset(buffer, 0, 4);
} else {
size_t length = strlen(data);
if (length < 4) length = 4;
buffer = malloc(length);
memset(buffer, 0, length);
strcpy(buffer, data);
}
// Some defaults.
*ctx = (pkb_ctx_t) {
// Position on screen of the keyboard.
.x = 0,
.y = 0,
// Maximum size of the keyboard.
.width = buf->width,
.height = buf->height,
// Content of the keyboard.
.content = buffer,
// Size in bytes of capacity of the content buffer.
.content_cap = 4,
// Starting position of the selection in the text box.
.selection = 0,
// Cursor position of the text box.
.cursor = 0,
// Cursor position of the keyboard.
.key_x = 3,
.key_y = 1,
// The currently held input.
.held = PKB_NO_INPUT,
// The time that holding the input started.
.hold_start = 0,
// The last time pkb_press was called.
.last_press = 0,
// Whether the keyboard is multi-line.
.multiline = false,
// Whether the keyboard is in insert mode.
.insert = false,
// The board that is currently selected.
.board_sel = PKB_LOWERCASE,
// The font to use for the keyboard.
.kb_font = PAX_FONT_DEFAULT,
// The font size to use for the keyboard.
.kb_font_size = 27,
// The font to use for the text.
.text_font = PAX_FONT_DEFAULT,
// The font size to use for the text.
.text_font_size = 18,
// The text color to use.
.text_col = 0xffffffff,
// The text color to use when a character is being held down.
.sel_text_col = 0xff000000,
// The selection color to use.
.sel_col = 0xff007fff,
// The background color to use.
.bg_col = 0xff000000,
// Whether something has changed since last draw.
.dirty = true,
// Whether the text has changed since last draw.
.text_dirty = true,
// Whether the keyboard has changed since last draw.
.kb_dirty = true,
// Whether just the selected character has changed since last draw.
.sel_dirty = true,
// Previous cursor position of the keyboard.
// Used for sel_dirty.
.last_key_x = 3,
.last_key_y = 1,
// Indicates that the input has been accepted.
.input_accepted = false,
};
// TODO: Pick fancier text sizes.
}
// Free any memory associated with the context.
void pkb_destroy(pkb_ctx_t *ctx) {
free(ctx->content);
ctx->content = NULL;
ctx->content_cap = 0;
}
const char *uppercase_board[] = {
"QWERTYUIOP",
"ASDFGHJKL",
" ZXCVBNM ",
" < > ",
"<", ">",
};
const char *lowercase_board[] = {
"qwertyuiop",
"asdfghjkl",
" zxcvbnm ",
" , . ",
",", ".",
};
const char *number_board[] = {
"1234567890",
"@#$_&-+()/",
" *\"';:!? ",
" = \\ ",
"=", "\\",
};
const char *symbols_board[] = {
"()[]{}`~",
"/|\\+-_=",
" ^%<>'\" ",
" , . ",
",", ".",
};
const char **boards[] = {
lowercase_board, uppercase_board,
number_board, symbols_board,
};
/* ==== Special key art ==== */
// Art for the accept key.
// Expects x to be the horizontal center of the key.
static void pkb_art_accept(pax_buf_t *buf, pkb_ctx_t *ctx, float x, float y, float dx, bool selected) {
pax_col_t col = selected && ctx->held == PKB_CHARSELECT ? ctx->sel_text_col : ctx->text_col;
float scale = fminf(ctx->kb_font_size - 4, dx - 4);
pax_push_2d (buf);
pax_apply_2d (buf, matrix_2d_translate(x-dx/2+2, y+2));
pax_apply_2d (buf, matrix_2d_scale(scale, scale));
pax_draw_line(buf, col, 0.25, 0.5, 0.5, 1);
pax_draw_line(buf, col, 0.5, 1, 1, 0);
pax_pop_2d (buf);
}
// Art for the backspace key.
// Expects x to be the horizontal center of the key.
static void pkb_art_bksp(pax_buf_t *buf, pkb_ctx_t *ctx, float x, float y, float dx, bool selected) {
pax_col_t col = selected && ctx->held == PKB_CHARSELECT ? ctx->sel_text_col : ctx->text_col;
float scale = fminf(ctx->kb_font_size - 4, dx - 4);
pax_push_2d (buf);
pax_apply_2d (buf, matrix_2d_translate(x-dx/2+2, y+2));
pax_apply_2d (buf, matrix_2d_scale(scale, scale));
// The stopper.
pax_draw_line(buf, col, 0, 0.25, 0, 0.75);
// The arrow.
pax_draw_line(buf, col, 0.1, 0.5, 0.35, 0.25);
pax_draw_line(buf, col, 0.1, 0.5, 0.35, 0.75);
pax_draw_line(buf, col, 0.1, 0.5, 1, 0.5);
pax_pop_2d (buf);
}
// Art for the shift key.
// Expects x to be the horizontal center of the key.
static void pkb_art_shift(pax_buf_t *buf, pkb_ctx_t *ctx, float x, float y, float dx, bool selected) {
bool active = ctx->board_sel & 1;
pax_col_t col = selected && ctx->held == PKB_CHARSELECT ? ctx->sel_text_col : ctx->text_col;
float scale = fminf(ctx->kb_font_size - 4, dx - 4);
pax_push_2d (buf);
pax_apply_2d(buf, matrix_2d_translate(x, y+2));
pax_apply_2d(buf, matrix_2d_scale(scale, scale));
if (active) {
// Filled in shift key.
pax_draw_tri (buf, col, -0.5, 0.5, 0, 0, 0.5, 0.5);
pax_draw_rect(buf, col, -0.25, 0.5, 0.5, 0.5);
} else {
// Outlined shift key.
pax_draw_line(buf, col, 0, 0, 0.5, 0.5);
pax_draw_line(buf, col, 0.5, 0.5, 0.25, 0.5);
pax_draw_line(buf, col, 0.25, 0.5, 0.25, 1);
pax_draw_line(buf, col, 0.25, 1, -0.25, 1);
pax_draw_line(buf, col, -0.25, 0.5, -0.25, 1);
pax_draw_line(buf, col, -0.5, 0.5, -0.25, 0.5);
pax_draw_line(buf, col, 0, 0, -0.5, 0.5);
}
pax_pop_2d (buf);
}
// Art for the letters/numbers key.
// Expects x to be the horizontal center of the key.
static void pkb_art_select(pax_buf_t *buf, pkb_ctx_t *ctx, float x, float y, float dx, bool selected) {
pax_col_t col = selected && ctx->held == PKB_CHARSELECT ? ctx->sel_text_col : ctx->text_col;
// Pick the stuff to show.
char *short_str;
char *long_str;
if (ctx->board_sel == PKB_NUMBERS) {
// Show some symbols.
short_str = "%";
long_str = "%&~";
} else if (ctx->board_sel == PKB_SYMBOLS) {
// Show some letters.
short_str = "A";
long_str = "Abc";
} else {
// Show some numbers.
short_str = "#";
long_str = "123";
}
// Calculate font size.
char *str = long_str;
pax_vec1_t dims = pax_text_size(ctx->kb_font, 0, str);
int font_size = 9;//(dx - 4) / dims.x * dims.y;
if (font_size < dims.y) {
str = short_str;
dims = pax_text_size(ctx->kb_font, 0, str);
font_size = 9;//(dx - 4) / dims.x * dims.y;
}
dims = pax_text_size(ctx->kb_font, font_size, str);
// Now draw it.
pax_push_2d (buf);
pax_apply_2d (buf, matrix_2d_translate(x-dims.x/2, y+(ctx->kb_font_size-font_size)/2));
pax_draw_text(buf, col, ctx->kb_font, font_size, 0, 0, str);
pax_pop_2d (buf);
}
/* ==== Rendering ==== */
// Draw one key of the keyboard.
// Expects x to be the horizontal center of the key.
static void pkb_char(pax_buf_t *buf, pkb_ctx_t *ctx, float x, float y, float dx, char *text, bool selected) {
pax_vec1_t dims = pax_text_size(ctx->kb_font, ctx->kb_font_size, text);
if (selected && ctx->held == PKB_CHARSELECT) {
// Infilll!
pax_draw_rect(buf, ctx->sel_col, x-dx/2, y, dx, ctx->kb_font_size);
pax_draw_text(buf, ctx->sel_text_col, ctx->kb_font, ctx->kb_font_size, x-dims.x*0.5, y, text);
} else {
pax_draw_text(buf, ctx->text_col, ctx->kb_font, ctx->kb_font_size, x-dims.x*0.5, y, text);
// Outline?
if (selected) {
pax_push_2d(buf);
pax_apply_2d(buf, matrix_2d_translate(-dx/2, 0));
pax_draw_line(buf, ctx->sel_col, x, y, x + dx - 1, y);
pax_draw_line(buf, ctx->sel_col, x, y+ctx->kb_font_size-1, x + dx - 1, y+ctx->kb_font_size-1);
pax_draw_line(buf, ctx->sel_col, x + dx - 1, y, x + dx - 1, y+ctx->kb_font_size-1);
pax_draw_line(buf, ctx->sel_col, x, y, x, y+ctx->kb_font_size-1);
pax_pop_2d(buf);
}
}
}
// Draw one full row of the keyboard.
static void pkb_row(pax_buf_t *buf, pkb_ctx_t *ctx, int rownum, int selected, float dx, float y) {
// Calculate some stuff.
char *row = boards[ctx->board_sel][rownum];
size_t len = strlen(row);
int x = ctx->x + (ctx->width - len * dx + dx) / 2;
char tmp[2] = {0,0};
// Show all of them.
for (int i = 0; i < len; i++) {
// Draw a KEY.
*tmp = row[i];
pkb_char(buf, ctx, x, y, dx, tmp, selected == i);
if (i == 0 && rownum == 2) {
// Draw shift key art.
pkb_art_shift(buf, ctx, x, y, dx, selected == i);
} else if (rownum == 2 && i == len - 1) {
// Draw the backspace key art.
pkb_art_bksp(buf, ctx, x, y, dx, selected == i);
}
x += dx;
}
}
// Draw a specific key in a row of the keyboard.
static void pkb_row_key(pax_buf_t *buf, pkb_ctx_t *ctx, int rownum, bool selected, float dx, float y, int keyno) {
// Calculate some stuff.
char *row = boards[ctx->board_sel][rownum];
size_t len = strlen(row);
int x = ctx->x + (ctx->width - len * dx + dx) / 2 + dx * keyno;
char tmp[2] = {0,0};
// Show one of them.
*tmp = row[keyno];
pax_draw_rect(buf, ctx->bg_col, x-dx/2, y, dx, ctx->kb_font_size);
pkb_char(buf, ctx, x, y, dx, tmp, selected);
if (rownum == 2 && keyno == 0) {
// Draw the shift key art.
pkb_art_shift(buf, ctx, x, y, dx, selected);
} else if (rownum == 2 && keyno == len - 1) {
// Draw the backspace key art.
pkb_art_bksp(buf, ctx, x, y, dx, selected);
}
}
// Draw just the board part.
static void pkb_render_keyb(pax_buf_t *buf, pkb_ctx_t *ctx, bool do_bg) {
// Draw background.
if (do_bg) {
pax_draw_rect(buf, ctx->bg_col, ctx->x, ctx->y + ctx->height - ctx->kb_font_size*4, ctx->width, ctx->kb_font_size*4);
}
// Select the board to display.
char **board = boards[ctx->board_sel];
float dx = ctx->width / 10;
float y = ctx->y + ctx->height - ctx->kb_font_size * 4;
// Draw the first three rows.
for (int i = 0; i < 3; i ++) {
int sel = -1;
if (i == ctx->key_y) {
sel = ctx->key_x;
}
pkb_row(buf, ctx, i, sel, dx, y);
y += ctx->kb_font_size;
}
// Spacebar row time.
bool space_sel = ctx->key_y == 3 && ctx->key_x > 1 && ctx->key_x < 7;
float x = ctx->x + (ctx->width - 8 * dx) / 2;
// The thingy selector.
pkb_char(buf, ctx, x, y, dx, " ", ctx->key_y == 3 && ctx->key_x == 0);
pkb_art_select(buf, ctx, x, y, dx, ctx->key_y == 3 && ctx->key_x == 0);
x += 1.0 * dx;
// Left char.
pkb_char(buf, ctx, x, y, dx, board[4], ctx->key_y == 3 && ctx->key_x == 1);
x += 1.0 * dx;
// SPACE.
if (space_sel && ctx->held == PKB_CHARSELECT) {
pax_draw_rect(buf, ctx->sel_col, x-dx/2, y, dx*5, ctx->kb_font_size);
pax_draw_rect(buf, ctx->sel_text_col, x, y + ctx->kb_font_size/3, dx*4, ctx->kb_font_size/3);
} else {
pax_draw_rect(buf, ctx->text_col, x, y + ctx->kb_font_size/3, dx*4, ctx->kb_font_size/3);
if (space_sel) {
// Outline rect?
pax_push_2d(buf);
pax_apply_2d(buf, matrix_2d_translate(-dx/2, 0));
pax_draw_line(buf, ctx->sel_col, x, y, x + dx*5 - 1, y);
pax_draw_line(buf, ctx->sel_col, x, y+ctx->kb_font_size-1, x + dx*5 - 1, y+ctx->kb_font_size-1);
pax_draw_line(buf, ctx->sel_col, x + dx*5 - 1, y, x + dx*5 - 1, y+ctx->kb_font_size-1);
pax_draw_line(buf, ctx->sel_col, x, y, x, y+ctx->kb_font_size-1);
pax_pop_2d(buf);
}
}
// Right char.
x += 5.0 * dx;
pkb_char(buf, ctx, x, y, dx, board[5], ctx->key_y == 3 && ctx->key_x == 7);
x += 1.0 * dx;
// The thingy acceptor.
pkb_char(buf, ctx, x, y, dx, " ", ctx->key_y == 3 && ctx->key_x == 8);
pkb_art_accept(buf, ctx, x, y, dx, ctx->key_y == 3 && ctx->key_x == 8);
}
// Draw just the text part.
static void pkb_render_text(pax_buf_t *buf, pkb_ctx_t *ctx, bool do_bg) {
// Draw background.
if (do_bg) {
pax_draw_rect(buf, ctx->bg_col, ctx->x, ctx->y, ctx->width, ctx->height - ctx->kb_font_size*4);
}
if (ctx->key_y == -1) {
// Outline us.
pax_outline_rect(buf, ctx->sel_col, ctx->x, ctx->y, ctx->width, ctx->height - ctx->kb_font_size*4);
}
// Some setup.
float x = ctx->x + 2;
float y = ctx->y + 2;
char tmp[2] = {0, 0};
// Draw everything.
for (int i = 0; i < strlen(ctx->content); i++) {
if (ctx->cursor == i) {
// The cursor in between the input.
pax_draw_line(buf, ctx->sel_col, x, y, x, y + ctx->text_font_size - 1);
}
// The character of the input.
tmp[0] = ctx->content[i];
pax_vec1_t dims = pax_text_size(ctx->text_font, ctx->text_font_size, tmp);
if (x + dims.x > ctx->width - 2) {
// Word wrap.
x = 2;
y += ctx->text_font_size;
}
pax_draw_text(buf, ctx->text_col, ctx->text_font, ctx->text_font_size, x, y, tmp);
x += dims.x;
}
if (ctx->cursor == strlen(ctx->content)) {
// The cursor after the input.
pax_draw_line(buf, ctx->sel_col, x, y, x, y + ctx->text_font_size - 1);
}
}
// Draw one specific key.
static void pkb_render_key(pax_buf_t *buf, pkb_ctx_t *ctx, int key_x, int key_y) {
if (key_y == -1) {
// If key_y is -1, the text box is selected to render.
pkb_render_text(buf, ctx, true);
return;
}
// Select the board to display.
char **board = boards[ctx->board_sel];
float dx = ctx->width / 10;
float y = ctx->y + ctx->height - ctx->kb_font_size * 4;
if (key_y < 3) {
// Draw one of the first three rows.
y += ctx->kb_font_size * key_y;
pkb_row_key(buf, ctx, key_y, key_y == ctx->key_y && key_x == ctx->key_x, dx, y, key_x);
y += ctx->kb_font_size;
} else {
// Spacebar row time.
y += ctx->kb_font_size * 3;
bool space_sel = ctx->key_y == 3 && ctx->key_x > 1 && ctx->key_x < 7;
float x = ctx->x + (ctx->width - 8 * dx) / 2;
// The thingy selector.
if (key_x == 0) {
pax_draw_rect(buf, ctx->bg_col, x-dx/2, y, dx, ctx->kb_font_size);
pkb_char(buf, ctx, x, y, dx, " ", ctx->key_y == 3 && ctx->key_x == 0);
pkb_art_select(buf, ctx, x, y, dx, ctx->key_y == 3 && ctx->key_x == 0);
}
x += 1.0 * dx;
if (key_x == 1) {
pax_draw_rect(buf, ctx->bg_col, x-dx/2, y, dx, ctx->kb_font_size);
pkb_char(buf, ctx, x, y, dx, board[4], ctx->key_y == 3 && ctx->key_x == 1);
}
x += 1.0 * dx;
// SPACE.
if (space_sel && ctx->held == PKB_CHARSELECT) {
pax_draw_rect(buf, ctx->sel_col, x-dx/2, y, dx*5, ctx->kb_font_size);
pax_draw_rect(buf, ctx->sel_text_col, x, y + ctx->kb_font_size/3, dx*4, ctx->kb_font_size/3);
} else {
pax_draw_rect(buf, ctx->bg_col, x-dx/2, y, dx*5, ctx->kb_font_size);
pax_draw_rect(buf, ctx->text_col, x, y + ctx->kb_font_size/3, dx*4, ctx->kb_font_size/3);
if (space_sel) {
// Outline rect?
pax_push_2d(buf);
pax_apply_2d(buf, matrix_2d_translate(-dx/2, 0));
pax_draw_line(buf, ctx->sel_col, x, y, x + dx*5 - 1, y);
pax_draw_line(buf, ctx->sel_col, x, y+ctx->kb_font_size-1, x + dx*5 - 1, y+ctx->kb_font_size-1);
pax_draw_line(buf, ctx->sel_col, x + dx*5 - 1, y, x + dx*5 - 1, y+ctx->kb_font_size-1);
pax_draw_line(buf, ctx->sel_col, x, y, x, y+ctx->kb_font_size-1);
pax_pop_2d(buf);
}
}
// Right char.
x += 5.0 * dx;
if (key_x == 7) {
pax_draw_rect(buf, ctx->bg_col, x-dx/2, y, dx, ctx->kb_font_size);
pkb_char(buf, ctx, x, y, dx, board[5], ctx->key_y == 3 && ctx->key_x == 7);
}
x += 1.0 * dx;
// The thingy acceptor.
if (key_x == 8) {
pax_draw_rect(buf, ctx->bg_col, x-dx/2, y, dx, ctx->kb_font_size);
pkb_char(buf, ctx, x, y, dx, " ", ctx->key_y == 3 && ctx->key_x == 8);
pkb_art_accept(buf, ctx, x, y, dx, ctx->key_y == 3 && ctx->key_x == 8);
}
}
}
// Redraw the complete on-screen keyboard.
void pkb_render(pax_buf_t *buf, pkb_ctx_t *ctx) {
if (matrix_2d_is_identity(buf->stack_2d.value)
&& ctx->x == 0 && ctx->y == 0
&& ctx->width == buf->width
&& ctx->height == buf->height) {
// We can just fill the entire screen.
pax_background(buf, ctx->bg_col);
} else {
// We'll need to fill a rectangle.
pax_draw_rect(
buf, ctx->bg_col,
ctx->x, ctx->y,
ctx->width, ctx->height
);
}
// Draw the board.
pkb_render_keyb(buf, ctx, false);
// Time to draw some text.
pkb_render_text(buf, ctx, false);
// Mark as not dirty.
ctx->dirty = false;
ctx->kb_dirty = false;
ctx->sel_dirty = false;
ctx->text_dirty = false;
ctx->last_key_x = ctx->key_x;
ctx->last_key_y = ctx->key_y;
}
// Redraw only the changed parts of the on-screen keyboard.
void pkb_redraw(pax_buf_t *buf, pkb_ctx_t *ctx) {
if (ctx->text_dirty) {
pkb_render_text(buf, ctx, true);
}
if (ctx->kb_dirty) {
pkb_render_keyb(buf, ctx, true);
} else if (ctx->sel_dirty) {
pkb_render_key(buf, ctx, ctx->last_key_x, ctx->last_key_y);
pkb_render_key(buf, ctx, ctx->key_x, ctx->key_y);
}
// Mark as not dirty.
ctx->dirty = false;
ctx->kb_dirty = false;
ctx->sel_dirty = false;
ctx->text_dirty = false;
ctx->last_key_x = ctx->key_x;
ctx->last_key_y = ctx->key_y;
}
/* ==== Text editing ==== */
// Handling of delete or backspace.
static void pkb_delete(pkb_ctx_t *ctx, bool is_backspace) {
size_t oldlen = strlen(ctx->content);
if (!is_backspace && ctx->cursor == oldlen) {
// No forward deleting at the end of the line.
return;
} else if (is_backspace && ctx->cursor == 0) {
// No backward deleting at the start of the line.
return;
} else if (!is_backspace) {
// Advanced backspace.
ctx->cursor ++;
}
// Copy back everything including null terminator.
ctx->cursor --;
for (int i = ctx->cursor; i < oldlen; i++) {
ctx->content[i] = ctx->content[i+1];
}
// DECREMENT length.
if (oldlen * 2 < ctx->content_cap) {
// Not decrementing here is important as oldlen excludes the null terminator.
ctx->content_cap = oldlen;
ctx->content = realloc(ctx->content, ctx->content_cap);
}
ctx->text_dirty = true;
}
// Handling of normal input.
static void pkb_append(pkb_ctx_t *ctx, char value) {
size_t oldlen = strlen(ctx->content);
if (oldlen + 2 >= ctx->content_cap) {
// Expand the buffer just a bit.
ctx->content_cap *= 2;
ctx->content = realloc(ctx->content, ctx->content_cap);
}
// Copy over the remainder of the buffer.
// If there's no text this still copies the null terminator.
for (int i = oldlen; i >= ctx->cursor; i --) {
ctx->content[i + 1] = ctx->content[i];
}
// And finally insert at the character.
ctx->content[ctx->cursor] = value;
ctx->cursor ++;
ctx->text_dirty = true;
}
/* ==== Input handling ==== */
// The loop that allows input repeating.
void pkb_loop(pkb_ctx_t *ctx) {
int64_t now = esp_timer_get_time();
if (!ctx->held) return;
bool is_dir = (ctx->held >= PKB_UP) && (ctx->held <= PKB_RIGHT);
if ((ctx->hold_start + 1000000 < now) || (is_dir && ctx->hold_start + 250000 < now)) {
// 8 repeats per second.
if (ctx->last_press + 125000 < now) {
pkb_press(ctx, ctx->held);
}
}
}
// A pressing of the input.
void pkb_press(pkb_ctx_t *ctx, pkb_input_t input) {
char **board = boards[ctx->board_sel];
ctx->last_press = esp_timer_get_time();
switch (input) {
// Cursor movements.
size_t rowlen;
case PKB_UP:
ctx->key_y --;
if (ctx->key_y < -1) ctx->key_y = 3;
else if (ctx->key_y != -1) {
rowlen = strlen(board[ctx->key_y]);
if (ctx->key_x >= rowlen) ctx->key_x = rowlen - 1;
}
ctx->sel_dirty = true;
break;
case PKB_DOWN:
ctx->key_y ++;
ctx->key_y %= 4;
rowlen = strlen(board[ctx->key_y]);
if (ctx->key_x >= rowlen) ctx->key_x = rowlen - 1;
ctx->sel_dirty = true;
break;
case PKB_LEFT:
if (ctx->key_y == -1) {
if (ctx->cursor > 0) ctx->cursor --;
} else if (ctx->key_y == 3 && ctx->key_x > 1 && ctx->key_x < 7) {
ctx->key_x = 1;
} else {
ctx->key_x --;
if (ctx->key_x < 0) ctx->key_x = strlen(board[ctx->key_y]) - 1;
}
ctx->sel_dirty = true;
break;
case PKB_RIGHT:
if (ctx->key_y == -1) {
if (ctx->cursor < strlen(ctx->content)) ctx->cursor ++;
} else if (ctx->key_y == 3 && ctx->key_x > 1 && ctx->key_x < 7) {
ctx->key_x = 7;
} else {
ctx->key_x ++;
ctx->key_x %= strlen(board[ctx->key_y]);
}
ctx->sel_dirty = true;
break;
// Enter a character.
case PKB_CHARSELECT:
ctx->sel_dirty |= ctx->held != PKB_CHARSELECT;
if (ctx->key_y == 3) {
switch (ctx->key_x) {
case 0:
// Board selector.
if (ctx->board_sel == PKB_NUMBERS) ctx->board_sel = PKB_SYMBOLS;
else if (ctx->board_sel == PKB_SYMBOLS) ctx->board_sel = PKB_LOWERCASE;
else ctx->board_sel = PKB_NUMBERS;
ctx->kb_dirty = true;
break;
case 1:
// Magic.
pkb_append(ctx, *board[4]);
break;
default:
// Spacebar.
pkb_append(ctx, ' ');
break;
case 7:
// mAGIC.
pkb_append(ctx, *board[5]);
break;
case 8:
// Enter idk.
ctx->input_accepted = true;
break;
}
} else if (ctx->key_y == 2) {
if (ctx->key_x == 0) {
// cAPS LOCK KEY.
if (ctx->held == PKB_CHARSELECT) ctx->held = PKB_NO_INPUT;
ctx->board_sel ^= 1;
ctx->kb_dirty = true;
} else if (ctx->key_x == strlen(board[2])-1) {
// Backspace.
pkb_delete(ctx, true);
} else {
// nORMAL CHAR.
pkb_append(ctx, board[2][ctx->key_x]);
}
} else {
// Normal char.
pkb_append(ctx, board[ctx->key_y][ctx->key_x]);
}
break;
// Shift key, the pressening.
case PKB_SHIFT:
ctx->board_sel |= 1;
ctx->kb_dirty = true;
break;
// Next keyboard.
case PKB_MODESELECT:
ctx->board_sel ++;
ctx->board_sel %= 4;
rowlen = strlen(board[ctx->key_y]);
if (ctx->key_x >= rowlen) ctx->key_x = rowlen - 1;
ctx->kb_dirty = true;
break;
// Backspace.
case PKB_DELETE_BEFORE:
pkb_delete(ctx, true);
break;
// Delete.
case PKB_DELETE_AFTER:
pkb_delete(ctx, false);
break;
default:
break;
}
if (input != PKB_SHIFT && input != ctx->held) {
ctx->held = input;
ctx->hold_start = esp_timer_get_time();
}
ctx->dirty = true;
}
// A relealing of the input.
void pkb_release(pkb_ctx_t *ctx, pkb_input_t input) {
switch (input) {
// Shift key, the releasening.
case PKB_SHIFT:
ctx->dirty = true;
ctx->board_sel &= ~1;
ctx->kb_dirty = true;
break;
// Unpress them char.
case PKB_CHARSELECT:
ctx->sel_dirty = true;
break;
default:
break;
}
if (ctx->held == input) {
ctx->held = PKB_NO_INPUT;
ctx->dirty = true;
}
}

View file

@ -27,6 +27,7 @@ typedef struct _uninstall_menu_args {
void uninstall_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { void uninstall_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {
menu_t* menu = menu_alloc("Uninstall application"); menu_t* menu = menu_alloc("Uninstall application");
const pax_font_t *font = pax_get_font("saira regular");
appfs_handle_t appfs_fd = APPFS_INVALID_FD; appfs_handle_t appfs_fd = APPFS_INVALID_FD;
while (1) { while (1) {
@ -49,7 +50,7 @@ void uninstall_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341*
pax_background(pax_buffer, 0xFFFFFF); pax_background(pax_buffer, 0xFFFFFF);
pax_noclip(pax_buffer); pax_noclip(pax_buffer);
pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] uninstall app [B] back"); pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] uninstall app [B] back");
bool quit = false; bool quit = false;