commit
1412a86108
16 changed files with 36 additions and 962 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -37,3 +37,6 @@
|
|||
[submodule "components/pax-codecs"]
|
||||
path = components/pax-codecs
|
||||
url = https://github.com/robotman2412/pax-codecs.git
|
||||
[submodule "main/pax-keyboard"]
|
||||
path = components/pax-keyboard
|
||||
url = https://github.com/robotman2412/pax-keyboard
|
||||
|
|
|
@ -16,6 +16,7 @@ Source code included as submodules is licensed separately, please check the foll
|
|||
| components/i2c-bno055 | MIT | Nicolai Electronics |
|
||||
| components/mch2022-rp2040 | MIT | Renze Nicolai |
|
||||
| components/pax-graphics | MIT | Julian Scheffers |
|
||||
| components/pax-keyboard | MIT | Julian Scheffers |
|
||||
| components/sdcard | MIT | Nicolai Electronics |
|
||||
| components/spi-ice40 | MIT | Nicolai Electronics |
|
||||
| components/spi-ili9341 | MIT | Nicolai Electronics |
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 8e603e9ca73a282a80e45e74160ab6c7c7fa4fff
|
||||
Subproject commit 36049d7deb159c835eee6a5aa021b654bd3dd83b
|
1
components/pax-keyboard
Submodule
1
components/pax-keyboard
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit adad199c55e91f68d3e162b48f4e37816ef95c9a
|
|
@ -4,7 +4,6 @@ idf_component_register(
|
|||
"fpga_test.c"
|
||||
"graphics_wrapper.c"
|
||||
"menu.c"
|
||||
"pax_keyboard.c"
|
||||
"rp2040_updater.c"
|
||||
"settings.c"
|
||||
"system_wrapper.c"
|
||||
|
|
|
@ -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");
|
||||
|
||||
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_background(pax_buffer, 0xFFFFFF);
|
||||
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_buf_destroy(&logo);
|
||||
|
||||
pax_vec1_t size = pax_text_size(NULL, 18, text);
|
||||
pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, (320 / 2) - (size.x / 2), 240 - 32, text);
|
||||
pax_vec1_t size = pax_text_size(font, 18, text);
|
||||
pax_draw_text(pax_buffer, 0xFF000000, font, 18, (320 / 2) - (size.x / 2), 240 - 32, text);
|
||||
ili9341_write(ili9341, pax_buffer->buf);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
const pax_font_t *font = pax_get_font("saira regular");
|
||||
bool accepted = false;
|
||||
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 bgColor = 0xFFFFFFFF;
|
||||
|
@ -42,7 +46,7 @@ bool keyboard(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341,
|
|||
pax_col_t selColor = 0xff007fff;
|
||||
|
||||
kb_ctx.text_col = borderColor;
|
||||
kb_ctx.sel_text_col = selColor;
|
||||
kb_ctx.sel_text_col = bgColor;
|
||||
kb_ctx.sel_col = selColor;
|
||||
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_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_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_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);
|
||||
|
||||
kb_ctx.x = aPosX + 1;
|
||||
|
|
|
@ -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
|
|
@ -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 scrollbarBgColor = 0xFFCCCCCC;
|
||||
pax_col_t scrollbarFgColor = 0xFF555555;
|
||||
const pax_font_t *font = pax_get_font("saira regular");
|
||||
|
||||
float entry_height = 18 + 2;
|
||||
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_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_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);
|
||||
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) {
|
||||
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_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);
|
||||
} else {
|
||||
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_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);
|
||||
}
|
||||
posY += entry_height;
|
||||
|
|
|
@ -30,9 +30,10 @@ typedef enum action {
|
|||
} menu_dev_action_t;
|
||||
|
||||
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_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) {
|
||||
|
|
|
@ -27,7 +27,8 @@ typedef struct {
|
|||
|
||||
void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {
|
||||
menu_t* menu = menu_alloc("Apps");
|
||||
|
||||
const pax_font_t *font = pax_get_font("saira regular");
|
||||
|
||||
appfs_handle_t appfs_fd = APPFS_INVALID_FD;
|
||||
while (1) {
|
||||
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_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;
|
||||
|
||||
|
|
|
@ -31,9 +31,10 @@ typedef enum action {
|
|||
} menu_settings_action_t;
|
||||
|
||||
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_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) {
|
||||
|
|
|
@ -24,9 +24,10 @@ typedef enum action {
|
|||
} menu_start_action_t;
|
||||
|
||||
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_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) {
|
||||
|
|
|
@ -60,9 +60,10 @@ typedef enum action {
|
|||
} menu_wifi_action_t;
|
||||
|
||||
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_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);
|
||||
|
@ -440,12 +441,7 @@ void wifi_setup(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili934
|
|||
/* ==== scanning phase ==== */
|
||||
if (scan) {
|
||||
// Show a little bit of text.
|
||||
char *text = "Scanning...";
|
||||
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);
|
||||
display_boot_screen(pax_buffer, ili9341, "Scanning WiFi networks...");
|
||||
|
||||
// Scan for networks.
|
||||
wifi_ap_record_t *aps;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ typedef struct _uninstall_menu_args {
|
|||
|
||||
void uninstall_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {
|
||||
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;
|
||||
while (1) {
|
||||
|
@ -49,7 +50,7 @@ void uninstall_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341*
|
|||
|
||||
pax_background(pax_buffer, 0xFFFFFF);
|
||||
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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue