Update UI fonts.

This commit is contained in:
RobotMan2412 2022-06-02 13:10:56 +02:00
parent 4960e10283
commit 872fd5da67
7 changed files with 16 additions and 944 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 = main/pax-keyboard
url = https://github.com/robotman2412/pax-keyboard

View file

@ -4,7 +4,7 @@ idf_component_register(
"fpga_test.c" "fpga_test.c"
"graphics_wrapper.c" "graphics_wrapper.c"
"menu.c" "menu.c"
"pax_keyboard.c" "pax-keyboard/pax_keyboard.c"
"rp2040_updater.c" "rp2040_updater.c"
"settings.c" "settings.c"
"system_wrapper.c" "system_wrapper.c"
@ -24,6 +24,7 @@ idf_component_register(
INCLUDE_DIRS "." INCLUDE_DIRS "."
"include" "include"
"menus" "menus"
"pax-keyboard"
EMBED_TXTFILES ${project_dir}/resources/isrgrootx1.pem EMBED_TXTFILES ${project_dir}/resources/isrgrootx1.pem
EMBED_FILES ${project_dir}/resources/wallpaper.png EMBED_FILES ${project_dir}/resources/wallpaper.png
${project_dir}/resources/fpga_selftest.bin ${project_dir}/resources/fpga_selftest.bin

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, 2048);
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

1
main/pax-keyboard Submodule

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

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;