From 47b046da739ea5a279f92c02a600c13c994ec6d2 Mon Sep 17 00:00:00 2001 From: Clayton Craft Date: Tue, 23 Sep 2025 01:48:35 -0700 Subject: [PATCH] f0rmz: new subproject to create a form/wizard setup thing --- README.md | 2 + buffyboard/command_line.c | 23 +- buffyboard/command_line.h | 15 +- buffyboard/main.c | 12 +- f0rmz/README.md | 147 ++++ f0rmz/command_line.c | 73 ++ f0rmz/command_line.h | 18 + f0rmz/config.c | 216 +++++ f0rmz/config.h | 167 ++++ f0rmz/lv_conf.defaults | 117 +++ f0rmz/lv_conf.h | 1392 +++++++++++++++++++++++++++++++++ f0rmz/main.c | 908 +++++++++++++++++++++ f0rmz/meson.build | 34 + f0rmz/sq2lv_layouts.c | 949 ++++++++++++++++++++++ f0rmz/sq2lv_layouts.h | 61 ++ meson.build | 8 + {unl0kr => shared}/backends.c | 10 +- shared/backends.h | 40 + shared/cli_common.c | 52 ++ shared/cli_common.h | 58 ++ shared/display.c | 91 +++ shared/display.h | 37 + shared/header.c | 88 +++ shared/header.h | 60 ++ shared/keyboard.c | 59 ++ shared/keyboard.h | 19 + {unl0kr => shared}/terminal.c | 4 +- {unl0kr => shared}/terminal.h | 10 +- shared/theme.c | 6 +- unl0kr/backends.h | 40 - unl0kr/command_line.c | 23 +- unl0kr/command_line.h | 17 +- unl0kr/config.c | 6 +- unl0kr/config.h | 4 +- unl0kr/main.c | 164 ++-- unl0kr/meson.build | 4 +- 36 files changed, 4693 insertions(+), 241 deletions(-) create mode 100644 f0rmz/README.md create mode 100644 f0rmz/command_line.c create mode 100644 f0rmz/command_line.h create mode 100644 f0rmz/config.c create mode 100644 f0rmz/config.h create mode 100644 f0rmz/lv_conf.defaults create mode 100644 f0rmz/lv_conf.h create mode 100644 f0rmz/main.c create mode 100644 f0rmz/meson.build create mode 100644 f0rmz/sq2lv_layouts.c create mode 100644 f0rmz/sq2lv_layouts.h rename {unl0kr => shared}/backends.c (65%) create mode 100644 shared/backends.h create mode 100644 shared/cli_common.c create mode 100644 shared/cli_common.h create mode 100644 shared/display.c create mode 100644 shared/display.h create mode 100644 shared/header.c create mode 100644 shared/header.h create mode 100644 shared/keyboard.c create mode 100644 shared/keyboard.h rename {unl0kr => shared}/terminal.c (93%) rename {unl0kr => shared}/terminal.h (65%) delete mode 100644 unl0kr/backends.h diff --git a/README.md b/README.md index 24024d7..2595327 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ BuffyBox is a suite of graphical applications for the terminal. **[unl0kr]** – Disk unlocking UI for the initramfs +**[f0rmz]** – A form/setup wizard for the initramfs + ### Utilities **[squeek2lvgl]** – Converter for transforming [Squeekboard] layouts into [LVGL]-compatible C code diff --git a/buffyboard/command_line.c b/buffyboard/command_line.c index fb8efcc..c5b7b3a 100644 --- a/buffyboard/command_line.c +++ b/buffyboard/command_line.c @@ -39,15 +39,10 @@ static void print_usage(); */ static void init_opts(bb_cli_opts *opts) { + bbx_cli_init_common_opts(&opts->common); opts->num_config_files = 0; opts->config_files = NULL; - opts->hor_res = -1; - opts->ver_res = -1; - opts->x_offset = 0; - opts->y_offset = 0; - opts->dpi = 0; opts->rotation = LV_DISPLAY_ROTATION_0; - opts->verbose = false; int fd_rotate = open("/sys/class/graphics/fbcon/rotate", O_RDONLY); if (fd_rotate < 0) { @@ -148,16 +143,12 @@ void bb_cli_parse_opts(int argc, char *argv[], bb_cli_opts *opts) { opts->num_config_files++; break; case 'g': - if (sscanf(optarg, "%ix%i@%i,%i", &(opts->hor_res), &(opts->ver_res), &(opts->x_offset), &(opts->y_offset)) != 4) { - if (sscanf(optarg, "%ix%i", &(opts->hor_res), &(opts->ver_res)) != 2) { - bbx_log(BBX_LOG_LEVEL_ERROR, "Invalid geometry argument \"%s\"\n", optarg); - exit(EXIT_FAILURE); - } + if (bbx_cli_parse_geometry(optarg, &opts->common) != 0) { + exit(EXIT_FAILURE); } break; case 'd': - if (sscanf(optarg, "%i", &(opts->dpi)) != 1) { - bbx_log(BBX_LOG_LEVEL_ERROR, "Invalid dpi argument \"%s\"\n", optarg); + if (bbx_cli_parse_dpi(optarg, &opts->common) != 0) { exit(EXIT_FAILURE); } break; @@ -187,11 +178,11 @@ void bb_cli_parse_opts(int argc, char *argv[], bb_cli_opts *opts) { print_usage(); exit(EXIT_SUCCESS); case 'v': - opts->verbose = true; + opts->common.verbose = true; break; case 'V': - fprintf(stderr, "buffyboard %s\n", PROJECT_VERSION); - exit(0); + bbx_cli_print_version_and_exit("unl0kr"); + break; default: print_usage(); exit(EXIT_FAILURE); diff --git a/buffyboard/command_line.h b/buffyboard/command_line.h index 009b44f..e5c9290 100644 --- a/buffyboard/command_line.h +++ b/buffyboard/command_line.h @@ -8,29 +8,20 @@ #define BB_COMMAND_LINE_H #include "lvgl/lvgl.h" +#include "../shared/cli_common.h" /** * Options parsed from command line arguments */ typedef struct { + /* Common cli options */ + bbx_cli_common_opts common; /* Number of config files */ int num_config_files; /* Paths of config file */ const char **config_files; - /* Horizontal display resolution */ - int hor_res; - /* Vertical display resolution */ - int ver_res; - /* Horizontal display offset */ - int x_offset; - /* Vertical display offset */ - int y_offset; - /* DPI */ - int dpi; /* Display rotation */ lv_display_rotation_t rotation; - /* Verbose mode. If true, provide more detailed logging output on STDERR. */ - bool verbose; } bb_cli_opts; /** diff --git a/buffyboard/main.c b/buffyboard/main.c index 824c402..97fbbe6 100644 --- a/buffyboard/main.c +++ b/buffyboard/main.c @@ -158,7 +158,7 @@ int main(int argc, char *argv[]) { bb_cli_parse_opts(argc, argv, &cli_opts); /* Set up log level */ - if (cli_opts.verbose) { + if (cli_opts.common.verbose) { bbx_log_set_level(BBX_LOG_LEVEL_VERBOSE); } @@ -194,12 +194,12 @@ int main(int argc, char *argv[]) { lv_display_get_vertical_resolution(disp)); /* Override display properties with command line options if necessary */ - lv_display_set_offset(disp, cli_opts.x_offset, cli_opts.y_offset); - if (cli_opts.hor_res > 0 && cli_opts.ver_res > 0) { - lv_display_set_resolution(disp, cli_opts.hor_res, cli_opts.ver_res); + lv_display_set_offset(disp, cli_opts.common.x_offset, cli_opts.common.y_offset); + if (cli_opts.common.hor_res > 0 && cli_opts.common.ver_res > 0) { + lv_display_set_resolution(disp, cli_opts.common.hor_res, cli_opts.common.ver_res); } - if (cli_opts.dpi > 0) { - lv_display_set_dpi(disp, cli_opts.dpi); + if (cli_opts.common.dpi > 0) { + lv_display_set_dpi(disp, cli_opts.common.dpi); } /* Set up display rotation */ diff --git a/f0rmz/README.md b/f0rmz/README.md new file mode 100644 index 0000000..be3dd8f --- /dev/null +++ b/f0rmz/README.md @@ -0,0 +1,147 @@ +f0rmz +===== + +Form collection tool for the initramfs based on [LVGL]. + +[[_TOC_]] + +# About + +f0rmz is a standalone form collection tool built on [LVGL], with rendering directly to the Linux framebuffer. It shares the same look and feel as [unl0kr] while providing a way to collect structured user input through configurable forms. + +f0rmz was created for use cases like prompting for username, passphrases, and hostname during "first boot" in the initramfs, before creating LUKS partitions or generating configuration files. + +# Status + +f0rmz provides a complete form collection workflow: + +- **Intro Page**: Configurable welcome screen with title and body text +- **Multi-field Forms**: Runtime-configurable forms via INI files using the same format as unl0kr +- **Touch-optimized UI**: One field per page for simplified display on small screens +- **Field Types**: Text and password input fields with validation +- **Summary Screen**: Review all values with click-to-edit capability +- **Input Support**: On-screen keyboard with layout switching, physical keyboard, mouse, and touchscreen +- **Theming**: Light and dark themes with runtime switching (shared with unl0kr) +- **Structured Output**: Key=value pairs printed to stdout for easy parsing + +# Usage + +f0rmz can be invoked with various command line options: + +``` +$ f0rmz --help +Usage: f0rmz [OPTION] + + -C, --config Path to form configuration file + -g, --geometry=NxM[@X,Y] Force display size and offset + -d, --dpi=N Override display DPI + -h, --help Show this help + -v, --verbose Enable verbose logging + -V, --version Show version +``` + +f0rmz reads configuration files in the following order: +- `/usr/share/f0rmz/f0rmz.conf` +- `/usr/share/f0rmz/f0rmz.conf.d/*` (alphabetically) +- `/etc/f0rmz.conf` +- `/etc/f0rmz.conf.d/*` (alphabetically) +- Custom config file (specified with `-C`) + +## Configuration + +### Basic Example + +```ini +[intro] +title=Welcome to postmarketOS! +body=Let's set up your device with a few quick questions. + +[form.username] +type=text +label=Username +required=true + +[form.password] +type=password +label=Password +required=true + +[form.hostname] +type=text +label=Hostname +required=false +``` + +### Configuration Sections + +#### `[intro]` +- `title` - Welcome screen title text +- `body` - Welcome screen body text + +#### `[form.fieldname]` +Define form fields where `fieldname` is the output key name. + +- `type` - Field type: `text` or `password` +- `label` - Display label for the field +- `required` - Whether field is required: `true` or `false` (default: `true`) + +#### Shared Sections +f0rmz supports the same configuration sections as unl0kr for theming, keyboard, and input device settings. See [unl0kr.conf] for examples of `[general]`, `[keyboard]`, `[textarea]`, `[theme]`, `[input]`, and `[quirks]` sections. + +## Navigation Flow + +1. **Intro Page** - Welcome screen with "Get Started" button +2. **Field Pages** - One field per page with Previous/Next navigation +3. **Summary Screen** - Review all values, click any field to edit +4. **Output** - Print `key=value` pairs to stdout and exit + +## Output Format + +f0rmz outputs structured data as key=value pairs: + +``` +username=alice +password=secretpass +hostname=mydevice +``` + +# Development + +## Dependencies + +- [inih] - INI file parsing +- [lvgl] (git submodule / linked statically) +- [squeek2lvgl] (linked statically) +- [libinput] - Input device handling +- [libudev] - Device enumeration +- [libxkbcommon] - Keyboard layout support +- evdev kernel module + +## Backends + +f0rmz uses the same backend system as unl0kr: + +- fbdev (default) +- drm (optional, if [libdrm] is available) + +The active backend can be selected via the `general.backend` option in the configuration file. + +## Keyboard layouts + +f0rmz uses [squeekboard layouts] converted to C via [squeek2lvgl], the same as unl0kr. To regenerate the layouts, ensure that you have pipenv installed and run: + +``` +$ ./regenerate-layouts.sh +``` + +[LVGL]: https://lvgl.io +[unl0kr]: ../unl0kr +[inih]: https://github.com/benhoyt/inih +[lvgl]: https://github.com/lvgl/lvgl +[squeek2lvgl]: ../squeek2lvgl +[libinput]: https://gitlab.freedesktop.org/libinput/libinput +[libudev]: https://github.com/systemd/systemd/tree/main/src/libudev +[libxkbcommon]: https://github.com/xkbcommon/libxkbcommon +[libdrm]: https://gitlab.freedesktop.org/mesa/drm +[squeekboard layouts]: https://gitlab.gnome.org/World/Phosh/squeekboard/-/tree/master/data/keyboards +[unl0kr.conf]: ../unl0kr/unl0kr.conf diff --git a/f0rmz/command_line.c b/f0rmz/command_line.c new file mode 100644 index 0000000..1d9426c --- /dev/null +++ b/f0rmz/command_line.c @@ -0,0 +1,73 @@ +/** + * Copyright 2025 Clayton Craft + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "command_line.h" +#include "../shared/log.h" + +#include +#include +#include + +static void init_opts(f0_cli_opts *opts) { + bbx_cli_init_common_opts(&opts->common); + opts->config_file = NULL; +} + +static void print_usage() { + fprintf(stderr, + "Usage: f0rmz [OPTION]\n" + "\n" + " -C, --config Path to form configuration file\n" + " -g, --geometry=NxM[@X,Y] Force display size and offset\n" + " -d, --dpi=N Override display DPI\n" + " -h, --help Show this help\n" + " -v, --verbose Enable verbose logging\n" + " -V, --version Show version\n"); +} + +void f0_cli_parse_opts(int argc, char *argv[], f0_cli_opts *opts) { + init_opts(opts); + + struct option long_opts[] = { + { "config", required_argument, NULL, 'C' }, + { "geometry", required_argument, NULL, 'g' }, + { "dpi", required_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } + }; + + int opt; + while ((opt = getopt_long(argc, argv, "C:g:d:hvV", long_opts, NULL)) != -1) { + switch (opt) { + case 'C': + opts->config_file = optarg; + break; + case 'g': + if (bbx_cli_parse_geometry(optarg, &opts->common) != 0) { + exit(EXIT_FAILURE); + } + break; + case 'd': + if (bbx_cli_parse_dpi(optarg, &opts->common) != 0) { + exit(EXIT_FAILURE); + } + break; + case 'h': + print_usage(); + exit(EXIT_SUCCESS); + case 'v': + opts->common.verbose = true; + break; + case 'V': + bbx_cli_print_version_and_exit("f0rmz"); + break; + default: + print_usage(); + exit(EXIT_FAILURE); + } + } +} diff --git a/f0rmz/command_line.h b/f0rmz/command_line.h new file mode 100644 index 0000000..7b1f5c6 --- /dev/null +++ b/f0rmz/command_line.h @@ -0,0 +1,18 @@ +/** + * Copyright 2025 Clayton Craft + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef F0_COMMAND_LINE_H +#define F0_COMMAND_LINE_H + +#include "../shared/cli_common.h" + +typedef struct { + bbx_cli_common_opts common; + const char *config_file; +} f0_cli_opts; + +void f0_cli_parse_opts(int argc, char *argv[], f0_cli_opts *opts); + +#endif /* F0_COMMAND_LINE_H */ diff --git a/f0rmz/config.c b/f0rmz/config.c new file mode 100644 index 0000000..a5a4998 --- /dev/null +++ b/f0rmz/config.c @@ -0,0 +1,216 @@ +/** + * Copyright 2025 Clayton Craft + * SPDX-License-Identifier: GPL-3.0-or-later + */ + + +#include "config.h" + +#include "../shared/config.h" +#include "../shared/log.h" +#include "../squeek2lvgl/sq2lv.h" + +#include +#include +#include + +/** + * Static prototypes + */ + +/** + * Handle parsing events from INIH. + * + * @param user_data pointer to user data + * @param section current section name + * @param key option key + * @param value option value + * @return 0 on error, non-0 otherwise + */ +static int parsing_handler(void* user_data, const char* section, const char* key, const char* value); + +/** + * Static functions + */ + +static int parsing_handler(void* user_data, const char* section, const char* key, const char* value) { + f0_config_opts *opts = (f0_config_opts *)user_data; + + if (strcmp(section, "general") == 0) { + if (strcmp(key, "backend") == 0) { + bbx_backends_backend_id_t id = bbx_backends_find_backend_with_name(value); + if (id != BBX_BACKENDS_BACKEND_NONE) { + opts->general.backend = id; + return 1; + } + } + } else if (strcmp(section, "keyboard") == 0) { + if (strcmp(key, "autohide") == 0) { + if (bbx_config_parse_bool(value, &(opts->keyboard.autohide))) { + return 1; + } + } else if (strcmp(key, "layout") == 0) { + sq2lv_layout_id_t id = sq2lv_find_layout_with_short_name(value); + if (id != SQ2LV_LAYOUT_NONE) { + opts->keyboard.layout_id = id; + return 1; + } + } else if (strcmp(key, "popovers") == 0) { + if (bbx_config_parse_bool(value, &(opts->keyboard.popovers))) { + return 1; + } + } + } else if (strcmp(section, "theme") == 0) { + if (strcmp(key, "default") == 0) { + bbx_themes_theme_id_t id = bbx_themes_find_theme_with_name(value); + if (id != BBX_THEMES_THEME_NONE) { + opts->theme.default_id = id; + return 1; + } + } else if (strcmp(key, "alternate") == 0) { + bbx_themes_theme_id_t id = bbx_themes_find_theme_with_name(value); + if (id != BBX_THEMES_THEME_NONE) { + opts->theme.alternate_id = id; + return 1; + } + } + } else if (strcmp(section, "input") == 0) { + if (strcmp(key, "keyboard") == 0) { + if (bbx_config_parse_bool(value, &(opts->input.keyboard))) { + return 1; + } + } else if (strcmp(key, "pointer") == 0) { + if (bbx_config_parse_bool(value, &(opts->input.pointer))) { + return 1; + } + } else if (strcmp(key, "touchscreen") == 0) { + if (bbx_config_parse_bool(value, &(opts->input.touchscreen))) { + return 1; + } + } + } else if (strcmp(section, "quirks") == 0) { + if (strcmp(key, "fbdev_force_refresh") == 0) { + if (bbx_config_parse_bool(value, &(opts->quirks.fbdev_force_refresh))) { + return 1; + } + } else if (strcmp(key, "terminal_prevent_graphics_mode") == 0) { + if (bbx_config_parse_bool(value, &(opts->quirks.terminal_prevent_graphics_mode))) { + return 1; + } + } else if (strcmp(key, "terminal_allow_keyboard_input") == 0) { + if (bbx_config_parse_bool(value, &(opts->quirks.terminal_allow_keyboard_input))) { + return 1; + } + } + } else if (strcmp(section, "intro") == 0) { + if (strcmp(key, "title") == 0) { + char *title = strdup(value); + if (title) { + opts->intro.title = title; + return 1; + } + } else if (strcmp(key, "body") == 0) { + char *body = strdup(value); + if (body) { + opts->intro.body = body; + return 1; + } + } + } else if (strncmp(section, "form.", 5) == 0) { + /* Extract field name */ + const char *field_name = section + 5; + + /* Find or create field */ + f0_form_field_t *field = NULL; + for (int i = 0; i < opts->num_fields; i++) { + if (strcmp(opts->fields[i].name, field_name) == 0) { + field = &opts->fields[i]; + break; + } + } + + if (!field) { + /* Create new field */ + opts->fields = realloc(opts->fields, (opts->num_fields + 1) * sizeof(f0_form_field_t)); + field = &opts->fields[opts->num_fields]; + lv_memzero(field, sizeof(f0_form_field_t)); + field->name = strdup(field_name); + opts->num_fields++; + } + + /* Parse field properties */ + if (strcmp(key, "type") == 0) { + if (strcmp(value, "text") == 0) { + field->type = F0_FIELD_TYPE_TEXT; + return 1; + } else if (strcmp(value, "password") == 0) { + field->type = F0_FIELD_TYPE_PASSWORD; + return 1; + } + } else if (strcmp(key, "label") == 0) { + field->label = strdup(value); + return 1; + } else if (strcmp(key, "required") == 0) { + if (bbx_config_parse_bool(value, &field->required)) { + return 1; + } + } + } + bbx_log(BBX_LOG_LEVEL_ERROR, "Ignoring invalid config value \"%s\" for key \"%s\" in section \"%s\"", value, key, section); + return 1; /* Return 1 (true) so that we can use the return value of ini_parse exclusively for file-level errors */ +} + +/** + * Public functions + */ + +void f0_config_init_opts(f0_config_opts *opts) { + opts->general.backend = bbx_backends_backends[0] == NULL ? BBX_BACKENDS_BACKEND_NONE : 0; + opts->intro.title = "A Form!"; + opts->intro.body = "Please complete the following form."; + opts->theme.default_id = BBX_THEMES_THEME_BREEZY_DARK; + opts->theme.alternate_id = BBX_THEMES_THEME_BREEZY_LIGHT; + opts->keyboard.autohide = true; + opts->keyboard.layout_id = SQ2LV_LAYOUT_US; + opts->keyboard.popovers = true; + opts->textarea.obscured = true; + opts->textarea.bullet = LV_SYMBOL_BULLET; + opts->input.keyboard = true; + opts->input.pointer = true; + opts->input.touchscreen = true; + opts->quirks.fbdev_force_refresh = false; + opts->quirks.terminal_prevent_graphics_mode = false; + opts->quirks.terminal_allow_keyboard_input = false; + opts->fields = NULL; + opts->num_fields = 0; +} + +void f0_config_parse_directory(const char *path, f0_config_opts *opts) { + /* Find files in directory */ + char **found = NULL; + int num_found = 0; + bbx_config_find_files(path, &found, &num_found); + + /* Sort and parse files */ + qsort(found, num_found, sizeof(char *), bbx_config_compare_strings); + f0_config_parse_files((const char **)found, num_found, opts); + + /* Free memory */ + for (int i = 0; i < num_found; ++i) { + free(found[i]); + } + free(found); +} + +void f0_config_parse_files(const char **files, int num_files, f0_config_opts *opts) { + for (int i = 0; i < num_files; ++i) { + f0_config_parse_file(files[i], opts); + } +} + +void f0_config_parse_file(const char *path, f0_config_opts *opts) { + bbx_log(BBX_LOG_LEVEL_VERBOSE, "Parsing config file %s", path); + if (ini_parse(path, parsing_handler, opts) != 0) { + bbx_log(BBX_LOG_LEVEL_ERROR, "Ignoring invalid config file %s", path); + } +} diff --git a/f0rmz/config.h b/f0rmz/config.h new file mode 100644 index 0000000..3d0700d --- /dev/null +++ b/f0rmz/config.h @@ -0,0 +1,167 @@ +/** + * Copyright 2025 Clayton Craft + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef F0_CONFIG_H +#define F0_CONFIG_H + +#include "../shared/backends.h" +#include "../shared/config.h" +#include "../shared/themes.h" + +#include "sq2lv_layouts.h" + +#include +#include + +/** + * General options + */ +typedef struct { + /* Backend to use */ + bbx_backends_backend_id_t backend; +} f0_config_opts_general; + +/** + * Options related to the keyboard + */ +typedef struct { + /* If true, hide the keyboard on launch when a hardware keyboard is connected */ + bool autohide; + /* Keyboard layout */ + sq2lv_layout_id_t layout_id; + /* If true, display key popovers on press */ + bool popovers; +} f0_config_opts_keyboard; + +/** + * Options related to the theme + */ +typedef struct { + /* Default theme */ + bbx_themes_theme_id_t default_id; + /* Alternate theme */ + bbx_themes_theme_id_t alternate_id; +} f0_config_opts_theme; + +/** + * Options related to the password textarea + */ +typedef struct { + /* If true, disguise the entered text with dots */ + bool obscured; + /* The character to use for disguising the entered text */ + const char *bullet; +} f0_config_opts_textarea; + +/** + * Options related to input devices + */ +typedef struct { + /* If true and a keyboard device is connected, use it for input */ + bool keyboard; + /* If true and a pointer device is connected, use it for input */ + bool pointer; + /* If true and a touchscreen device is connected, use it for input */ + bool touchscreen; +} f0_config_opts_input; + +/** + * (Normally unneeded) quirky options + */ +typedef struct { + /* If true and using the framebuffer backend, force a refresh on every draw operation */ + bool fbdev_force_refresh; + /* If true, do *not* switch terminal into graphics mode (will show terminal command prompt) */ + bool terminal_prevent_graphics_mode; + /* If true, do *not* turn off terminal keyboard input (will show entered characters) */ + bool terminal_allow_keyboard_input; +} f0_config_opts_quirks; + +/** + * Form configuration options +*/ + +/** + * Intro section configuration + */ +typedef struct { + /* Welcome screen title */ + const char *title; + /* Welcome screen body text */ + const char *body; +} f0_config_intro; + +/** + * Form field types + */ +typedef enum { + F0_FIELD_TYPE_TEXT, + F0_FIELD_TYPE_PASSWORD +} f0_field_type_t; + +/** + * Form field definition + */ +typedef struct { + char *name; + f0_field_type_t type; + char *label; + bool required; +} f0_form_field_t; + +typedef struct { + /* General options */ + f0_config_opts_general general; + /* Options related to the keyboard */ + f0_config_opts_keyboard keyboard; + /* Options related to the theme */ + f0_config_opts_theme theme; + /* Options related to the password textarea */ + f0_config_opts_textarea textarea; + /* Options related to input devices */ + f0_config_opts_input input; + /* Options related to (normally unneeded) quirks */ + f0_config_opts_quirks quirks; + /* Intro section */ + f0_config_intro intro; + /* Form fields */ + f0_form_field_t *fields; + /* Number of form fields/pages */ + int num_fields; +} f0_config_opts; + +/** + * Initialize config options with default values. + * + * @param opts pointer to the options struct + */ +void f0_config_init_opts(f0_config_opts *opts); + +/** + * Find configuration files in a directory and parse them in alphabetic order. + * + * @param path directory path + * @param opts pointer for writing the parsed options into + */ +void f0_config_parse_directory(const char *path, f0_config_opts *opts); + +/** + * Parse one or more configuration files. + * + * @param files paths to configuration files + * @param num_files number of configuration files + * @param opts pointer for writing the parsed options into + */ +void f0_config_parse_files(const char **files, int num_files, f0_config_opts *opts); + +/** + * Parse a configuration file. + * + * @param path path to configuration file + * @param opts pointer for writing the parsed options into + */ +void f0_config_parse_file(const char *path, f0_config_opts *opts); + +#endif /* F0_CONFIG_H */ diff --git a/f0rmz/lv_conf.defaults b/f0rmz/lv_conf.defaults new file mode 100644 index 0000000..4b81a39 --- /dev/null +++ b/f0rmz/lv_conf.defaults @@ -0,0 +1,117 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +# Manual post-processing steps for the generated lv_conf.h +# 1. Comment LV_USE_LINUX_DRM (handled by meson.build) +# 2. Remove LV_BIG_ENDIAN_SYSTEM (handled by meson.build) +# 3. Add `#define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(bbx_font_32)` (a bug in generate_lv_conf.py) + +LV_COLOR_DEPTH 32 +LV_USE_STDLIB_MALLOC LV_STDLIB_CLIB +LV_USE_STDLIB_STRING LV_STDLIB_CLIB +LV_USE_STDLIB_SPRINTF LV_STDLIB_CLIB + +LV_USE_DRAW_SW 1 +LV_DRAW_SW_COMPLEX 1 +LV_DRAW_SW_SUPPORT_RGB565 0 +LV_DRAW_SW_SUPPORT_RGB565_SWAPPED 0 +LV_DRAW_SW_SUPPORT_RGB565A8 0 +LV_DRAW_SW_SUPPORT_RGB888 1 +LV_DRAW_SW_SUPPORT_XRGB8888 1 +LV_DRAW_SW_SUPPORT_ARGB8888 1 +LV_DRAW_SW_SUPPORT_ARGB8888_PREMULTIPLIED 0 +LV_DRAW_SW_SUPPORT_L8 0 +LV_DRAW_SW_SUPPORT_AL88 0 +LV_DRAW_SW_SUPPORT_A8 0 +LV_DRAW_SW_SUPPORT_I1 0 + +LV_USE_LOG 1 +LV_LOG_LEVEL LV_LOG_LEVEL_WARN +LV_USE_PRIVATE_API 1 + +LV_FONT_MONTSERRAT_8 0 +LV_FONT_MONTSERRAT_10 0 +LV_FONT_MONTSERRAT_12 0 +LV_FONT_MONTSERRAT_14 0 +LV_FONT_MONTSERRAT_16 0 +LV_FONT_MONTSERRAT_18 0 +LV_FONT_MONTSERRAT_20 0 +LV_FONT_MONTSERRAT_22 0 +LV_FONT_MONTSERRAT_24 0 +LV_FONT_MONTSERRAT_26 0 +LV_FONT_MONTSERRAT_28 0 +LV_FONT_MONTSERRAT_30 0 +LV_FONT_MONTSERRAT_32 0 +LV_FONT_MONTSERRAT_34 0 +LV_FONT_MONTSERRAT_36 0 +LV_FONT_MONTSERRAT_38 0 +LV_FONT_MONTSERRAT_40 0 +LV_FONT_MONTSERRAT_42 0 +LV_FONT_MONTSERRAT_44 0 +LV_FONT_MONTSERRAT_46 0 +LV_FONT_MONTSERRAT_48 0 +LV_FONT_MONTSERRAT_28_COMPRESSED 0 +LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 +LV_FONT_SIMSUN_14_CJK 0 +LV_FONT_SIMSUN_16_CJK 0 +LV_FONT_UNSCII_8 0 +LV_FONT_UNSCII_16 0 + +#LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(bbx_font_32) +LV_FONT_DEFAULT &bbx_font_32 + +LV_WIDGETS_HAS_DEFAULT_VALUE 0 +LV_USE_ANIMIMG 0 +LV_USE_ARC 0 +LV_USE_BAR 0 +LV_USE_BUTTON 1 +LV_USE_BUTTONMATRIX 1 +LV_USE_CALENDAR 0 +LV_USE_CANVAS 0 +LV_USE_CHART 0 +LV_USE_CHECKBOX 0 +LV_USE_DROPDOWN 1 +LV_USE_IMAGE 1 +LV_USE_IMAGEBUTTON 0 +LV_USE_KEYBOARD 1 +LV_USE_LABEL 1 +LV_LABEL_TEXT_SELECTION 0 +LV_LABEL_LONG_TXT_HINT 0 +LV_USE_LED 0 +LV_USE_LINE 0 +LV_USE_LIST 0 +LV_USE_LOTTIE 0 +LV_USE_MENU 0 +LV_USE_MSGBOX 1 +LV_USE_ROLLER 0 +LV_USE_SCALE 0 +LV_USE_SLIDER 0 +LV_USE_SPAN 0 +LV_USE_SPINBOX 0 +LV_USE_SPINNER 0 +LV_USE_SWITCH 0 +LV_USE_TEXTAREA 1 +LV_TEXTAREA_DEF_PWD_SHOW_TIME 0 /*ms*/ +LV_USE_TABLE 0 +LV_USE_TABVIEW 0 +LV_USE_TILEVIEW 0 +LV_USE_WIN 0 + +LV_USE_THEME_DEFAULT 0 +LV_USE_THEME_SIMPLE 0 +LV_USE_THEME_MONO 0 + +LV_USE_FLEX 1 +LV_USE_GRID 0 + +LV_USE_LINUX_FBDEV 1 +LV_LINUX_FBDEV_BSD 0 +LV_LINUX_FBDEV_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL + +LV_USE_LINUX_DRM 0 + +LV_USE_LIBINPUT 1 +LV_LIBINPUT_BSD 0 +LV_LIBINPUT_XKB 1 + +LV_BUILD_EXAMPLES 0 +LV_BUILD_DEMOS 0 diff --git a/f0rmz/lv_conf.h b/f0rmz/lv_conf.h new file mode 100644 index 0000000..94bd31d --- /dev/null +++ b/f0rmz/lv_conf.h @@ -0,0 +1,1392 @@ +/** + * @file lv_conf.h + * Configuration file for v9.3.0 + */ + +/* + * Copy this file as `lv_conf.h` + * 1. simply next to `lvgl` folder + * 2. or to any other place and + * - define `LV_CONF_INCLUDE_SIMPLE`; + * - add the path as an include path. + */ + +/* clang-format off */ +#if 1 /* Enable content */ +#ifndef LV_CONF_H +#define LV_CONF_H + +/* If you need to include anything here, do it inside the `__ASSEMBLY__` guard */ +#if 0 && defined(__ASSEMBLY__) +#include "my_include.h" +#endif + +/*==================== + COLOR SETTINGS + *====================*/ + +/** Color depth: 1 (I1), 8 (L8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888) */ +#define LV_COLOR_DEPTH 32 + +/*========================= + STDLIB WRAPPER SETTINGS + *=========================*/ + +/** Possible values + * - LV_STDLIB_BUILTIN: LVGL's built in implementation + * - LV_STDLIB_CLIB: Standard C functions, like malloc, strlen, etc + * - LV_STDLIB_MICROPYTHON: MicroPython implementation + * - LV_STDLIB_RTTHREAD: RT-Thread implementation + * - LV_STDLIB_CUSTOM: Implement the functions externally + */ +#define LV_USE_STDLIB_MALLOC LV_STDLIB_CLIB + +/** Possible values + * - LV_STDLIB_BUILTIN: LVGL's built in implementation + * - LV_STDLIB_CLIB: Standard C functions, like malloc, strlen, etc + * - LV_STDLIB_MICROPYTHON: MicroPython implementation + * - LV_STDLIB_RTTHREAD: RT-Thread implementation + * - LV_STDLIB_CUSTOM: Implement the functions externally + */ +#define LV_USE_STDLIB_STRING LV_STDLIB_CLIB + +/** Possible values + * - LV_STDLIB_BUILTIN: LVGL's built in implementation + * - LV_STDLIB_CLIB: Standard C functions, like malloc, strlen, etc + * - LV_STDLIB_MICROPYTHON: MicroPython implementation + * - LV_STDLIB_RTTHREAD: RT-Thread implementation + * - LV_STDLIB_CUSTOM: Implement the functions externally + */ +#define LV_USE_STDLIB_SPRINTF LV_STDLIB_CLIB + +#define LV_STDINT_INCLUDE +#define LV_STDDEF_INCLUDE +#define LV_STDBOOL_INCLUDE +#define LV_INTTYPES_INCLUDE +#define LV_LIMITS_INCLUDE +#define LV_STDARG_INCLUDE + +#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN + /** Size of memory available for `lv_malloc()` in bytes (>= 2kB) */ + #define LV_MEM_SIZE (64 * 1024U) /**< [bytes] */ + + /** Size of the memory expand for `lv_malloc()` in bytes */ + #define LV_MEM_POOL_EXPAND_SIZE 0 + + /** Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too. */ + #define LV_MEM_ADR 0 /**< 0: unused*/ + /* Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc */ + #if LV_MEM_ADR == 0 + #undef LV_MEM_POOL_INCLUDE + #undef LV_MEM_POOL_ALLOC + #endif +#endif /*LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN*/ + +/*==================== + HAL SETTINGS + *====================*/ + +/** Default display refresh, input device read and animation step period. */ +#define LV_DEF_REFR_PERIOD 33 /**< [ms] */ + +/** Default Dots Per Inch. Used to initialize default sizes such as widgets sized, style paddings. + * (Not so important, you can adjust it to modify default sizes and spaces.) */ +#define LV_DPI_DEF 130 /**< [px/inch] */ + +/*================= + * OPERATING SYSTEM + *=================*/ +/** Select operating system to use. Possible options: + * - LV_OS_NONE + * - LV_OS_PTHREAD + * - LV_OS_FREERTOS + * - LV_OS_CMSIS_RTOS2 + * - LV_OS_RTTHREAD + * - LV_OS_WINDOWS + * - LV_OS_MQX + * - LV_OS_SDL2 + * - LV_OS_CUSTOM */ +#define LV_USE_OS LV_OS_NONE + +#if LV_USE_OS == LV_OS_CUSTOM + #define LV_OS_CUSTOM_INCLUDE +#endif +#if LV_USE_OS == LV_OS_FREERTOS + /* + * Unblocking an RTOS task with a direct notification is 45% faster and uses less RAM + * than unblocking a task using an intermediary object such as a binary semaphore. + * RTOS task notifications can only be used when there is only one task that can be the recipient of the event. + */ + #define LV_USE_FREERTOS_TASK_NOTIFY 1 +#endif + +/*======================== + * RENDERING CONFIGURATION + *========================*/ + +/** Align stride of all layers and images to this bytes */ +#define LV_DRAW_BUF_STRIDE_ALIGN 1 + +/** Align start address of draw_buf addresses to this bytes*/ +#define LV_DRAW_BUF_ALIGN 4 + +/** Using matrix for transformations. + * Requirements: + * - `LV_USE_MATRIX = 1`. + * - Rendering engine needs to support 3x3 matrix transformations. */ +#define LV_DRAW_TRANSFORM_USE_MATRIX 0 + +/* If a widget has `style_opa < 255` (not `bg_opa`, `text_opa` etc) or not NORMAL blend mode + * it is buffered into a "simple" layer before rendering. The widget can be buffered in smaller chunks. + * "Transformed layers" (if `transform_angle/zoom` are set) use larger buffers + * and can't be drawn in chunks. */ + +/** The target buffer size for simple layer chunks. */ +#define LV_DRAW_LAYER_SIMPLE_BUF_SIZE (24 * 1024) /**< [bytes]*/ + +/* Limit the max allocated memory for simple and transformed layers. + * It should be at least `LV_DRAW_LAYER_SIMPLE_BUF_SIZE` sized but if transformed layers are also used + * it should be enough to store the largest widget too (width x height x 4 area). + * Set it to 0 to have no limit. */ +#define LV_DRAW_LAYER_MAX_MEMORY 0 /**< No limit by default [bytes]*/ + +/** Stack size of drawing thread. + * NOTE: If FreeType or ThorVG is enabled, it is recommended to set it to 32KB or more. + */ +#define LV_DRAW_THREAD_STACK_SIZE (8 * 1024) /**< [bytes]*/ + +/** Thread priority of the drawing task. + * Higher values mean higher priority. + * Can use values from lv_thread_prio_t enum in lv_os.h: LV_THREAD_PRIO_LOWEST, + * LV_THREAD_PRIO_LOW, LV_THREAD_PRIO_MID, LV_THREAD_PRIO_HIGH, LV_THREAD_PRIO_HIGHEST + * Make sure the priority value aligns with the OS-specific priority levels. + * On systems with limited priority levels (e.g., FreeRTOS), a higher value can improve + * rendering performance but might cause other tasks to starve. */ +#define LV_DRAW_THREAD_PRIO LV_THREAD_PRIO_HIGH + +#define LV_USE_DRAW_SW 1 +#if LV_USE_DRAW_SW == 1 + /* + * Selectively disable color format support in order to reduce code size. + * NOTE: some features use certain color formats internally, e.g. + * - gradients use RGB888 + * - bitmaps with transparency may use ARGB8888 + */ + #define LV_DRAW_SW_SUPPORT_RGB565 0 + #define LV_DRAW_SW_SUPPORT_RGB565_SWAPPED 0 + #define LV_DRAW_SW_SUPPORT_RGB565A8 0 + #define LV_DRAW_SW_SUPPORT_RGB888 1 + #define LV_DRAW_SW_SUPPORT_XRGB8888 1 + #define LV_DRAW_SW_SUPPORT_ARGB8888 1 + #define LV_DRAW_SW_SUPPORT_ARGB8888_PREMULTIPLIED 0 + #define LV_DRAW_SW_SUPPORT_L8 0 + #define LV_DRAW_SW_SUPPORT_AL88 0 + #define LV_DRAW_SW_SUPPORT_A8 0 + #define LV_DRAW_SW_SUPPORT_I1 0 + + /* The threshold of the luminance to consider a pixel as + * active in indexed color format */ + #define LV_DRAW_SW_I1_LUM_THRESHOLD 127 + + /** Set number of draw units. + * - > 1 requires operating system to be enabled in `LV_USE_OS`. + * - > 1 means multiple threads will render the screen in parallel. */ + #define LV_DRAW_SW_DRAW_UNIT_CNT 1 + + /** Use Arm-2D to accelerate software (sw) rendering. */ + #define LV_USE_DRAW_ARM2D_SYNC 0 + + /** Enable native helium assembly to be compiled. */ + #define LV_USE_NATIVE_HELIUM_ASM 0 + + /** + * - 0: Use a simple renderer capable of drawing only simple rectangles with gradient, images, text, and straight lines only. + * - 1: Use a complex renderer capable of drawing rounded corners, shadow, skew lines, and arcs too. */ + #define LV_DRAW_SW_COMPLEX 1 + + #if LV_DRAW_SW_COMPLEX == 1 + /** Allow buffering some shadow calculation. + * LV_DRAW_SW_SHADOW_CACHE_SIZE is the maximum shadow size to buffer, where shadow size is + * `shadow_width + radius`. Caching has LV_DRAW_SW_SHADOW_CACHE_SIZE^2 RAM cost. */ + #define LV_DRAW_SW_SHADOW_CACHE_SIZE 0 + + /** Set number of maximally-cached circle data. + * The circumference of 1/4 circle are saved for anti-aliasing. + * `radius * 4` bytes are used per circle (the most often used radiuses are saved). + * - 0: disables caching */ + #define LV_DRAW_SW_CIRCLE_CACHE_SIZE 4 + #endif + + #define LV_USE_DRAW_SW_ASM LV_DRAW_SW_ASM_NONE + + #if LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_CUSTOM + #define LV_DRAW_SW_ASM_CUSTOM_INCLUDE "" + #endif + + /** Enable drawing complex gradients in software: linear at an angle, radial or conical */ + #define LV_USE_DRAW_SW_COMPLEX_GRADIENTS 0 + +#endif + +/*Use TSi's aka (Think Silicon) NemaGFX */ +#define LV_USE_NEMA_GFX 0 + +#if LV_USE_NEMA_GFX + /** Select which NemaGFX HAL to use. Possible options: + * - LV_NEMA_HAL_CUSTOM + * - LV_NEMA_HAL_STM32 */ + #define LV_USE_NEMA_HAL LV_NEMA_HAL_CUSTOM + #if LV_USE_NEMA_HAL == LV_NEMA_HAL_STM32 + #define LV_NEMA_STM32_HAL_INCLUDE + #endif + + /*Enable Vector Graphics Operations. Available only if NemaVG library is present*/ + #define LV_USE_NEMA_VG 0 + #if LV_USE_NEMA_VG + /*Define application's resolution used for VG related buffer allocation */ + #define LV_NEMA_GFX_MAX_RESX 800 + #define LV_NEMA_GFX_MAX_RESY 600 + #endif +#endif + +/** Use NXP's VG-Lite GPU on iMX RTxxx platforms. */ +#define LV_USE_DRAW_VGLITE 0 + +#if LV_USE_DRAW_VGLITE + /** Enable blit quality degradation workaround recommended for screen's dimension > 352 pixels. */ + #define LV_USE_VGLITE_BLIT_SPLIT 0 + + #if LV_USE_OS + /** Use additional draw thread for VG-Lite processing. */ + #define LV_USE_VGLITE_DRAW_THREAD 1 + + #if LV_USE_VGLITE_DRAW_THREAD + /** Enable VGLite draw async. Queue multiple tasks and flash them once to the GPU. */ + #define LV_USE_VGLITE_DRAW_ASYNC 1 + #endif + #endif + + /** Enable VGLite asserts. */ + #define LV_USE_VGLITE_ASSERT 0 + + /** Enable VGLite error checks. */ + #define LV_USE_VGLITE_CHECK_ERROR 0 +#endif + +/** Use NXP's PXP on iMX RTxxx platforms. */ +#define LV_USE_PXP 0 + +#if LV_USE_PXP + /** Use PXP for drawing.*/ + #define LV_USE_DRAW_PXP 1 + + /** Use PXP to rotate display.*/ + #define LV_USE_ROTATE_PXP 0 + + #if LV_USE_DRAW_PXP && LV_USE_OS + /** Use additional draw thread for PXP processing.*/ + #define LV_USE_PXP_DRAW_THREAD 1 + #endif + + /** Enable PXP asserts. */ + #define LV_USE_PXP_ASSERT 0 +#endif + +/** Use NXP's G2D on MPU platforms. */ +#define LV_USE_DRAW_G2D 0 + +#if LV_USE_DRAW_G2D + /** Maximum number of buffers that can be stored for G2D draw unit. + * Includes the frame buffers and assets. */ + #define LV_G2D_HASH_TABLE_SIZE 50 + + #if LV_USE_OS + /** Use additional draw thread for G2D processing.*/ + #define LV_USE_G2D_DRAW_THREAD 1 + #endif + + /** Enable G2D asserts. */ + #define LV_USE_G2D_ASSERT 0 +#endif + +/** Use Renesas Dave2D on RA platforms. */ +#define LV_USE_DRAW_DAVE2D 0 + +/** Draw using cached SDL textures*/ +#define LV_USE_DRAW_SDL 0 + +/** Use VG-Lite GPU. */ +#define LV_USE_DRAW_VG_LITE 0 + +#if LV_USE_DRAW_VG_LITE + /** Enable VG-Lite custom external 'gpu_init()' function */ + #define LV_VG_LITE_USE_GPU_INIT 0 + + /** Enable VG-Lite assert. */ + #define LV_VG_LITE_USE_ASSERT 0 + + /** VG-Lite flush commit trigger threshold. GPU will try to batch these many draw tasks. */ + #define LV_VG_LITE_FLUSH_MAX_COUNT 8 + + /** Enable border to simulate shadow. + * NOTE: which usually improves performance, + * but does not guarantee the same rendering quality as the software. */ + #define LV_VG_LITE_USE_BOX_SHADOW 1 + + /** VG-Lite gradient maximum cache number. + * @note The memory usage of a single gradient image is 4K bytes. */ + #define LV_VG_LITE_GRAD_CACHE_CNT 32 + + /** VG-Lite stroke maximum cache number. */ + #define LV_VG_LITE_STROKE_CACHE_CNT 32 +#endif + +/** Accelerate blends, fills, etc. with STM32 DMA2D */ +#define LV_USE_DRAW_DMA2D 0 + +#if LV_USE_DRAW_DMA2D + #define LV_DRAW_DMA2D_HAL_INCLUDE "stm32h7xx_hal.h" + + /* if enabled, the user is required to call `lv_draw_dma2d_transfer_complete_interrupt_handler` + * upon receiving the DMA2D global interrupt + */ + #define LV_USE_DRAW_DMA2D_INTERRUPT 0 +#endif + +/** Draw using cached OpenGLES textures */ +#define LV_USE_DRAW_OPENGLES 0 + +/*======================= + * FEATURE CONFIGURATION + *=======================*/ + +/*------------- + * Logging + *-----------*/ + +/** Enable log module */ +#define LV_USE_LOG 1 +#if LV_USE_LOG + /** Set value to one of the following levels of logging detail: + * - LV_LOG_LEVEL_TRACE Log detailed information. + * - LV_LOG_LEVEL_INFO Log important events. + * - LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem. + * - LV_LOG_LEVEL_ERROR Log only critical issues, when system may fail. + * - LV_LOG_LEVEL_USER Log only custom log messages added by the user. + * - LV_LOG_LEVEL_NONE Do not log anything. */ + #define LV_LOG_LEVEL LV_LOG_LEVEL_WARN + + /** - 1: Print log with 'printf'; + * - 0: User needs to register a callback with `lv_log_register_print_cb()`. */ + #define LV_LOG_PRINTF 0 + + /** Set callback to print logs. + * E.g `my_print`. The prototype should be `void my_print(lv_log_level_t level, const char * buf)`. + * Can be overwritten by `lv_log_register_print_cb`. */ + //#define LV_LOG_PRINT_CB + + /** - 1: Enable printing timestamp; + * - 0: Disable printing timestamp. */ + #define LV_LOG_USE_TIMESTAMP 1 + + /** - 1: Print file and line number of the log; + * - 0: Do not print file and line number of the log. */ + #define LV_LOG_USE_FILE_LINE 1 + + /* Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs. */ + #define LV_LOG_TRACE_MEM 1 /**< Enable/disable trace logs in memory operations. */ + #define LV_LOG_TRACE_TIMER 1 /**< Enable/disable trace logs in timer operations. */ + #define LV_LOG_TRACE_INDEV 1 /**< Enable/disable trace logs in input device operations. */ + #define LV_LOG_TRACE_DISP_REFR 1 /**< Enable/disable trace logs in display re-draw operations. */ + #define LV_LOG_TRACE_EVENT 1 /**< Enable/disable trace logs in event dispatch logic. */ + #define LV_LOG_TRACE_OBJ_CREATE 1 /**< Enable/disable trace logs in object creation (core `obj` creation plus every widget). */ + #define LV_LOG_TRACE_LAYOUT 1 /**< Enable/disable trace logs in flex- and grid-layout operations. */ + #define LV_LOG_TRACE_ANIM 1 /**< Enable/disable trace logs in animation logic. */ + #define LV_LOG_TRACE_CACHE 1 /**< Enable/disable trace logs in cache operations. */ +#endif /*LV_USE_LOG*/ + +/*------------- + * Asserts + *-----------*/ + +/* Enable assertion failures if an operation fails or invalid data is found. + * If LV_USE_LOG is enabled, an error message will be printed on failure. */ +#define LV_USE_ASSERT_NULL 1 /**< Check if the parameter is NULL. (Very fast, recommended) */ +#define LV_USE_ASSERT_MALLOC 1 /**< Checks is the memory is successfully allocated or no. (Very fast, recommended) */ +#define LV_USE_ASSERT_STYLE 0 /**< Check if the styles are properly initialized. (Very fast, recommended) */ +#define LV_USE_ASSERT_MEM_INTEGRITY 0 /**< Check the integrity of `lv_mem` after critical operations. (Slow) */ +#define LV_USE_ASSERT_OBJ 0 /**< Check the object's type and existence (e.g. not deleted). (Slow) */ + +/** Add a custom handler when assert happens e.g. to restart MCU. */ +#define LV_ASSERT_HANDLER_INCLUDE +#define LV_ASSERT_HANDLER while(1); /**< Halt by default */ + +/*------------- + * Debug + *-----------*/ + +/** 1: Draw random colored rectangles over the redrawn areas. */ +#define LV_USE_REFR_DEBUG 0 + +/** 1: Draw a red overlay for ARGB layers and a green overlay for RGB layers*/ +#define LV_USE_LAYER_DEBUG 0 + +/** 1: Adds the following behaviors for debugging: + * - Draw overlays with different colors for each draw_unit's tasks. + * - Draw index number of draw unit on white background. + * - For layers, draws index number of draw unit on black background. */ +#define LV_USE_PARALLEL_DRAW_DEBUG 0 + +/*------------- + * Others + *-----------*/ + +#define LV_ENABLE_GLOBAL_CUSTOM 0 +#if LV_ENABLE_GLOBAL_CUSTOM + /** Header to include for custom 'lv_global' function" */ + #define LV_GLOBAL_CUSTOM_INCLUDE +#endif + +/** Default cache size in bytes. + * Used by image decoders such as `lv_lodepng` to keep the decoded image in memory. + * If size is not set to 0, the decoder will fail to decode when the cache is full. + * If size is 0, the cache function is not enabled and the decoded memory will be + * released immediately after use. */ +#define LV_CACHE_DEF_SIZE 0 + +/** Default number of image header cache entries. The cache is used to store the headers of images + * The main logic is like `LV_CACHE_DEF_SIZE` but for image headers. */ +#define LV_IMAGE_HEADER_CACHE_DEF_CNT 0 + +/** Number of stops allowed per gradient. Increase this to allow more stops. + * This adds (sizeof(lv_color_t) + 1) bytes per additional stop. */ +#define LV_GRADIENT_MAX_STOPS 2 + +/** Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently. + * - 0: round down, + * - 64: round up from x.75, + * - 128: round up from half, + * - 192: round up from x.25, + * - 254: round up */ +#define LV_COLOR_MIX_ROUND_OFS 0 + +/** Add 2 x 32-bit variables to each `lv_obj_t` to speed up getting style properties */ +#define LV_OBJ_STYLE_CACHE 0 + +/** Add `id` field to `lv_obj_t` */ +#define LV_USE_OBJ_ID 0 + +/** Enable support widget names*/ +#define LV_USE_OBJ_NAME 0 + +/** Automatically assign an ID when obj is created */ +#define LV_OBJ_ID_AUTO_ASSIGN LV_USE_OBJ_ID + +/** Use builtin obj ID handler functions: +* - lv_obj_assign_id: Called when a widget is created. Use a separate counter for each widget class as an ID. +* - lv_obj_id_compare: Compare the ID to decide if it matches with a requested value. +* - lv_obj_stringify_id: Return string-ified identifier, e.g. "button3". +* - lv_obj_free_id: Does nothing, as there is no memory allocation for the ID. +* When disabled these functions needs to be implemented by the user.*/ +#define LV_USE_OBJ_ID_BUILTIN 1 + +/** Use obj property set/get API. */ +#define LV_USE_OBJ_PROPERTY 0 + +/** Enable property name support. */ +#define LV_USE_OBJ_PROPERTY_NAME 1 + +/* Use VG-Lite Simulator. + * - Requires: LV_USE_THORVG_INTERNAL or LV_USE_THORVG_EXTERNAL */ +#define LV_USE_VG_LITE_THORVG 0 + +#if LV_USE_VG_LITE_THORVG + /** Enable LVGL's blend mode support */ + #define LV_VG_LITE_THORVG_LVGL_BLEND_SUPPORT 0 + + /** Enable YUV color format support */ + #define LV_VG_LITE_THORVG_YUV_SUPPORT 0 + + /** Enable Linear gradient extension support */ + #define LV_VG_LITE_THORVG_LINEAR_GRADIENT_EXT_SUPPORT 0 + + /** Enable alignment on 16 pixels */ + #define LV_VG_LITE_THORVG_16PIXELS_ALIGN 1 + + /** Buffer address alignment */ + #define LV_VG_LITE_THORVG_BUF_ADDR_ALIGN 64 + + /** Enable multi-thread render */ + #define LV_VG_LITE_THORVG_THREAD_RENDER 0 +#endif + +/* Enable the multi-touch gesture recognition feature */ +/* Gesture recognition requires the use of floats */ +#define LV_USE_GESTURE_RECOGNITION 0 + +/*===================== + * COMPILER SETTINGS + *====================*/ + +/** Define a custom attribute for `lv_tick_inc` function */ +#define LV_ATTRIBUTE_TICK_INC + +/** Define a custom attribute for `lv_timer_handler` function */ +#define LV_ATTRIBUTE_TIMER_HANDLER + +/** Define a custom attribute for `lv_display_flush_ready` function */ +#define LV_ATTRIBUTE_FLUSH_READY + +/** Align VG_LITE buffers on this number of bytes. + * @note vglite_src_buf_aligned() uses this value to validate alignment of passed buffer pointers. */ +#define LV_ATTRIBUTE_MEM_ALIGN_SIZE 1 + +/** Will be added where memory needs to be aligned (with -Os data might not be aligned to boundary by default). + * E.g. __attribute__((aligned(4)))*/ +#define LV_ATTRIBUTE_MEM_ALIGN + +/** Attribute to mark large constant arrays, for example for font bitmaps */ +#define LV_ATTRIBUTE_LARGE_CONST + +/** Compiler prefix for a large array declaration in RAM */ +#define LV_ATTRIBUTE_LARGE_RAM_ARRAY + +/** Place performance critical functions into a faster memory (e.g RAM) */ +#define LV_ATTRIBUTE_FAST_MEM + +/** Export integer constant to binding. This macro is used with constants in the form of LV_ that + * should also appear on LVGL binding API such as MicroPython. */ +#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /**< The default value just prevents GCC warning */ + +/** Prefix all global extern data with this */ +#define LV_ATTRIBUTE_EXTERN_DATA + +/** Use `float` as `lv_value_precise_t` */ +#define LV_USE_FLOAT 0 + +/** Enable matrix support + * - Requires `LV_USE_FLOAT = 1` */ +#define LV_USE_MATRIX 0 + +/** Include `lvgl_private.h` in `lvgl.h` to access internal data and functions by default */ +#ifndef LV_USE_PRIVATE_API + #define LV_USE_PRIVATE_API 1 +#endif + +/*================== + * FONT USAGE + *===================*/ + +/* Montserrat fonts with ASCII range and some symbols using bpp = 4 + * https://fonts.google.com/specimen/Montserrat */ +#define LV_FONT_MONTSERRAT_8 0 +#define LV_FONT_MONTSERRAT_10 0 +#define LV_FONT_MONTSERRAT_12 0 +#define LV_FONT_MONTSERRAT_14 0 +#define LV_FONT_MONTSERRAT_16 0 +#define LV_FONT_MONTSERRAT_18 0 +#define LV_FONT_MONTSERRAT_20 0 +#define LV_FONT_MONTSERRAT_22 0 +#define LV_FONT_MONTSERRAT_24 0 +#define LV_FONT_MONTSERRAT_26 0 +#define LV_FONT_MONTSERRAT_28 0 +#define LV_FONT_MONTSERRAT_30 0 +#define LV_FONT_MONTSERRAT_32 0 +#define LV_FONT_MONTSERRAT_34 0 +#define LV_FONT_MONTSERRAT_36 0 +#define LV_FONT_MONTSERRAT_38 0 +#define LV_FONT_MONTSERRAT_40 0 +#define LV_FONT_MONTSERRAT_42 0 +#define LV_FONT_MONTSERRAT_44 0 +#define LV_FONT_MONTSERRAT_46 0 +#define LV_FONT_MONTSERRAT_48 0 + +/* Demonstrate special features */ +#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 +#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 +#define LV_FONT_SIMSUN_14_CJK 0 +#define LV_FONT_SIMSUN_16_CJK 0 +#define LV_FONT_SOURCE_HAN_SANS_SC_14_CJK 0 /**< 1338 most common CJK radicals */ +#define LV_FONT_SOURCE_HAN_SANS_SC_16_CJK 0 /**< 1338 most common CJK radicals */ + +/** Pixel perfect monospaced fonts */ +#define LV_FONT_UNSCII_8 0 +#define LV_FONT_UNSCII_16 0 + +/** Optionally declare custom fonts here. + * + * You can use any of these fonts as the default font too and they will be available + * globally. Example: + * + * @code + * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2) + * @endcode + */ +#define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(bbx_font_32) + +/** Always set a default font */ +#define LV_FONT_DEFAULT &bbx_font_32 + +/** Enable handling large font and/or fonts with a lot of characters. + * The limit depends on the font size, font face and bpp. + * A compiler error will be triggered if a font needs it. */ +#define LV_FONT_FMT_TXT_LARGE 0 + +/** Enables/disables support for compressed fonts. */ +#define LV_USE_FONT_COMPRESSED 0 + +/** Enable drawing placeholders when glyph dsc is not found. */ +#define LV_USE_FONT_PLACEHOLDER 1 + +/*================= + * TEXT SETTINGS + *=================*/ + +/** + * Select a character encoding for strings. + * Your IDE or editor should have the same character encoding. + * - LV_TXT_ENC_UTF8 + * - LV_TXT_ENC_ASCII + */ +#define LV_TXT_ENC LV_TXT_ENC_UTF8 + +/** While rendering text strings, break (wrap) text on these chars. */ +#define LV_TXT_BREAK_CHARS " ,.;:-_)]}" + +/** If a word is at least this long, will break wherever "prettiest". + * To disable, set to a value <= 0. */ +#define LV_TXT_LINE_BREAK_LONG_LEN 0 + +/** Minimum number of characters in a long word to put on a line before a break. + * Depends on LV_TXT_LINE_BREAK_LONG_LEN. */ +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 + +/** Minimum number of characters in a long word to put on a line after a break. + * Depends on LV_TXT_LINE_BREAK_LONG_LEN. */ +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 + +/** Support bidirectional text. Allows mixing Left-to-Right and Right-to-Left text. + * The direction will be processed according to the Unicode Bidirectional Algorithm: + * https://www.w3.org/International/articles/inline-bidi-markup/uba-basics */ +#define LV_USE_BIDI 0 +#if LV_USE_BIDI + /*Set the default direction. Supported values: + *`LV_BASE_DIR_LTR` Left-to-Right + *`LV_BASE_DIR_RTL` Right-to-Left + *`LV_BASE_DIR_AUTO` detect text base direction*/ + #define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO +#endif + +/** Enable Arabic/Persian processing + * In these languages characters should be replaced with another form based on their position in the text */ +#define LV_USE_ARABIC_PERSIAN_CHARS 0 + +/*The control character to use for signaling text recoloring*/ +#define LV_TXT_COLOR_CMD "#" + +/*================== + * WIDGETS + *================*/ +/* Documentation for widgets can be found here: https://docs.lvgl.io/master/details/widgets/index.html . */ + +/** 1: Causes these widgets to be given default values at creation time. + * - lv_buttonmatrix_t: Get default maps: {"Btn1", "Btn2", "Btn3", "\n", "Btn4", "Btn5", ""}, else map not set. + * - lv_checkbox_t : String label set to "Check box", else set to empty string. + * - lv_dropdown_t : Options set to "Option 1", "Option 2", "Option 3", else no values are set. + * - lv_roller_t : Options set to "Option 1", "Option 2", "Option 3", "Option 4", "Option 5", else no values are set. + * - lv_label_t : Text set to "Text", else empty string. + * */ +#define LV_WIDGETS_HAS_DEFAULT_VALUE 0 + +#define LV_USE_ANIMIMG 0 + +#define LV_USE_ARC 0 + +#define LV_USE_BAR 0 + +#define LV_USE_BUTTON 1 + +#define LV_USE_BUTTONMATRIX 1 + +#define LV_USE_CALENDAR 0 +#if LV_USE_CALENDAR + #define LV_CALENDAR_WEEK_STARTS_MONDAY 0 + #if LV_CALENDAR_WEEK_STARTS_MONDAY + #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"} + #else + #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"} + #endif + + #define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} + #define LV_USE_CALENDAR_HEADER_ARROW 1 + #define LV_USE_CALENDAR_HEADER_DROPDOWN 1 + #define LV_USE_CALENDAR_CHINESE 0 +#endif /*LV_USE_CALENDAR*/ + +#define LV_USE_CANVAS 0 + +#define LV_USE_CHART 0 + +#define LV_USE_CHECKBOX 0 + +#define LV_USE_DROPDOWN 1 + +#define LV_USE_IMAGE 1 + +#define LV_USE_IMAGEBUTTON 0 + +#define LV_USE_KEYBOARD 1 + +#define LV_USE_LABEL 1 +#if LV_USE_LABEL + #define LV_LABEL_TEXT_SELECTION 0 + #define LV_LABEL_LONG_TXT_HINT 0 + #define LV_LABEL_WAIT_CHAR_COUNT 3 /**< The count of wait chart */ +#endif + +#define LV_USE_LED 0 + +#define LV_USE_LINE 0 + +#define LV_USE_LIST 0 + +#define LV_USE_LOTTIE 0 + +#define LV_USE_MENU 0 + +#define LV_USE_MSGBOX 1 + +#define LV_USE_ROLLER 0 + +#define LV_USE_SCALE 0 + +#define LV_USE_SLIDER 0 + +#define LV_USE_SPAN 0 +#if LV_USE_SPAN + /** A line of text can contain this maximum number of span descriptors. */ + #define LV_SPAN_SNIPPET_STACK_SIZE 64 +#endif + +#define LV_USE_SPINBOX 0 + +#define LV_USE_SPINNER 0 + +#define LV_USE_SWITCH 0 + +#define LV_USE_TABLE 0 + +#define LV_USE_TABVIEW 0 + +#define LV_USE_TEXTAREA 1 +#if LV_USE_TEXTAREA != 0 + #define LV_TEXTAREA_DEF_PWD_SHOW_TIME 0 /*ms*/ +#endif + +#define LV_USE_TILEVIEW 0 + +#define LV_USE_WIN 0 + +#define LV_USE_3DTEXTURE 0 + +/*================== + * THEMES + *==================*/ +/* Documentation for themes can be found here: https://docs.lvgl.io/master/details/common-widget-features/styles/style.html#themes . */ + +/** A simple, impressive and very complete theme */ +#define LV_USE_THEME_DEFAULT 0 +#if LV_USE_THEME_DEFAULT + /** 0: Light mode; 1: Dark mode */ + #define LV_THEME_DEFAULT_DARK 0 + + /** 1: Enable grow on press */ + #define LV_THEME_DEFAULT_GROW 1 + + /** Default transition time in ms. */ + #define LV_THEME_DEFAULT_TRANSITION_TIME 80 +#endif /*LV_USE_THEME_DEFAULT*/ + +/** A very simple theme that is a good starting point for a custom theme */ +#define LV_USE_THEME_SIMPLE 0 + +/** A theme designed for monochrome displays */ +#define LV_USE_THEME_MONO 0 + +/*================== + * LAYOUTS + *==================*/ +/* Documentation for layouts can be found here: https://docs.lvgl.io/master/details/common-widget-features/layouts/index.html . */ + +/** A layout similar to Flexbox in CSS. */ +#define LV_USE_FLEX 1 + +/** A layout similar to Grid in CSS. */ +#define LV_USE_GRID 0 + +/*==================== + * 3RD PARTS LIBRARIES + *====================*/ +/* Documentation for libraries can be found here: https://docs.lvgl.io/master/details/libs/index.html . */ + +/* File system interfaces for common APIs */ + +/** Setting a default driver letter allows skipping the driver prefix in filepaths. + * Documentation about how to use the below driver-identifier letters can be found at + * https://docs.lvgl.io/master/details/main-modules/fs.html#lv-fs-identifier-letters . */ +#define LV_FS_DEFAULT_DRIVER_LETTER '\0' + +/** API for fopen, fread, etc. */ +#define LV_USE_FS_STDIO 0 +#if LV_USE_FS_STDIO + #define LV_FS_STDIO_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */ + #define LV_FS_STDIO_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */ + #define LV_FS_STDIO_CACHE_SIZE 0 /**< >0 to cache this number of bytes in lv_fs_read() */ +#endif + +/** API for open, read, etc. */ +#define LV_USE_FS_POSIX 0 +#if LV_USE_FS_POSIX + #define LV_FS_POSIX_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */ + #define LV_FS_POSIX_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */ + #define LV_FS_POSIX_CACHE_SIZE 0 /**< >0 to cache this number of bytes in lv_fs_read() */ +#endif + +/** API for CreateFile, ReadFile, etc. */ +#define LV_USE_FS_WIN32 0 +#if LV_USE_FS_WIN32 + #define LV_FS_WIN32_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */ + #define LV_FS_WIN32_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */ + #define LV_FS_WIN32_CACHE_SIZE 0 /**< >0 to cache this number of bytes in lv_fs_read() */ +#endif + +/** API for FATFS (needs to be added separately). Uses f_open, f_read, etc. */ +#define LV_USE_FS_FATFS 0 +#if LV_USE_FS_FATFS + #define LV_FS_FATFS_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */ + #define LV_FS_FATFS_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */ + #define LV_FS_FATFS_CACHE_SIZE 0 /**< >0 to cache this number of bytes in lv_fs_read() */ +#endif + +/** API for memory-mapped file access. */ +#define LV_USE_FS_MEMFS 0 +#if LV_USE_FS_MEMFS + #define LV_FS_MEMFS_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */ +#endif + +/** API for LittleFs. */ +#define LV_USE_FS_LITTLEFS 0 +#if LV_USE_FS_LITTLEFS + #define LV_FS_LITTLEFS_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */ + #define LV_FS_LITTLEFS_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */ +#endif + +/** API for Arduino LittleFs. */ +#define LV_USE_FS_ARDUINO_ESP_LITTLEFS 0 +#if LV_USE_FS_ARDUINO_ESP_LITTLEFS + #define LV_FS_ARDUINO_ESP_LITTLEFS_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */ + #define LV_FS_ARDUINO_ESP_LITTLEFS_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */ +#endif + +/** API for Arduino Sd. */ +#define LV_USE_FS_ARDUINO_SD 0 +#if LV_USE_FS_ARDUINO_SD + #define LV_FS_ARDUINO_SD_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */ + #define LV_FS_ARDUINO_SD_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */ +#endif + +/** API for UEFI */ +#define LV_USE_FS_UEFI 0 +#if LV_USE_FS_UEFI + #define LV_FS_UEFI_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */ +#endif + +/** LODEPNG decoder library */ +#define LV_USE_LODEPNG 0 + +/** PNG decoder(libpng) library */ +#define LV_USE_LIBPNG 0 + +/** BMP decoder library */ +#define LV_USE_BMP 0 + +/** JPG + split JPG decoder library. + * Split JPG is a custom format optimized for embedded systems. */ +#define LV_USE_TJPGD 0 + +/** libjpeg-turbo decoder library. + * - Supports complete JPEG specifications and high-performance JPEG decoding. */ +#define LV_USE_LIBJPEG_TURBO 0 + +/** GIF decoder library */ +#define LV_USE_GIF 0 +#if LV_USE_GIF + /** GIF decoder accelerate */ + #define LV_GIF_CACHE_DECODE_DATA 0 +#endif + + +/** Decode bin images to RAM */ +#define LV_BIN_DECODER_RAM_LOAD 0 + +/** RLE decompress library */ +#define LV_USE_RLE 0 + +/** QR code library */ +#define LV_USE_QRCODE 0 + +/** Barcode code library */ +#define LV_USE_BARCODE 0 + +/** FreeType library */ +#define LV_USE_FREETYPE 0 +#if LV_USE_FREETYPE + /** Let FreeType use LVGL memory and file porting */ + #define LV_FREETYPE_USE_LVGL_PORT 0 + + /** Cache count of glyphs in FreeType, i.e. number of glyphs that can be cached. + * The higher the value, the more memory will be used. */ + #define LV_FREETYPE_CACHE_FT_GLYPH_CNT 256 +#endif + +/** Built-in TTF decoder */ +#define LV_USE_TINY_TTF 0 +#if LV_USE_TINY_TTF + /* Enable loading TTF data from files */ + #define LV_TINY_TTF_FILE_SUPPORT 0 + #define LV_TINY_TTF_CACHE_GLYPH_CNT 256 +#endif + +/** Rlottie library */ +#define LV_USE_RLOTTIE 0 + +/** Enable Vector Graphic APIs + * - Requires `LV_USE_MATRIX = 1` */ +#define LV_USE_VECTOR_GRAPHIC 0 + +/** Enable ThorVG (vector graphics library) from the src/libs folder */ +#define LV_USE_THORVG_INTERNAL 0 + +/** Enable ThorVG by assuming that its installed and linked to the project */ +#define LV_USE_THORVG_EXTERNAL 0 + +/** Use lvgl built-in LZ4 lib */ +#define LV_USE_LZ4_INTERNAL 0 + +/** Use external LZ4 library */ +#define LV_USE_LZ4_EXTERNAL 0 + +/*SVG library + * - Requires `LV_USE_VECTOR_GRAPHIC = 1` */ +#define LV_USE_SVG 0 +#define LV_USE_SVG_ANIMATION 0 +#define LV_USE_SVG_DEBUG 0 + +/** FFmpeg library for image decoding and playing videos. + * Supports all major image formats so do not enable other image decoder with it. */ +#define LV_USE_FFMPEG 0 +#if LV_USE_FFMPEG + /** Dump input information to stderr */ + #define LV_FFMPEG_DUMP_FORMAT 0 + /** Use lvgl file path in FFmpeg Player widget + * You won't be able to open URLs after enabling this feature. + * Note that FFmpeg image decoder will always use lvgl file system. */ + #define LV_FFMPEG_PLAYER_USE_LV_FS 0 +#endif + +/*================== + * OTHERS + *==================*/ +/* Documentation for several of the below items can be found here: https://docs.lvgl.io/master/details/auxiliary-modules/index.html . */ + +/** 1: Enable API to take snapshot for object */ +#define LV_USE_SNAPSHOT 0 + +/** 1: Enable system monitor component */ +#define LV_USE_SYSMON 0 +#if LV_USE_SYSMON + /** Get the idle percentage. E.g. uint32_t my_get_idle(void); */ + #define LV_SYSMON_GET_IDLE lv_os_get_idle_percent + + /** 1: Show CPU usage and FPS count. + * - Requires `LV_USE_SYSMON = 1` */ + #define LV_USE_PERF_MONITOR 0 + #if LV_USE_PERF_MONITOR + #define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT + + /** 0: Displays performance data on the screen; 1: Prints performance data using log. */ + #define LV_USE_PERF_MONITOR_LOG_MODE 0 + #endif + + /** 1: Show used memory and memory fragmentation. + * - Requires `LV_USE_STDLIB_MALLOC = LV_STDLIB_BUILTIN` + * - Requires `LV_USE_SYSMON = 1`*/ + #define LV_USE_MEM_MONITOR 0 + #if LV_USE_MEM_MONITOR + #define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT + #endif +#endif /*LV_USE_SYSMON*/ + +/** 1: Enable runtime performance profiler */ +#define LV_USE_PROFILER 0 +#if LV_USE_PROFILER + /** 1: Enable the built-in profiler */ + #define LV_USE_PROFILER_BUILTIN 1 + #if LV_USE_PROFILER_BUILTIN + /** Default profiler trace buffer size */ + #define LV_PROFILER_BUILTIN_BUF_SIZE (16 * 1024) /**< [bytes] */ + #define LV_PROFILER_BUILTIN_DEFAULT_ENABLE 1 + #endif + + /** Header to include for profiler */ + #define LV_PROFILER_INCLUDE "lvgl/src/misc/lv_profiler_builtin.h" + + /** Profiler start point function */ + #define LV_PROFILER_BEGIN LV_PROFILER_BUILTIN_BEGIN + + /** Profiler end point function */ + #define LV_PROFILER_END LV_PROFILER_BUILTIN_END + + /** Profiler start point function with custom tag */ + #define LV_PROFILER_BEGIN_TAG LV_PROFILER_BUILTIN_BEGIN_TAG + + /** Profiler end point function with custom tag */ + #define LV_PROFILER_END_TAG LV_PROFILER_BUILTIN_END_TAG + + /*Enable layout profiler*/ + #define LV_PROFILER_LAYOUT 1 + + /*Enable disp refr profiler*/ + #define LV_PROFILER_REFR 1 + + /*Enable draw profiler*/ + #define LV_PROFILER_DRAW 1 + + /*Enable indev profiler*/ + #define LV_PROFILER_INDEV 1 + + /*Enable decoder profiler*/ + #define LV_PROFILER_DECODER 1 + + /*Enable font profiler*/ + #define LV_PROFILER_FONT 1 + + /*Enable fs profiler*/ + #define LV_PROFILER_FS 1 + + /*Enable style profiler*/ + #define LV_PROFILER_STYLE 0 + + /*Enable timer profiler*/ + #define LV_PROFILER_TIMER 1 + + /*Enable cache profiler*/ + #define LV_PROFILER_CACHE 1 + + /*Enable event profiler*/ + #define LV_PROFILER_EVENT 1 +#endif + +/** 1: Enable Monkey test */ +#define LV_USE_MONKEY 0 + +/** 1: Enable grid navigation */ +#define LV_USE_GRIDNAV 0 + +/** 1: Enable `lv_obj` fragment logic */ +#define LV_USE_FRAGMENT 0 + +/** 1: Support using images as font in label or span widgets */ +#define LV_USE_IMGFONT 0 + +/** 1: Enable an observer pattern implementation */ +#define LV_USE_OBSERVER 1 + +/** 1: Enable Pinyin input method + * - Requires: lv_keyboard */ +#define LV_USE_IME_PINYIN 0 +#if LV_USE_IME_PINYIN + /** 1: Use default thesaurus. + * @note If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesaurus. */ + #define LV_IME_PINYIN_USE_DEFAULT_DICT 1 + /** Set maximum number of candidate panels that can be displayed. + * @note This needs to be adjusted according to size of screen. */ + #define LV_IME_PINYIN_CAND_TEXT_NUM 6 + + /** Use 9-key input (k9). */ + #define LV_IME_PINYIN_USE_K9_MODE 1 + #if LV_IME_PINYIN_USE_K9_MODE == 1 + #define LV_IME_PINYIN_K9_CAND_TEXT_NUM 3 + #endif /*LV_IME_PINYIN_USE_K9_MODE*/ +#endif + +/** 1: Enable file explorer. + * - Requires: lv_table */ +#define LV_USE_FILE_EXPLORER 0 +#if LV_USE_FILE_EXPLORER + /** Maximum length of path */ + #define LV_FILE_EXPLORER_PATH_MAX_LEN (128) + /** Quick access bar, 1:use, 0:do not use. + * - Requires: lv_list */ + #define LV_FILE_EXPLORER_QUICK_ACCESS 1 +#endif + +/** 1: Enable Font manager */ +#define LV_USE_FONT_MANAGER 0 +#if LV_USE_FONT_MANAGER + +/**Font manager name max length*/ +#define LV_FONT_MANAGER_NAME_MAX_LEN 32 + +#endif + +/** Enable emulated input devices, time emulation, and screenshot compares. */ +#define LV_USE_TEST 0 +#if LV_USE_TEST + +/** Enable `lv_test_screenshot_compare`. + * Requires libpng and a few MB of extra RAM. */ +#define LV_USE_TEST_SCREENSHOT_COMPARE 0 +#endif /*LV_USE_TEST*/ + +/** Enable loading XML UIs runtime */ +#define LV_USE_XML 0 + +/*1: Enable color filter style*/ +#define LV_USE_COLOR_FILTER 0 +/*================== + * DEVICES + *==================*/ + +/** Use SDL to open window on PC and handle mouse and keyboard. */ +#define LV_USE_SDL 0 +#if LV_USE_SDL + #define LV_SDL_INCLUDE_PATH + #define LV_SDL_RENDER_MODE LV_DISPLAY_RENDER_MODE_DIRECT /**< LV_DISPLAY_RENDER_MODE_DIRECT is recommended for best performance */ + #define LV_SDL_BUF_COUNT 1 /**< 1 or 2 */ + #define LV_SDL_ACCELERATED 1 /**< 1: Use hardware acceleration*/ + #define LV_SDL_FULLSCREEN 0 /**< 1: Make the window full screen by default */ + #define LV_SDL_DIRECT_EXIT 1 /**< 1: Exit the application when all SDL windows are closed */ + #define LV_SDL_MOUSEWHEEL_MODE LV_SDL_MOUSEWHEEL_MODE_ENCODER /*LV_SDL_MOUSEWHEEL_MODE_ENCODER/CROWN*/ +#endif + +/** Use X11 to open window on Linux desktop and handle mouse and keyboard */ +#define LV_USE_X11 0 +#if LV_USE_X11 + #define LV_X11_DIRECT_EXIT 1 /**< Exit application when all X11 windows have been closed */ + #define LV_X11_DOUBLE_BUFFER 1 /**< Use double buffers for rendering */ + /* Select only 1 of the following render modes (LV_X11_RENDER_MODE_PARTIAL preferred!). */ + #define LV_X11_RENDER_MODE_PARTIAL 1 /**< Partial render mode (preferred) */ + #define LV_X11_RENDER_MODE_DIRECT 0 /**< Direct render mode */ + #define LV_X11_RENDER_MODE_FULL 0 /**< Full render mode */ +#endif + +/** Use Wayland to open a window and handle input on Linux or BSD desktops */ +#define LV_USE_WAYLAND 0 +#if LV_USE_WAYLAND + #define LV_WAYLAND_BUF_COUNT 1 /**< Use 1 for single buffer with partial render mode or 2 for double buffer with full render mode*/ + #define LV_WAYLAND_USE_DMABUF 0 /**< Use DMA buffers for frame buffers. Requires LV_DRAW_USE_G2D */ + #define LV_WAYLAND_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL /**< DMABUF supports LV_DISPLAY_RENDER_MODE_FULL and LV_DISPLAY_RENDER_MODE_DIRECT*/ + /**< When LV_WAYLAND_USE_DMABUF is disabled, only LV_DISPLAY_RENDER_MODE_PARTIAL is supported*/ + #define LV_WAYLAND_WINDOW_DECORATIONS 0 /**< Draw client side window decorations only necessary on Mutter/GNOME. Not supported using DMABUF*/ + #define LV_WAYLAND_WL_SHELL 0 /**< Use the legacy wl_shell protocol instead of the default XDG shell*/ +#endif + +/** Driver for /dev/fb */ +#define LV_USE_LINUX_FBDEV 1 +#if LV_USE_LINUX_FBDEV + #define LV_LINUX_FBDEV_BSD 0 + #define LV_LINUX_FBDEV_RENDER_MODE LV_DISPLAY_RENDER_MODE_DIRECT + #define LV_LINUX_FBDEV_BUFFER_COUNT 0 + #define LV_LINUX_FBDEV_BUFFER_SIZE 60 + #define LV_LINUX_FBDEV_MMAP 1 +#endif + +/** Use Nuttx to open window and handle touchscreen */ +#define LV_USE_NUTTX 0 + +#if LV_USE_NUTTX + #define LV_USE_NUTTX_INDEPENDENT_IMAGE_HEAP 0 + + /** Use independent image heap for default draw buffer */ + #define LV_NUTTX_DEFAULT_DRAW_BUF_USE_INDEPENDENT_IMAGE_HEAP 0 + + #define LV_USE_NUTTX_LIBUV 0 + + /** Use Nuttx custom init API to open window and handle touchscreen */ + #define LV_USE_NUTTX_CUSTOM_INIT 0 + + /** Driver for /dev/lcd */ + #define LV_USE_NUTTX_LCD 0 + #if LV_USE_NUTTX_LCD + #define LV_NUTTX_LCD_BUFFER_COUNT 0 + #define LV_NUTTX_LCD_BUFFER_SIZE 60 + #endif + + /** Driver for /dev/input */ + #define LV_USE_NUTTX_TOUCHSCREEN 0 + + /*Touchscreen cursor size in pixels(<=0: disable cursor)*/ + #define LV_NUTTX_TOUCHSCREEN_CURSOR_SIZE 0 +#endif + +/** Driver for /dev/dri/card */ +//#define LV_USE_LINUX_DRM 0 + +#if LV_USE_LINUX_DRM + + /* Use the MESA GBM library to allocate DMA buffers that can be + * shared across sub-systems and libraries using the Linux DMA-BUF API. + * The GBM library aims to provide a platform independent memory management system + * it supports the major GPU vendors - This option requires linking with libgbm */ + #define LV_LINUX_DRM_GBM_BUFFERS 0 +#endif + +/** Interface for TFT_eSPI */ +#define LV_USE_TFT_ESPI 0 + +/** Driver for evdev input devices */ +#define LV_USE_EVDEV 0 + +/** Driver for libinput input devices */ +#define LV_USE_LIBINPUT 1 + +#if LV_USE_LIBINPUT + #define LV_LIBINPUT_BSD 0 + + /** Full keyboard support */ + #define LV_LIBINPUT_XKB 1 + #if LV_LIBINPUT_XKB + /** "setxkbmap -query" can help find the right values for your keyboard */ + #define LV_LIBINPUT_XKB_KEY_MAP { .rules = NULL, .model = "pc101", .layout = "us", .variant = NULL, .options = NULL } + #endif +#endif + +/* Drivers for LCD devices connected via SPI/parallel port */ +#define LV_USE_ST7735 0 +#define LV_USE_ST7789 0 +#define LV_USE_ST7796 0 +#define LV_USE_ILI9341 0 +#define LV_USE_FT81X 0 + +#if (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341) + #define LV_USE_GENERIC_MIPI 1 +#else + #define LV_USE_GENERIC_MIPI 0 +#endif + +/** Driver for Renesas GLCD */ +#define LV_USE_RENESAS_GLCDC 0 + +/** Driver for ST LTDC */ +#define LV_USE_ST_LTDC 0 +#if LV_USE_ST_LTDC + /* Only used for partial. */ + #define LV_ST_LTDC_USE_DMA2D_FLUSH 0 +#endif + +/** LVGL Windows backend */ +#define LV_USE_WINDOWS 0 + +/** LVGL UEFI backend */ +#define LV_USE_UEFI 0 +#if LV_USE_UEFI + #define LV_USE_UEFI_INCLUDE "myefi.h" /**< Header that hides the actual framework (EDK2, gnu-efi, ...) */ + #define LV_UEFI_USE_MEMORY_SERVICES 0 /**< Use the memory functions from the boot services table */ +#endif + +/** Use OpenGL to open window on PC and handle mouse and keyboard */ +#define LV_USE_OPENGLES 0 +#if LV_USE_OPENGLES + #define LV_USE_OPENGLES_DEBUG 1 /**< Enable or disable debug for opengles */ +#endif + +/** QNX Screen display and input drivers */ +#define LV_USE_QNX 0 +#if LV_USE_QNX + #define LV_QNX_BUF_COUNT 1 /**< 1 or 2 */ +#endif + +/*===================== +* BUILD OPTIONS +*======================*/ + +/** Enable examples to be built with the library. */ +#define LV_BUILD_EXAMPLES 0 + +/** Build the demos */ +#define LV_BUILD_DEMOS 0 + +/*=================== + * DEMO USAGE + ====================*/ + +#if LV_BUILD_DEMOS + /** Show some widgets. This might be required to increase `LV_MEM_SIZE`. */ + #define LV_USE_DEMO_WIDGETS 0 + + /** Demonstrate usage of encoder and keyboard. */ + #define LV_USE_DEMO_KEYPAD_AND_ENCODER 0 + + /** Benchmark your system */ + #define LV_USE_DEMO_BENCHMARK 0 + + #if LV_USE_DEMO_BENCHMARK + /** Use fonts where bitmaps are aligned 16 byte and has Nx16 byte stride */ + #define LV_DEMO_BENCHMARK_ALIGNED_FONTS 0 + #endif + + /** Render test for each primitive. + * - Requires at least 480x272 display. */ + #define LV_USE_DEMO_RENDER 0 + + /** Stress test for LVGL */ + #define LV_USE_DEMO_STRESS 0 + + /** Music player demo */ + #define LV_USE_DEMO_MUSIC 0 + #if LV_USE_DEMO_MUSIC + #define LV_DEMO_MUSIC_SQUARE 0 + #define LV_DEMO_MUSIC_LANDSCAPE 0 + #define LV_DEMO_MUSIC_ROUND 0 + #define LV_DEMO_MUSIC_LARGE 0 + #define LV_DEMO_MUSIC_AUTO_PLAY 0 + #endif + + /** Vector graphic demo */ + #define LV_USE_DEMO_VECTOR_GRAPHIC 0 + + /*--------------------------- + * Demos from lvgl/lv_demos + ---------------------------*/ + + /** Flex layout demo */ + #define LV_USE_DEMO_FLEX_LAYOUT 0 + + /** Smart-phone like multi-language demo */ + #define LV_USE_DEMO_MULTILANG 0 + + /** Widget transformation demo */ + #define LV_USE_DEMO_TRANSFORM 0 + + /** Demonstrate scroll settings */ + #define LV_USE_DEMO_SCROLL 0 + + /*E-bike demo with Lottie animations (if LV_USE_LOTTIE is enabled)*/ + #define LV_USE_DEMO_EBIKE 0 + #if LV_USE_DEMO_EBIKE + #define LV_DEMO_EBIKE_PORTRAIT 0 /*0: for 480x270..480x320, 1: for 480x800..720x1280*/ + #endif + + /** High-resolution demo */ + #define LV_USE_DEMO_HIGH_RES 0 + + /* Smart watch demo */ + #define LV_USE_DEMO_SMARTWATCH 0 +#endif /* LV_BUILD_DEMOS */ + +/*--END OF LV_CONF_H--*/ + +#endif /*LV_CONF_H*/ + +#endif /*End of "Content enable"*/ diff --git a/f0rmz/main.c b/f0rmz/main.c new file mode 100644 index 0000000..5e33332 --- /dev/null +++ b/f0rmz/main.c @@ -0,0 +1,908 @@ +/** + * Copyright 2025 Clayton Craft + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "command_line.h" +#include "config.h" + +#include "../shared/backends.h" +#include "../shared/display.h" +#include "../shared/header.h" +#include "../shared/indev.h" +#include "../shared/keyboard.h" +#include "../shared/log.h" +#include "../shared/theme.h" +#include "../shared/themes.h" +#include "../shared/terminal.h" +#include "../squeek2lvgl/sq2lv.h" + +#include "lvgl/lvgl.h" + +#include +#include +#include +#include + +#include + +#define F0_PASSWORD_HIDDEN_DOTS "••••••••" + +/** + * Static variables + */ + +f0_cli_opts cli_opts; +f0_config_opts conf_opts; + +bool is_alternate_theme = false; +bool is_keyboard_hidden = false; + +static char **field_values = NULL; + +int current_field_index = 0; + +lv_obj_t *form_container = NULL; +lv_obj_t *form_textarea = NULL; +lv_obj_t *keyboard = NULL; + +int32_t content_height_with_kb; +int32_t content_height_without_kb; + +/** + * Static prototypes + */ + +/** + * Handle LV_EVENT_CLICKED events from the theme toggle button. + * + * @param event the event object + */ +static void toggle_theme_btn_clicked_cb(lv_event_t *event); + +/** + * Toggle between the light and dark theme. + */ +static void toggle_theme(void); + +/** + * Set the UI theme. + * + * @param is_alternate true if the alternate theme should be applied, false if the default theme should be applied + */ +static void set_theme(bool is_alternate); + +/** + * Get the UI theme. + * + * @param is_alternate true if the alternate theme should be selected, false if the default theme should be selected + */ +static const bbx_theme * get_theme(bool is_alternate); + +/** + * Show the intro screen. + * + */ +static void show_intro_screen(void); + +/** + * Handle LV_EVENT_KEY events from the intro 'get started' button. + * + * @param event the event object + */ +static void get_started_btn_clicked_cb(lv_event_t *event); + +/** + * Handle LV_EVENT_KEY events on intro screen. + * + * @param event the event object + */ +static void intro_key_cb(lv_event_t *event); + +/** + * Show form screen with a field + */ +static void show_form_screen(void); + +/** + * Handle LV_EVENT_CLICKED events from the form field submit. + * + * @param event the event object + */ +static void field_submit_cb(lv_event_t *event); + +/** + * Handle LV_EVENT_CLICKED events from the form 'previous' button. + * + * @param event the event object + */ +static void prev_btn_clicked_cb(lv_event_t *event); + +/** + * Handle LV_EVENT_CLICKED events from the form 'next' button. + * + * @param event the event object + */ + static void next_btn_clicked_cb(lv_event_t *event); + + /** + * Validate a form field according to its requirements. + * + * @param field_index index of the field to validate + * @return true if field is valid, false otherwise + */ +static bool validate_field(int field_index); + +/** + * Set visual validation error state on the current textarea. + * + * @param has_error true to show error styling, false to clear it + */ +static void set_field_validation_error(bool has_error); + +/** + * Save current textarea content and validate the field. + * + * @return true if field is valid, false if validation failed + */ +static bool save_and_validate_current_field(void); + +/** + * Handle LV_EVENT_CLICKED events from the show/hide keyboard toggle button. + * + * @param event the event object + */ +static void toggle_kb_btn_clicked_cb(lv_event_t *event); + +/** + * Toggle between showing and hiding the keyboard. + */ +static void toggle_keyboard_hidden(void); + +/** + * Show / hide the keyboard. + * + * @param is_hidden true if the keyboard should be hidden, false if it should be shown + */ +static void set_keyboard_hidden(bool is_hidden); + +/** + * Handle LV_EVENT_CLICKED events from password visibility toggle button. + * + * @param event the event object + */ +static void toggle_password_btn_clicked_cb(lv_event_t *event); + +/** + * Handle LV_EVENT_CLICKED events from password visibility toggle button in + * summary. + * + * @param event the event object + */ +static void toggle_password_summary_btn_clicked_cb(lv_event_t *event); + +/** + * Handle LV_EVENT_VALUE_CHANGED events from the keyboard layout dropdown. + * + * @param event the event object + */ +static void layout_dropdown_value_changed_cb(lv_event_t *event); + +/** + * Handle LV_EVENT_CLICKED events from the shutdown button. + * + * @param event the event object + */ +static void shutdown_btn_clicked_cb(lv_event_t *event); + +/** + * Handle confirmation events from the shutdown message box. + * + * @param event the event object + */ +static void shutdown_mbox_confirmed_cb(lv_event_t *event); + +/** + * Handle declination events from the shutdown message box. + * + * @param event the event object + */ +static void shutdown_mbox_declined_cb(lv_event_t *event); + +/** + * Handle LV_EVENT_VALUE_CHANGED events from the keyboard widget. + * + * @param event the event object + */ +static void keyboard_value_changed_cb(lv_event_t *event); + +/** + * Handle LV_EVENT_READY events from the keyboard widget. + * + * @param event the event object + */ +static void keyboard_ready_cb(lv_event_t *event); + +/** + * Show summary screen with all field values. + */ +static void show_summary_screen(void); + +/** + * Handle LV_EVENT_CLICKED events from summary field items. + * + * @param event the event object + */ +static void summary_field_clicked_cb(lv_event_t *event); + +/** + * Handle LV_EVENT_CLICKED events from finish button. + * + * @param event the event object + */ +static void finish_cb(lv_event_t *event); + +/** + * Shuts down the device. + */ +static void shutdown(void); + +/** + * Handle termination signals sent to the process. + * + * @param signum the signal's number + */ +static void sigaction_handler(int signum); + +/** + * Restore the terminal and exit from the program with EXIT_FAILURE. + */ +static void exit_failure(); + +/** + * Static functions + */ + + static void intro_key_cb(lv_event_t *event) { + uint32_t key = lv_indev_get_key(lv_indev_active()); + if (key == LV_KEY_ENTER) { + get_started_btn_clicked_cb(event); + } +} + +static void toggle_theme_btn_clicked_cb(lv_event_t *event) { + LV_UNUSED(event); + toggle_theme(); +} + +static void sigaction_handler(int signum) { + bbx_terminal_reset_current_terminal(); + exit(signum); +} + +static void exit_failure() { + bbx_terminal_reset_current_terminal(); + exit(EXIT_FAILURE); +} + + +static void toggle_theme(void) { + is_alternate_theme = !is_alternate_theme; + set_theme(is_alternate_theme); +} + +static void set_theme(bool is_alternate) { + bbx_theme_apply(get_theme(is_alternate)); +} + +static const bbx_theme * get_theme(bool is_alternate) { + return bbx_themes_themes[is_alternate ? conf_opts.theme.alternate_id : conf_opts.theme.default_id]; +} + +static void toggle_kb_btn_clicked_cb(lv_event_t *event) { + LV_UNUSED(event); + toggle_keyboard_hidden(); +} + +static void toggle_keyboard_hidden(void) { + is_keyboard_hidden = !is_keyboard_hidden; + set_keyboard_hidden(is_keyboard_hidden); +} + +static void set_keyboard_hidden(bool is_hidden) { + if (!form_container) return; + + lv_anim_t container_anim; + lv_anim_init(&container_anim); + lv_anim_set_var(&container_anim, form_container); + lv_anim_set_exec_cb(&container_anim, (lv_anim_exec_xcb_t) lv_obj_set_height); + lv_anim_set_path_cb(&container_anim, lv_anim_path_ease_out); + lv_anim_set_time(&container_anim, 500); + + lv_anim_set_values(&container_anim, + is_hidden? content_height_with_kb : content_height_without_kb, + is_hidden? content_height_without_kb : content_height_with_kb); + + lv_anim_start(&container_anim); +} + +static void toggle_password_btn_clicked_cb(lv_event_t *event) { + lv_obj_t *btn = lv_event_get_target(event); + lv_obj_t *textarea = (lv_obj_t *)lv_obj_get_user_data(btn); + lv_obj_t *btn_label = lv_obj_get_child(btn, 0); + + bool is_obscured = lv_textarea_get_password_mode(textarea); + lv_textarea_set_password_mode(textarea, !is_obscured); + lv_label_set_text(btn_label, is_obscured ? LV_SYMBOL_EYE_CLOSE : LV_SYMBOL_EYE_OPEN); +} + +static void toggle_password_summary_btn_clicked_cb(lv_event_t *event) { + lv_obj_t *btn = lv_event_get_target(event); + lv_obj_t *value_label = (lv_obj_t *)lv_obj_get_user_data(btn); + lv_obj_t *btn_label = lv_obj_get_child(btn, 0); + + const char *current_text = lv_label_get_text(value_label); + bool is_obscured = (strcmp(current_text, F0_PASSWORD_HIDDEN_DOTS) == 0); + + if (is_obscured) { + /* Show actual password - need field index to get real value */ + int field_index = (int)(intptr_t)lv_obj_get_user_data(value_label); + const char *real_value = field_values[field_index] ? field_values[field_index] : ""; + lv_label_set_text(value_label, real_value); + lv_label_set_text(btn_label, LV_SYMBOL_EYE_CLOSE); + } else { + lv_label_set_text(value_label, F0_PASSWORD_HIDDEN_DOTS); + lv_label_set_text(btn_label, LV_SYMBOL_EYE_OPEN); + } +} + +static void layout_dropdown_value_changed_cb(lv_event_t *event) { + lv_obj_t *dropdown = lv_event_get_target(event); + uint16_t idx = lv_dropdown_get_selected(dropdown); + sq2lv_switch_layout(keyboard, idx); +} + +static void shutdown_btn_clicked_cb(lv_event_t *event) { + LV_UNUSED(event); + lv_obj_t *mbox = lv_msgbox_create(NULL); + lv_msgbox_add_title(mbox, "Shutdown device?"); + lv_obj_t *confirm_btn = lv_msgbox_add_footer_button(mbox, "Yes"); + lv_obj_add_event_cb(confirm_btn, shutdown_mbox_confirmed_cb, LV_EVENT_CLICKED, NULL); + lv_obj_t *decline_btn = lv_msgbox_add_footer_button(mbox, "No"); + lv_obj_add_event_cb(decline_btn, shutdown_mbox_declined_cb, LV_EVENT_CLICKED, NULL); + lv_obj_set_size(mbox, 400, LV_SIZE_CONTENT); + lv_obj_center(mbox); +} + +static void shutdown_mbox_confirmed_cb(lv_event_t *event) { + LV_UNUSED(event); + shutdown(); +} + +static void shutdown_mbox_declined_cb(lv_event_t *event) { + /* Find the containing message box for the clicked button */ + lv_obj_t *obj = lv_event_get_target(event); + while (obj && !lv_obj_check_type(obj, &lv_msgbox_class)) { + obj = lv_obj_get_parent(obj); + } + + if (!obj) { + bbx_log(BBX_LOG_LEVEL_ERROR, "Could not find containing message box for clicked button"); + return; + } + + lv_msgbox_close(obj); +} + +static void keyboard_value_changed_cb(lv_event_t *event) { + lv_obj_t *kb = lv_event_get_target(event); + + uint16_t btn_id = lv_buttonmatrix_get_selected_button(kb); + if (btn_id == LV_BUTTONMATRIX_BUTTON_NONE) { + return; + } + + if (sq2lv_is_layer_switcher(kb, btn_id)) { + sq2lv_switch_layer(kb, btn_id); + return; + } + + lv_keyboard_def_event_cb(event); +} + +static void keyboard_ready_cb(lv_event_t *event) { + field_submit_cb(event); +} + +static void get_started_btn_clicked_cb(lv_event_t *event) { + LV_UNUSED(event); + current_field_index = 0; + show_form_screen(); +} + +static void field_submit_cb(lv_event_t *event) { + LV_UNUSED(event); + if (save_and_validate_current_field()) { + current_field_index++; + if (current_field_index >= conf_opts.num_fields) { + show_summary_screen(); + } else { + show_form_screen(); + } + } +} + +static void prev_btn_clicked_cb(lv_event_t *event) { + LV_UNUSED(event); + if (current_field_index > 0 && save_and_validate_current_field()) { + current_field_index--; + show_form_screen(); + } +} + +static void next_btn_clicked_cb(lv_event_t *event) { + LV_UNUSED(event); + if (save_and_validate_current_field()) { + current_field_index++; + if (current_field_index >= conf_opts.num_fields) { + show_summary_screen(); + } else { + show_form_screen(); + } + } +} + +static void summary_field_clicked_cb(lv_event_t *event) { + lv_obj_t *target = lv_event_get_target(event); + int field_index = (int)(intptr_t)lv_obj_get_user_data(target); + + current_field_index = field_index; + show_form_screen(); +} + +static void finish_cb(lv_event_t *event) { + LV_UNUSED(event); + + /* Output key=value pairs */ + for (int i = 0; i < conf_opts.num_fields; i++) { + const f0_form_field_t *field = &conf_opts.fields[i]; + const char *value = field_values[i] ? field_values[i] : ""; + printf("%s=%s\n", field->name, value); + } + + /* Clear the screen so that form data cannot leak via stale display buffers */ + lv_obj_t *rect = lv_obj_create(lv_screen_active()); + lv_obj_set_size(rect, LV_PCT(100), LV_PCT(100)); + lv_obj_set_pos(rect, 0, 0); + lv_obj_set_style_bg_opa(rect, LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_bg_color(rect, lv_color_hex(get_theme(is_alternate_theme)->window.bg_color), LV_PART_MAIN); + lv_refr_now(lv_display_get_default()); /* Force the screen to be drawn */ + + /* Trigger SIGTERM to exit */ + sigaction_handler(SIGTERM); + + exit(0); +} + +static bool validate_field(int field_index) { + if (field_index >= conf_opts.num_fields) return true; + + const f0_form_field_t *field = &conf_opts.fields[field_index]; + const char *value = field_values[field_index] ? field_values[field_index] : ""; + + // Required field validation + if (field->required && strlen(value) == 0) { + return false; + } + + // Future validation rules here, e.g.: + // if (field->min_length > 0 && strlen(value) < field->min_length) return false; + + return true; +} + +static void set_field_validation_error(bool has_error) { + if (!form_textarea) return; + + if (has_error) { + lv_obj_set_style_border_color(form_textarea, lv_color_hex(0xFF0000), LV_PART_MAIN); + lv_obj_set_style_border_width(form_textarea, 2, LV_PART_MAIN); + } else { + lv_obj_set_style_border_color(form_textarea, lv_color_hex(0x000000), LV_PART_MAIN); + lv_obj_set_style_border_width(form_textarea, 1, LV_PART_MAIN); + } +} + +static bool save_and_validate_current_field() { + if (!form_textarea || !field_values) return true; + + // Save current content + char *new_value = strdup(lv_textarea_get_text(form_textarea)); + if (new_value) { + if (field_values[current_field_index]) { + free(field_values[current_field_index]); + } + field_values[current_field_index] = new_value; + } + + // Validate and show/clear error + bool is_valid = validate_field(current_field_index); + set_field_validation_error(!is_valid); + + return is_valid; +} + +static void show_intro_screen(void) { + lv_obj_t *screen = lv_screen_active(); + + /* Header config */ + bbx_header_config_t header_config; + bbx_header_init_config(&header_config); + /* No OSK needed on intro */ + header_config.show_keyboard_toggle = false; + header_config.show_layout_dropdown = false; + + bbx_header_widgets_t header_widgets; + lv_obj_t *header = bbx_header_create(screen, &header_config, &header_widgets); + lv_obj_add_flag(header, BBX_WIDGET_HEADER); + lv_theme_apply(header); + + /* Attach callbacks */ + lv_obj_add_event_cb(header_widgets.theme_toggle_btn, toggle_theme_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + + /* Container for intro content */ + lv_obj_t *container = lv_obj_create(screen); + lv_obj_set_size(container, LV_PCT(100), LV_PCT(100)); + lv_obj_set_flex_flow(container, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_align(container, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_all(container, 40, LV_PART_MAIN); + + /* Title */ + lv_obj_t *title = lv_label_create(container); + lv_label_set_text(title, conf_opts.intro.title); + lv_obj_set_style_text_align(title, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN); + lv_obj_set_style_pad_bottom(title, 20, LV_PART_MAIN); + + /* Body */ + lv_obj_t *body = lv_label_create(container); + lv_label_set_text(body, conf_opts.intro.body); + lv_label_set_long_mode(body, LV_LABEL_LONG_WRAP); + lv_obj_set_width(body, LV_PCT(80)); + lv_obj_set_style_text_align(body, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN); + lv_obj_set_style_pad_bottom(body, 30, LV_PART_MAIN); + + /* Get Started button */ + lv_obj_t *btn = lv_button_create(container); + lv_obj_t *btn_label = lv_label_create(btn); + lv_label_set_text(btn_label, "Get Started"); + lv_obj_center(btn_label); + lv_obj_add_event_cb(btn, get_started_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + + /* Set up keyboard input for intro screen */ + lv_group_t *intro_input_group = lv_group_create(); + bbx_indev_set_keyboard_input_group(intro_input_group); + lv_group_add_obj(intro_input_group, btn); + lv_obj_add_event_cb(btn, intro_key_cb, LV_EVENT_KEY, NULL); + } + +static void show_form_screen(void) { + if (current_field_index >= conf_opts.num_fields) { + bbx_log(BBX_LOG_LEVEL_VERBOSE, "Form complete"); + return; + } + + if (field_values == NULL) { + field_values = calloc(conf_opts.num_fields, sizeof(char*)); + } + + f0_form_field_t *field = &conf_opts.fields[current_field_index]; + + /* Clear screen */ + lv_obj_clean(lv_screen_active()); + + /* Recreate header */ + bbx_header_config_t header_config; + bbx_header_init_config(&header_config); + header_config.show_keyboard_toggle = true; + header_config.show_layout_dropdown = true; + header_config.dropdown_options = sq2lv_layout_short_names; + + bbx_header_widgets_t header_widgets; + lv_obj_t *header = bbx_header_create(lv_screen_active(), &header_config, &header_widgets); + lv_obj_add_flag(header, BBX_WIDGET_HEADER); + lv_theme_apply(header); + + /* Attach callbacks */ + lv_obj_add_event_cb(header_widgets.theme_toggle_btn, toggle_theme_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + lv_obj_add_event_cb(header_widgets.keyboard_toggle_btn, toggle_kb_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + lv_obj_add_event_cb(header_widgets.layout_dropdown, layout_dropdown_value_changed_cb, LV_EVENT_VALUE_CHANGED, NULL); + lv_obj_add_event_cb(header_widgets.shutdown_btn, shutdown_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + + /* Calculate keyboard dimensions and container heights */ + lv_obj_update_layout(header); + const int32_t hor_res = lv_display_get_horizontal_resolution(lv_display_get_default()); + const int32_t ver_res = lv_display_get_vertical_resolution(lv_display_get_default()); + const int32_t keyboard_height = ver_res > hor_res ? ver_res / 2.5 : ver_res / 1.8; + + content_height_without_kb = ver_res - lv_obj_get_height(header); + content_height_with_kb = content_height_without_kb - keyboard_height; + + /* Form container - vertical layout */ + form_container = lv_obj_create(lv_screen_active()); + lv_obj_set_flex_flow(form_container, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_align(form_container, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_all(form_container, 40, LV_PART_MAIN); + lv_obj_remove_flag(form_container, LV_OBJ_FLAG_SCROLLABLE); + + /* Field label */ + lv_obj_t *label = lv_label_create(form_container); + lv_label_set_text(label, field->label ? field->label : field->name); + lv_obj_set_style_pad_bottom(label, 20, LV_PART_MAIN); + + /* Textarea container */ + lv_obj_t *textarea_container = lv_obj_create(form_container); + lv_obj_set_size(textarea_container, LV_PCT(80), LV_SIZE_CONTENT); + lv_obj_set_flex_flow(textarea_container, LV_FLEX_FLOW_ROW); + + /* Create textarea and restore content */ + form_textarea = lv_textarea_create(textarea_container); + lv_textarea_set_one_line(form_textarea, true); + if (field->type == F0_FIELD_TYPE_PASSWORD) { + lv_textarea_set_password_mode(form_textarea, true); + lv_textarea_set_password_bullet(form_textarea, conf_opts.textarea.bullet); + } + lv_obj_add_event_cb(form_textarea, field_submit_cb, LV_EVENT_READY, NULL); + lv_obj_set_flex_grow(form_textarea, 1); + lv_obj_add_state(form_textarea, LV_STATE_FOCUSED); + + /* Reveal / obscure password button */ + if (field->type == F0_FIELD_TYPE_PASSWORD) { + lv_obj_update_layout(form_textarea); + const int32_t textarea_height = lv_obj_get_height(form_textarea); + + lv_obj_t *toggle_pw_btn = lv_button_create(textarea_container); + lv_obj_set_size(toggle_pw_btn, textarea_height, textarea_height); + lv_obj_t *toggle_pw_btn_label = lv_label_create(toggle_pw_btn); + lv_obj_center(toggle_pw_btn_label); + lv_label_set_text(toggle_pw_btn_label, LV_SYMBOL_EYE_OPEN); + lv_obj_set_user_data(toggle_pw_btn, form_textarea); + lv_obj_add_event_cb(toggle_pw_btn, toggle_password_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + } + + /* Restore saved content */ + if (field_values[current_field_index]) { + lv_textarea_set_text(form_textarea, field_values[current_field_index]); + /* Prevent text from being scrolled off to the left of the textarea */ + lv_obj_update_layout(form_textarea); + lv_obj_scroll_to_x(form_textarea, 0, LV_ANIM_OFF); + } + + /* Navigation bar at bottom */ + lv_obj_t *nav_container = lv_obj_create(lv_screen_active()); + lv_obj_set_size(nav_container, LV_PCT(100), LV_SIZE_CONTENT); + lv_obj_set_flex_flow(nav_container, LV_FLEX_FLOW_ROW); + lv_obj_set_style_pad_all(nav_container, 10, LV_PART_MAIN); + + /* Previous button */ + lv_obj_t *prev_btn = lv_button_create(nav_container); + lv_obj_t *prev_label = lv_label_create(prev_btn); + lv_label_set_text(prev_label, "Previous"); + lv_obj_center(prev_label); + lv_obj_add_event_cb(prev_btn, prev_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + if (current_field_index == 0) { + lv_obj_add_flag(prev_btn, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_remove_flag(prev_btn, LV_OBJ_FLAG_HIDDEN); + } + + /* Spacer to push Next to the right */ + lv_obj_t *spacer = lv_obj_create(nav_container); + lv_obj_set_flex_grow(spacer, 1); + lv_obj_set_height(spacer, 0); + + /* Next button */ + lv_obj_t *next_btn = lv_button_create(nav_container); + lv_obj_t *next_label = lv_label_create(next_btn); + lv_label_set_text(next_label, current_field_index >= conf_opts.num_fields - 1 ? "Submit" : "Next"); + lv_obj_center(next_label); + lv_obj_add_event_cb(next_btn, next_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + + /* Update layout to get nav bar height */ + lv_obj_update_layout(nav_container); + const int32_t nav_height = lv_obj_get_height(nav_container); + + /* Adjust content heights for nav bar */ + content_height_without_kb -= nav_height; + content_height_with_kb -= nav_height; + + /* Update form container size to account for nav bar */ + lv_obj_set_size(form_container, LV_PCT(100), is_keyboard_hidden ? content_height_without_kb : content_height_with_kb); + + /* Create keyboard widget */ + bbx_keyboard_config_t keyboard_config; + bbx_keyboard_init_config(&keyboard_config); + keyboard_config.layout_id = (int)conf_opts.keyboard.layout_id; + keyboard_config.height = keyboard_height; + keyboard_config.popovers = conf_opts.keyboard.popovers; + keyboard_config.value_changed_callback = keyboard_value_changed_cb; + keyboard_config.ready_callback = keyboard_ready_cb; + keyboard = bbx_keyboard_create(lv_screen_active(), form_textarea, &keyboard_config); + + /* Configuring routing for physical keyboard input into the textarea */ + lv_group_t *keyboard_input_group = lv_group_create(); + bbx_indev_set_keyboard_input_group(keyboard_input_group); + lv_group_add_obj(keyboard_input_group, form_textarea); +} + +static void show_summary_screen(void) { + /* Clear screen */ + lv_obj_clean(lv_screen_active()); + + /* Header */ + bbx_header_config_t header_config; + bbx_header_init_config(&header_config); + header_config.show_keyboard_toggle = false; + header_config.show_layout_dropdown = false; + + bbx_header_widgets_t header_widgets; + lv_obj_t *header = bbx_header_create(lv_screen_active(), &header_config, &header_widgets); + lv_obj_add_flag(header, BBX_WIDGET_HEADER); + lv_theme_apply(header); + lv_obj_add_event_cb(header_widgets.theme_toggle_btn, toggle_theme_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + + /* Summary container */ + lv_obj_t *container = lv_obj_create(lv_screen_active()); + lv_obj_set_size(container, LV_PCT(100), LV_PCT(80)); + lv_obj_set_flex_flow(container, LV_FLEX_FLOW_COLUMN); + lv_obj_set_style_pad_all(container, 20, LV_PART_MAIN); + + /* Title */ + lv_obj_t *title = lv_label_create(container); + lv_label_set_text(title, "Summary"); + lv_obj_set_style_pad_bottom(title, 20, LV_PART_MAIN); + + /* Field list */ + for (int i = 0; i < conf_opts.num_fields; i++) { + f0_form_field_t *field = &conf_opts.fields[i]; + const char *value = field_values[i] ? field_values[i] : ""; + + lv_obj_t *item_btn = lv_button_create(container); + lv_obj_set_width(item_btn, LV_PCT(100)); + lv_obj_set_user_data(item_btn, (void*)(intptr_t)i); + lv_obj_add_event_cb(item_btn, summary_field_clicked_cb, LV_EVENT_CLICKED, NULL); + + lv_obj_t *item_container = lv_obj_create(item_btn); + lv_obj_set_flex_flow(item_container, LV_FLEX_FLOW_COLUMN); + lv_obj_set_width(item_container, LV_PCT(100)); + lv_obj_add_flag(item_container, LV_OBJ_FLAG_EVENT_BUBBLE); + + lv_obj_t *label = lv_label_create(item_container); + lv_label_set_text(label, field->label ? field->label : field->name); + lv_obj_set_style_text_decor(label, LV_TEXT_DECOR_UNDERLINE, LV_PART_MAIN); + + lv_obj_t *value_label = lv_label_create(item_container); + if (strlen(value) > 0) { + if (field->type == F0_FIELD_TYPE_PASSWORD) { + lv_label_set_text(value_label, F0_PASSWORD_HIDDEN_DOTS); + + /* Add toggle button for password */ + lv_obj_t *toggle_btn = lv_button_create(item_container); + lv_obj_set_size(toggle_btn, 40, 30); + lv_obj_set_user_data(toggle_btn, value_label); + + lv_obj_t *toggle_label = lv_label_create(toggle_btn); + lv_label_set_text(toggle_label, LV_SYMBOL_EYE_OPEN); + lv_obj_center(toggle_label); + lv_obj_add_event_cb(toggle_btn, toggle_password_summary_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + } else { + lv_label_set_text(value_label, value); + } + } else { + lv_label_set_text(value_label, "(empty)"); + } + + /* Save field index to obj to reference later in summary_field_click_cb */ + lv_obj_set_user_data(item_container, (void*)(intptr_t)i); + lv_obj_set_user_data(label, (void*)(intptr_t)i); + lv_obj_set_user_data(value_label, (void*)(intptr_t)i); + } + + /* Spacer for button positioning */ + lv_obj_t *spacer = lv_obj_create(container); + lv_obj_set_height(spacer, 20); + lv_obj_set_width(spacer, 0); + + /* Button container for centering */ + lv_obj_t *button_container = lv_obj_create(container); + lv_obj_set_size(button_container, LV_PCT(100), LV_SIZE_CONTENT); + lv_obj_set_flex_flow(button_container, LV_FLEX_FLOW_ROW); + lv_obj_set_flex_align(button_container, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + + /* Finish button */ + lv_obj_t *finish_btn = lv_button_create(button_container); + lv_obj_t *finish_label = lv_label_create(finish_btn); + lv_label_set_text(finish_label, "Finish"); + lv_obj_center(finish_label); + lv_obj_add_event_cb(finish_btn, finish_cb, LV_EVENT_CLICKED, NULL); + + /* Set up keyboard input for summary screen */ + lv_group_t *summary_input_group = lv_group_create(); + bbx_indev_set_keyboard_input_group(summary_input_group); + lv_group_add_obj(summary_input_group, finish_btn); +} + +int main(int argc, char *argv[]) { + f0_cli_parse_opts(argc, argv, &cli_opts); + + if (cli_opts.common.verbose) { + bbx_log_set_level(BBX_LOG_LEVEL_VERBOSE); + } + + /* Parse config files */ + f0_config_init_opts(&conf_opts); + f0_config_parse_file("/usr/share/f0rmz/f0rmz.conf", &conf_opts); + f0_config_parse_directory("/usr/share/f0rmz/f0rmz.conf.d", &conf_opts); + f0_config_parse_file("/etc/f0rmz.conf", &conf_opts); + f0_config_parse_directory("/etc/f0rmz.conf.d", &conf_opts); + f0_config_parse_file(cli_opts.config_file, &conf_opts); + + /* Prepare current TTY and clean up on termination */ + bbx_terminal_prepare_current_terminal(!conf_opts.quirks.terminal_prevent_graphics_mode, !conf_opts.quirks.terminal_allow_keyboard_input); + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = sigaction_handler; + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); + + /* Initialize LVGL */ + lv_init(); + lv_log_register_print_cb(bbx_log_print_cb); + + /* Populate display config */ + bbx_display_config_t display_config = { + .hor_res = cli_opts.common.hor_res, + .ver_res = cli_opts.common.ver_res, + .x_offset = cli_opts.common.x_offset, + .y_offset = cli_opts.common.y_offset, + .dpi = cli_opts.common.dpi, + .fbdev_force_refresh = conf_opts.quirks.fbdev_force_refresh + }; + + /* Initialize display */ + lv_display_t *disp = bbx_display_create(conf_opts.general.backend, &display_config); + if (!disp) { + exit_failure(); + } + + /* Prepare for routing physical keyboard input into the textarea */ + lv_group_t *keyboard_input_group = lv_group_create(); + bbx_indev_set_keyboard_input_group(keyboard_input_group); + + /* Start input device monitor and auto-connect available devices */ + bbx_indev_start_monitor_and_autoconnect(conf_opts.input.keyboard, conf_opts.input.pointer, conf_opts.input.touchscreen); + + /* Hide the on-screen keyboard by default if a physical keyboard is connected */ + if (conf_opts.keyboard.autohide && bbx_indev_is_keyboard_connected()) { + is_keyboard_hidden = true; + } + + /* Prevent scrolling when keyboard is off-screen */ + lv_obj_t *screen = lv_screen_active(); + lv_theme_apply(screen); + lv_obj_set_flex_flow(screen, LV_FLEX_FLOW_COLUMN); + lv_obj_remove_flag(screen, LV_OBJ_FLAG_SCROLLABLE); + + /* Initialise theme */ + set_theme(is_alternate_theme); + + /* Create header */ + show_intro_screen(); + + /* Main loop */ + while(1) { + uint32_t time_till_next = lv_timer_handler(); + usleep(time_till_next * 1000); + } + + return 0; +} diff --git a/f0rmz/meson.build b/f0rmz/meson.build new file mode 100644 index 0000000..80239c8 --- /dev/null +++ b/f0rmz/meson.build @@ -0,0 +1,34 @@ +# Copyright 2025 buffybox contributors +# SPDX-License-Identifier: GPL-3.0-or-later + +f0rmz_sources = files( + 'command_line.c', + 'config.c', + 'main.c', + 'sq2lv_layouts.c' +) + +f0rmz_dependencies = [ + common_dependencies, + depinih, + depxkbcommon +] + +f0rmz_args = [] + +deplibdrm = dependency('libdrm', required: get_option('with-drm')) +if deplibdrm.found() + f0rmz_dependencies += deplibdrm + f0rmz_args += '-DLV_USE_LINUX_DRM=1' +else + f0rmz_args += '-DLV_USE_LINUX_DRM=0' +endif + +executable('f0rmz', + include_directories: common_include_dirs, + sources: f0rmz_sources + shared_sources + squeek2lvgl_sources + lvgl_sources + header_sources, + dependencies: f0rmz_dependencies, + c_args: f0rmz_args, + install: true, + install_tag: 'f0rmz' +) diff --git a/f0rmz/sq2lv_layouts.c b/f0rmz/sq2lv_layouts.c new file mode 100644 index 0000000..fb3c2e3 --- /dev/null +++ b/f0rmz/sq2lv_layouts.c @@ -0,0 +1,949 @@ +/** + * Auto-generated with squeek2lvgl + **/ + +#include "sq2lv_layouts.h" +#include "../squeek2lvgl/sq2lv.h" + +#define SQ2LV_SYMBOL_SHIFT "\xef\x8d\x9b" + +/** + * Layout: US English - generated from us + **/ + +static const char * const name_us = "US English"; +static const char * const short_name_us = "us"; + +/* Layer: Lowercase letters - generated from base */ + +static const int num_keys_lower_us = 44; + +static const char * const keycaps_lower_us[] = { \ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \ + "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "\n", \ + "a", "s", "d", "f", "g", "h", "j", "k", "l", "\n", \ + SQ2LV_SYMBOL_SHIFT, "z", "x", "c", "v", "b", "n", "m", LV_SYMBOL_BACKSPACE, "\n", \ + "123", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_lower_us[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_lower_us = 0; + +static const int * const modifier_idxs_lower_us = NULL; + +static const int num_switchers_lower_us = 2; + +static const int switcher_idxs_lower_us[] = { \ + 29, 38 \ +}; + +static const int switcher_dests_lower_us[] = { \ + 1, 2 \ +}; + +/* Layer: Uppercase letters - generated from upper */ + +static const int num_keys_upper_us = 44; + +static const char * const keycaps_upper_us[] = { \ + "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "\n", \ + "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "\n", \ + "A", "S", "D", "F", "G", "H", "J", "K", "L", "\n", \ + SQ2LV_SYMBOL_SHIFT, "Z", "X", "C", "V", "B", "N", "M", LV_SYMBOL_BACKSPACE, "\n", \ + "123", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_upper_us[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_MOD_ACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_upper_us = 0; + +static const int * const modifier_idxs_upper_us = NULL; + +static const int num_switchers_upper_us = 2; + +static const int switcher_idxs_upper_us[] = { \ + 29, 38 \ +}; + +static const int switcher_dests_upper_us[] = { \ + 0, 2 \ +}; + +/* Layer: Numbers / symbols - generated from numbers */ + +static const int num_keys_numbers_us = 36; + +static const char * const keycaps_numbers_us[] = { \ + "", "\n", \ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \ + "@", "#", "$", "%", "&", "-", "_", "+", "(", ")", "\n", \ + "*/=", ",", "\"", "'", ":", ";", "!", "?", LV_SYMBOL_BACKSPACE, "\n", \ + "ABC", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_numbers_us[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_numbers_us = 0; + +static const int * const modifier_idxs_numbers_us = NULL; + +static const int num_switchers_numbers_us = 2; + +static const int switcher_idxs_numbers_us[] = { \ + 21, 30 \ +}; + +static const int switcher_dests_numbers_us[] = { \ + 3, 0 \ +}; + +/* Layer: Symbols - generated from symbols */ + +static const int num_keys_symbols_us = 36; + +static const char * const keycaps_symbols_us[] = { \ + "", "\n", \ + "~", "`", "|", "·", "√", "π", "τ", "÷", "×", "¶", "\n", \ + "©", "®", "£", "€", "¥", "^", "°", "*", "{", "}", "\n", \ + "123", "\\", "/", "<", ">", "=", "[", "]", LV_SYMBOL_BACKSPACE, "\n", \ + "ABC", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_symbols_us[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_symbols_us = 0; + +static const int * const modifier_idxs_symbols_us = NULL; + +static const int num_switchers_symbols_us = 2; + +static const int switcher_idxs_symbols_us[] = { \ + 21, 30 \ +}; + +static const int switcher_dests_symbols_us[] = { \ + 2, 0 \ +}; + +/* Layer array */ + +static const int num_layers_us = 4; + +static const sq2lv_layer_t layers_us[] = { + { + .num_keys = num_keys_lower_us, + .keycaps = keycaps_lower_us, + .attributes = attributes_lower_us, + .num_modifiers = num_modifiers_lower_us, + .modifier_idxs = modifier_idxs_lower_us, + .num_switchers = num_switchers_lower_us, + .switcher_idxs = switcher_idxs_lower_us, + .switcher_dests = switcher_dests_lower_us + }, + { + .num_keys = num_keys_upper_us, + .keycaps = keycaps_upper_us, + .attributes = attributes_upper_us, + .num_modifiers = num_modifiers_upper_us, + .modifier_idxs = modifier_idxs_upper_us, + .num_switchers = num_switchers_upper_us, + .switcher_idxs = switcher_idxs_upper_us, + .switcher_dests = switcher_dests_upper_us + }, + { + .num_keys = num_keys_numbers_us, + .keycaps = keycaps_numbers_us, + .attributes = attributes_numbers_us, + .num_modifiers = num_modifiers_numbers_us, + .modifier_idxs = modifier_idxs_numbers_us, + .num_switchers = num_switchers_numbers_us, + .switcher_idxs = switcher_idxs_numbers_us, + .switcher_dests = switcher_dests_numbers_us + }, + { + .num_keys = num_keys_symbols_us, + .keycaps = keycaps_symbols_us, + .attributes = attributes_symbols_us, + .num_modifiers = num_modifiers_symbols_us, + .modifier_idxs = modifier_idxs_symbols_us, + .num_switchers = num_switchers_symbols_us, + .switcher_idxs = switcher_idxs_symbols_us, + .switcher_dests = switcher_dests_symbols_us + } +}; + +/** + * Layout: Deutsch - generated from de + **/ + +static const char * const name_de = "Deutsch"; +static const char * const short_name_de = "de"; + +/* Layer: Lowercase letters - generated from base */ + +static const int num_keys_lower_de = 46; + +static const char * const keycaps_lower_de[] = { \ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \ + "q", "w", "e", "r", "t", "z", "u", "i", "o", "p", "\n", \ + "a", "s", "d", "f", "g", "h", "j", "k", "l", "\n", \ + SQ2LV_SYMBOL_SHIFT, "y", "x", "c", "v", "b", "n", "m", LV_SYMBOL_BACKSPACE, "\n", \ + "123", "äÄ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ",", ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_lower_de[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_lower_de = 0; + +static const int * const modifier_idxs_lower_de = NULL; + +static const int num_switchers_lower_de = 3; + +static const int switcher_idxs_lower_de[] = { \ + 29, 38, 39 \ +}; + +static const int switcher_dests_lower_de[] = { \ + 1, 2, 4 \ +}; + +/* Layer: Uppercase letters - generated from upper */ + +static const int num_keys_upper_de = 46; + +static const char * const keycaps_upper_de[] = { \ + "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "\n", \ + "Q", "W", "E", "R", "T", "Z", "U", "I", "O", "P", "\n", \ + "A", "S", "D", "F", "G", "H", "J", "K", "L", "\n", \ + SQ2LV_SYMBOL_SHIFT, "Y", "X", "C", "V", "B", "N", "M", LV_SYMBOL_BACKSPACE, "\n", \ + "123", "äÄ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "!", "?", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_upper_de[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_MOD_ACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_upper_de = 0; + +static const int * const modifier_idxs_upper_de = NULL; + +static const int num_switchers_upper_de = 3; + +static const int switcher_idxs_upper_de[] = { \ + 29, 38, 39 \ +}; + +static const int switcher_dests_upper_de[] = { \ + 0, 2, 4 \ +}; + +/* Layer: Numbers / symbols - generated from numbers */ + +static const int num_keys_numbers_de = 38; + +static const char * const keycaps_numbers_de[] = { \ + "", "\n", \ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \ + "@", "#", "€", "%", "&", "-", "_", "+", "(", ")", "\n", \ + "*/=", ";", "\"", "'", ":", "=", "<", ">", LV_SYMBOL_BACKSPACE, "\n", \ + "abc", "äÄ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ",", ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_numbers_de[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_numbers_de = 0; + +static const int * const modifier_idxs_numbers_de = NULL; + +static const int num_switchers_numbers_de = 3; + +static const int switcher_idxs_numbers_de[] = { \ + 21, 30, 31 \ +}; + +static const int switcher_dests_numbers_de[] = { \ + 3, 0, 4 \ +}; + +/* Layer: Symbols - generated from symbols */ + +static const int num_keys_symbols_de = 38; + +static const char * const keycaps_symbols_de[] = { \ + "", "\n", \ + "~", "`", "´", "|", "·", "√", "µ", "÷", "×", "¶", "\n", \ + "©", "®", "£", "$", "¥", "^", "°", "*", "{", "}", "\n", \ + "123", "\\", "/", "§", "π", "τ", "[", "]", LV_SYMBOL_BACKSPACE, "\n", \ + "abc", "äÄ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ",", ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_symbols_de[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_symbols_de = 0; + +static const int * const modifier_idxs_symbols_de = NULL; + +static const int num_switchers_symbols_de = 3; + +static const int switcher_idxs_symbols_de[] = { \ + 21, 30, 31 \ +}; + +static const int switcher_dests_symbols_de[] = { \ + 2, 0, 4 \ +}; + +/* Layer: Special characters - generated from eschars */ + +static const int num_keys_special_de = 38; + +static const char * const keycaps_special_de[] = { \ + "", "\n", \ + "ä", "è", "é", "ö", "ü", "Ä", "È", "É", "Ö", "Ü", "\n", \ + "à", "â", "ê", "î", "ô", "À", "Â", "È", "Î", "Ô", "\n", \ + "123", "«", "»", "ç", "Ç", "æ", "œ", "ß", LV_SYMBOL_BACKSPACE, "\n", \ + "abc", "äÄ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "„", "“", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_special_de[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_ACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_special_de = 0; + +static const int * const modifier_idxs_special_de = NULL; + +static const int num_switchers_special_de = 3; + +static const int switcher_idxs_special_de[] = { \ + 21, 30, 31 \ +}; + +static const int switcher_dests_special_de[] = { \ + 2, 0, 0 \ +}; + +/* Layer array */ + +static const int num_layers_de = 5; + +static const sq2lv_layer_t layers_de[] = { + { + .num_keys = num_keys_lower_de, + .keycaps = keycaps_lower_de, + .attributes = attributes_lower_de, + .num_modifiers = num_modifiers_lower_de, + .modifier_idxs = modifier_idxs_lower_de, + .num_switchers = num_switchers_lower_de, + .switcher_idxs = switcher_idxs_lower_de, + .switcher_dests = switcher_dests_lower_de + }, + { + .num_keys = num_keys_upper_de, + .keycaps = keycaps_upper_de, + .attributes = attributes_upper_de, + .num_modifiers = num_modifiers_upper_de, + .modifier_idxs = modifier_idxs_upper_de, + .num_switchers = num_switchers_upper_de, + .switcher_idxs = switcher_idxs_upper_de, + .switcher_dests = switcher_dests_upper_de + }, + { + .num_keys = num_keys_numbers_de, + .keycaps = keycaps_numbers_de, + .attributes = attributes_numbers_de, + .num_modifiers = num_modifiers_numbers_de, + .modifier_idxs = modifier_idxs_numbers_de, + .num_switchers = num_switchers_numbers_de, + .switcher_idxs = switcher_idxs_numbers_de, + .switcher_dests = switcher_dests_numbers_de + }, + { + .num_keys = num_keys_symbols_de, + .keycaps = keycaps_symbols_de, + .attributes = attributes_symbols_de, + .num_modifiers = num_modifiers_symbols_de, + .modifier_idxs = modifier_idxs_symbols_de, + .num_switchers = num_switchers_symbols_de, + .switcher_idxs = switcher_idxs_symbols_de, + .switcher_dests = switcher_dests_symbols_de + }, + { + .num_keys = num_keys_special_de, + .keycaps = keycaps_special_de, + .attributes = attributes_special_de, + .num_modifiers = num_modifiers_special_de, + .modifier_idxs = modifier_idxs_special_de, + .num_switchers = num_switchers_special_de, + .switcher_idxs = switcher_idxs_special_de, + .switcher_dests = switcher_dests_special_de + } +}; + +/** + * Layout: Español - generated from es + **/ + +static const char * const name_es = "Español"; +static const char * const short_name_es = "es"; + +/* Layer: Lowercase letters - generated from base */ + +static const int num_keys_lower_es = 47; + +static const char * const keycaps_lower_es[] = { \ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \ + "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "\n", \ + "a", "s", "d", "f", "g", "h", "j", "k", "l", "ñ", "\n", \ + SQ2LV_SYMBOL_SHIFT, "z", "x", "c", "v", "b", "n", "m", LV_SYMBOL_BACKSPACE, "\n", \ + "123", "áÁ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "?", ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_lower_es[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_lower_es = 0; + +static const int * const modifier_idxs_lower_es = NULL; + +static const int num_switchers_lower_es = 3; + +static const int switcher_idxs_lower_es[] = { \ + 30, 39, 40 \ +}; + +static const int switcher_dests_lower_es[] = { \ + 1, 2, 4 \ +}; + +/* Layer: Uppercase letters - generated from upper */ + +static const int num_keys_upper_es = 47; + +static const char * const keycaps_upper_es[] = { \ + "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "\n", \ + "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "\n", \ + "A", "S", "D", "F", "G", "H", "J", "K", "L", "Ñ", "\n", \ + SQ2LV_SYMBOL_SHIFT, "Z", "X", "C", "V", "B", "N", "M", LV_SYMBOL_BACKSPACE, "\n", \ + "123", "áÁ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "¿", ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_upper_es[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_MOD_ACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_upper_es = 0; + +static const int * const modifier_idxs_upper_es = NULL; + +static const int num_switchers_upper_es = 3; + +static const int switcher_idxs_upper_es[] = { \ + 30, 39, 40 \ +}; + +static const int switcher_dests_upper_es[] = { \ + 0, 2, 4 \ +}; + +/* Layer: Numbers / symbols - generated from numbers */ + +static const int num_keys_numbers_es = 38; + +static const char * const keycaps_numbers_es[] = { \ + "", "\n", \ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \ + "@", "#", "€", "%", "&", "-", "_", "+", "(", ")", "\n", \ + "*/=", ",", "\"", "'", ":", ";", "!", "=", LV_SYMBOL_BACKSPACE, "\n", \ + "abc", "áÁ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "?", ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_numbers_es[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_numbers_es = 0; + +static const int * const modifier_idxs_numbers_es = NULL; + +static const int num_switchers_numbers_es = 3; + +static const int switcher_idxs_numbers_es[] = { \ + 21, 30, 31 \ +}; + +static const int switcher_dests_numbers_es[] = { \ + 3, 0, 4 \ +}; + +/* Layer: Symbols - generated from symbols */ + +static const int num_keys_symbols_es = 38; + +static const char * const keycaps_symbols_es[] = { \ + "", "\n", \ + "~", "`", "|", "·", "√", "π", "τ", "÷", "×", "¶", "\n", \ + "©", "®", "£", "$", "¥", "^", "°", "*", "{", "}", "\n", \ + "123", "\\", "/", "<", ">", "=", "[", "]", LV_SYMBOL_BACKSPACE, "\n", \ + "abc", "áÁ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "?", ".", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_symbols_es[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_symbols_es = 0; + +static const int * const modifier_idxs_symbols_es = NULL; + +static const int num_switchers_symbols_es = 3; + +static const int switcher_idxs_symbols_es[] = { \ + 21, 30, 31 \ +}; + +static const int switcher_dests_symbols_es[] = { \ + 2, 0, 4 \ +}; + +/* Layer: Special characters - generated from eschars */ + +static const int num_keys_special_es = 38; + +static const char * const keycaps_special_es[] = { \ + "", "\n", \ + "á", "é", "í", "ó", "ú", "Á", "É", "Í", "Ó", "Ú", "\n", \ + "à", "è", "ì", "ò", "ù", "À", "È", "Ì", "Ò", "Ù", "\n", \ + "123", "ü", "ç", "ï", "Ü", "Ç", "Ï", "¡", LV_SYMBOL_BACKSPACE, "\n", \ + "abc", "áÁ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "«", "»", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_special_es[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_ACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_special_es = 0; + +static const int * const modifier_idxs_special_es = NULL; + +static const int num_switchers_special_es = 3; + +static const int switcher_idxs_special_es[] = { \ + 21, 30, 31 \ +}; + +static const int switcher_dests_special_es[] = { \ + 2, 0, 0 \ +}; + +/* Layer array */ + +static const int num_layers_es = 5; + +static const sq2lv_layer_t layers_es[] = { + { + .num_keys = num_keys_lower_es, + .keycaps = keycaps_lower_es, + .attributes = attributes_lower_es, + .num_modifiers = num_modifiers_lower_es, + .modifier_idxs = modifier_idxs_lower_es, + .num_switchers = num_switchers_lower_es, + .switcher_idxs = switcher_idxs_lower_es, + .switcher_dests = switcher_dests_lower_es + }, + { + .num_keys = num_keys_upper_es, + .keycaps = keycaps_upper_es, + .attributes = attributes_upper_es, + .num_modifiers = num_modifiers_upper_es, + .modifier_idxs = modifier_idxs_upper_es, + .num_switchers = num_switchers_upper_es, + .switcher_idxs = switcher_idxs_upper_es, + .switcher_dests = switcher_dests_upper_es + }, + { + .num_keys = num_keys_numbers_es, + .keycaps = keycaps_numbers_es, + .attributes = attributes_numbers_es, + .num_modifiers = num_modifiers_numbers_es, + .modifier_idxs = modifier_idxs_numbers_es, + .num_switchers = num_switchers_numbers_es, + .switcher_idxs = switcher_idxs_numbers_es, + .switcher_dests = switcher_dests_numbers_es + }, + { + .num_keys = num_keys_symbols_es, + .keycaps = keycaps_symbols_es, + .attributes = attributes_symbols_es, + .num_modifiers = num_modifiers_symbols_es, + .modifier_idxs = modifier_idxs_symbols_es, + .num_switchers = num_switchers_symbols_es, + .switcher_idxs = switcher_idxs_symbols_es, + .switcher_dests = switcher_dests_symbols_es + }, + { + .num_keys = num_keys_special_es, + .keycaps = keycaps_special_es, + .attributes = attributes_special_es, + .num_modifiers = num_modifiers_special_es, + .modifier_idxs = modifier_idxs_special_es, + .num_switchers = num_switchers_special_es, + .switcher_idxs = switcher_idxs_special_es, + .switcher_dests = switcher_dests_special_es + } +}; + +/** + * Layout: Français - generated from fr + **/ + +static const char * const name_fr = "Français"; +static const char * const short_name_fr = "fr"; + +/* Layer: Lowercase letters - generated from base */ + +static const int num_keys_lower_fr = 45; + +static const char * const keycaps_lower_fr[] = { \ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \ + "a", "z", "e", "r", "t", "y", "u", "i", "o", "p", "\n", \ + "q", "s", "d", "f", "g", "h", "j", "k", "l", "m", "\n", \ + SQ2LV_SYMBOL_SHIFT, "w", "x", "c", "v", "b", "n", ".", LV_SYMBOL_BACKSPACE, "\n", \ + "123", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "âÂ", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_lower_fr[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_lower_fr = 0; + +static const int * const modifier_idxs_lower_fr = NULL; + +static const int num_switchers_lower_fr = 3; + +static const int switcher_idxs_lower_fr[] = { \ + 30, 39, 43 \ +}; + +static const int switcher_dests_lower_fr[] = { \ + 1, 2, 4 \ +}; + +/* Layer: Uppercase letters - generated from upper */ + +static const int num_keys_upper_fr = 45; + +static const char * const keycaps_upper_fr[] = { \ + "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "\n", \ + "A", "Z", "E", "R", "T", "Y", "U", "I", "O", "P", "\n", \ + "Q", "S", "D", "F", "G", "H", "J", "K", "L", "M", "\n", \ + SQ2LV_SYMBOL_SHIFT, "W", "X", "C", "V", "B", "N", ",", LV_SYMBOL_BACKSPACE, "\n", \ + "123", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "âÂ", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_upper_fr[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_MOD_ACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_upper_fr = 0; + +static const int * const modifier_idxs_upper_fr = NULL; + +static const int num_switchers_upper_fr = 3; + +static const int switcher_idxs_upper_fr[] = { \ + 30, 39, 43 \ +}; + +static const int switcher_dests_upper_fr[] = { \ + 0, 2, 4 \ +}; + +/* Layer: Numbers / symbols - generated from numbers */ + +static const int num_keys_numbers_fr = 36; + +static const char * const keycaps_numbers_fr[] = { \ + "", "\n", \ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \ + "@", "#", "€", "%", "&", "-", "_", "+", "(", ")", "\n", \ + "*/=", ",", "\"", "'", ":", ";", "!", "?", LV_SYMBOL_BACKSPACE, "\n", \ + "abc", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "âÂ", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_numbers_fr[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_numbers_fr = 0; + +static const int * const modifier_idxs_numbers_fr = NULL; + +static const int num_switchers_numbers_fr = 3; + +static const int switcher_idxs_numbers_fr[] = { \ + 21, 30, 34 \ +}; + +static const int switcher_dests_numbers_fr[] = { \ + 3, 0, 4 \ +}; + +/* Layer: Symbols - generated from symbols */ + +static const int num_keys_symbols_fr = 36; + +static const char * const keycaps_symbols_fr[] = { \ + "", "\n", \ + "~", "`", "|", "·", "√", "π", "τ", "÷", "×", "¶", "\n", \ + "©", "®", "£", "$", "¥", "^", "°", "*", "{", "}", "\n", \ + "123", "\\", "/", "<", ">", "=", "[", "]", LV_SYMBOL_BACKSPACE, "\n", \ + "abc", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "âÂ", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_symbols_fr[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, SQ2LV_CTRL_MOD_INACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_symbols_fr = 0; + +static const int * const modifier_idxs_symbols_fr = NULL; + +static const int num_switchers_symbols_fr = 3; + +static const int switcher_idxs_symbols_fr[] = { \ + 21, 30, 34 \ +}; + +static const int switcher_dests_symbols_fr[] = { \ + 2, 0, 4 \ +}; + +/* Layer: Special characters - generated from eschars */ + +static const int num_keys_special_fr = 36; + +static const char * const keycaps_special_fr[] = { \ + "", "\n", \ + "à", "â", "ç", "é", "è", "ê", "î", "ô", "ù", "û", "\n", \ + "À", "Â", "Ç", "É", "È", "Ê", "Î", "Ô", "Ù", "Û", "\n", \ + "123", "æ", "œ", "ä", "ë", "ï", "ö", "ü", LV_SYMBOL_BACKSPACE, "\n", \ + "abc", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "âÂ", LV_SYMBOL_OK, "" \ +}; + +static const lv_buttonmatrix_ctrl_t attributes_special_fr[] = { \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_HIDDEN | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, LV_BUTTONMATRIX_CTRL_POPOVER | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \ + SQ2LV_CTRL_NON_CHAR | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, SQ2LV_CTRL_MOD_ACTIVE | LV_BUTTONMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 3 \ +}; + +static const int num_modifiers_special_fr = 0; + +static const int * const modifier_idxs_special_fr = NULL; + +static const int num_switchers_special_fr = 3; + +static const int switcher_idxs_special_fr[] = { \ + 21, 30, 34 \ +}; + +static const int switcher_dests_special_fr[] = { \ + 2, 0, 0 \ +}; + +/* Layer array */ + +static const int num_layers_fr = 5; + +static const sq2lv_layer_t layers_fr[] = { + { + .num_keys = num_keys_lower_fr, + .keycaps = keycaps_lower_fr, + .attributes = attributes_lower_fr, + .num_modifiers = num_modifiers_lower_fr, + .modifier_idxs = modifier_idxs_lower_fr, + .num_switchers = num_switchers_lower_fr, + .switcher_idxs = switcher_idxs_lower_fr, + .switcher_dests = switcher_dests_lower_fr + }, + { + .num_keys = num_keys_upper_fr, + .keycaps = keycaps_upper_fr, + .attributes = attributes_upper_fr, + .num_modifiers = num_modifiers_upper_fr, + .modifier_idxs = modifier_idxs_upper_fr, + .num_switchers = num_switchers_upper_fr, + .switcher_idxs = switcher_idxs_upper_fr, + .switcher_dests = switcher_dests_upper_fr + }, + { + .num_keys = num_keys_numbers_fr, + .keycaps = keycaps_numbers_fr, + .attributes = attributes_numbers_fr, + .num_modifiers = num_modifiers_numbers_fr, + .modifier_idxs = modifier_idxs_numbers_fr, + .num_switchers = num_switchers_numbers_fr, + .switcher_idxs = switcher_idxs_numbers_fr, + .switcher_dests = switcher_dests_numbers_fr + }, + { + .num_keys = num_keys_symbols_fr, + .keycaps = keycaps_symbols_fr, + .attributes = attributes_symbols_fr, + .num_modifiers = num_modifiers_symbols_fr, + .modifier_idxs = modifier_idxs_symbols_fr, + .num_switchers = num_switchers_symbols_fr, + .switcher_idxs = switcher_idxs_symbols_fr, + .switcher_dests = switcher_dests_symbols_fr + }, + { + .num_keys = num_keys_special_fr, + .keycaps = keycaps_special_fr, + .attributes = attributes_special_fr, + .num_modifiers = num_modifiers_special_fr, + .modifier_idxs = modifier_idxs_special_fr, + .num_switchers = num_switchers_special_fr, + .switcher_idxs = switcher_idxs_special_fr, + .switcher_dests = switcher_dests_special_fr + } +}; + +/** + * Public interface + **/ + +const int sq2lv_num_layouts = 4; + +const sq2lv_layout_t sq2lv_layouts[] = { + /* US English */ + { + .name = name_us, + .short_name = short_name_us, + .num_layers = num_layers_us, + .layers = layers_us + }, + /* Deutsch */ + { + .name = name_de, + .short_name = short_name_de, + .num_layers = num_layers_de, + .layers = layers_de + }, + /* Español */ + { + .name = name_es, + .short_name = short_name_es, + .num_layers = num_layers_es, + .layers = layers_es + }, + /* Français */ + { + .name = name_fr, + .short_name = short_name_fr, + .num_layers = num_layers_fr, + .layers = layers_fr + } +}; + +const char * const sq2lv_layout_names = + "US English" "\n" + "Deutsch" "\n" + "Español" "\n" + "Français"; + +const char * const sq2lv_layout_short_names = + "us" "\n" + "de" "\n" + "es" "\n" + "fr"; diff --git a/f0rmz/sq2lv_layouts.h b/f0rmz/sq2lv_layouts.h new file mode 100644 index 0000000..b9b75c0 --- /dev/null +++ b/f0rmz/sq2lv_layouts.h @@ -0,0 +1,61 @@ +/** + * Auto-generated with squeek2lvgl + **/ + +#ifndef SQ2LV_LAYOUTS_H +#define SQ2LV_LAYOUTS_H + +#include "lvgl/lvgl.h" + +#define SQ2LV_SCANCODES_ENABLED 0 + +/* Layout IDs, values can be used as indexes into the sq2lv_layouts array */ +typedef enum { + SQ2LV_LAYOUT_NONE = -1, + SQ2LV_LAYOUT_US = 0, + SQ2LV_LAYOUT_DE = 1, + SQ2LV_LAYOUT_ES = 2, + SQ2LV_LAYOUT_FR = 3 +} sq2lv_layout_id_t; + +/* Layer type */ +typedef struct { + /* Number of keys */ + const int num_keys; + /* Key caps */ + const char * const * const keycaps; + /* Key attributes */ + const lv_buttonmatrix_ctrl_t * const attributes; + /* Number of modifier keys */ + const int num_modifiers; + /* Button indexes of modifier keys */ + const int * const modifier_idxs; + /* Number of buttons that trigger a layer switch */ + const int num_switchers; + /* Button indexes that trigger a layer switch */ + const int * const switcher_idxs; + /* Indexes of layers to jump to when triggering layer switch buttons */ + const int * const switcher_dests; +} sq2lv_layer_t; + +/* Layout type */ +typedef struct { + /* Layout name */ + const char * const name; + /* Layout short name */ + const char * const short_name; + /* Total number of layers */ + const int num_layers; + /* Layers array */ + const sq2lv_layer_t * const layers; +} sq2lv_layout_t; + +/* Layouts */ +extern const int sq2lv_num_layouts; +extern const sq2lv_layout_t sq2lv_layouts[]; + +/* Layout names (suitable for use in lv_dropdown_t) */ +extern const char * const sq2lv_layout_names; +extern const char * const sq2lv_layout_short_names; + +#endif /* SQ2LV_LAYOUTS_H */ diff --git a/meson.build b/meson.build index d5993ad..37af432 100644 --- a/meson.build +++ b/meson.build @@ -22,15 +22,22 @@ endif common_include_dirs = include_directories('.') shared_sources = files( + 'shared/backends.c', 'shared/cursor/cursor.c', + 'shared/cli_common.c', + 'shared/display.c', 'shared/fonts/font_32.c', 'shared/config.c', 'shared/indev.c', + 'shared/keyboard.c', 'shared/log.c', + 'shared/terminal.c', 'shared/theme.c', 'shared/themes.c' ) +header_sources = files('shared/header.c') + squeek2lvgl_sources = files( 'squeek2lvgl/sq2lv.c' ) @@ -47,6 +54,7 @@ common_dependencies = [ subdir('unl0kr') subdir('buffyboard') +subdir('f0rmz') if get_option('man') subdir('man') diff --git a/unl0kr/backends.c b/shared/backends.c similarity index 65% rename from unl0kr/backends.c rename to shared/backends.c index 3fa21b1..74cfd6b 100644 --- a/unl0kr/backends.c +++ b/shared/backends.c @@ -15,7 +15,7 @@ * Public interface */ -const char *ul_backends_backends[] = { +const char *bbx_backends_backends[] = { #if LV_USE_LINUX_FBDEV "fbdev", #endif /* LV_USE_LINUX_FBDEV */ @@ -25,13 +25,13 @@ const char *ul_backends_backends[] = { NULL }; -ul_backends_backend_id_t ul_backends_find_backend_with_name(const char *name) { - for (int i = 0; ul_backends_backends[i] != NULL; ++i) { - if (strcmp(ul_backends_backends[i], name) == 0) { +bbx_backends_backend_id_t bbx_backends_find_backend_with_name(const char *name) { + for (int i = 0; bbx_backends_backends[i] != NULL; ++i) { + if (strcmp(bbx_backends_backends[i], name) == 0) { bbx_log(BBX_LOG_LEVEL_VERBOSE, "Found backend: %s\n", name); return i; } } bbx_log(BBX_LOG_LEVEL_WARNING, "Backend %s not found\n", name); - return UL_BACKENDS_BACKEND_NONE; + return BBX_BACKENDS_BACKEND_NONE; } diff --git a/shared/backends.h b/shared/backends.h new file mode 100644 index 0000000..1bd4766 --- /dev/null +++ b/shared/backends.h @@ -0,0 +1,40 @@ +/** + * Copyright 2022 Eugenio Paolantonio (g7) + * SPDX-License-Identifier: GPL-3.0-or-later + */ + + +#ifndef BBX_BACKENDS_H +#define BBX_BACKENDS_H + +#include "lvgl/lvgl.h" + +/** + * Backend identifiers + * + * Only BBX_BACKENDS_BACKEND_NONE should have an explicit value assigned + */ +typedef enum { + BBX_BACKENDS_BACKEND_NONE = -1, +#if LV_USE_LINUX_FBDEV + BBX_BACKENDS_BACKEND_FBDEV, +#endif /* LV_USE_LINUX_FBDEV */ +#if LV_USE_LINUX_DRM + BBX_BACKENDS_BACKEND_DRM, +#endif /* LV_USE_LINUX_DRM */ +} bbx_backends_backend_id_t; + +/** + * Actual backends + */ +extern const char *bbx_backends_backends[]; + +/** + * Find the first backend with a given name. + * + * @param name backend name + * @return ID of the first matching backend or BBX_BACKENDS_BACKEND_NONE if no backend matched + */ +bbx_backends_backend_id_t bbx_backends_find_backend_with_name(const char *name); + +#endif /* BBX_BACKENDS_H */ diff --git a/shared/cli_common.c b/shared/cli_common.c new file mode 100644 index 0000000..a28ef2b --- /dev/null +++ b/shared/cli_common.c @@ -0,0 +1,52 @@ +/** + * Copyright 2025 buffybox contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "cli_common.h" +#include "log.h" + +#include +#include + +#ifndef PROJECT_VERSION +#define PROJECT_VERSION "?" /* Real version injected by meson during build */ +#endif + +void bbx_cli_init_common_opts(bbx_cli_common_opts *opts) { + opts->hor_res = -1; + opts->ver_res = -1; + opts->x_offset = 0; + opts->y_offset = 0; + opts->dpi = 0; + opts->verbose = false; +} + +int bbx_cli_parse_geometry(const char *optarg, bbx_cli_common_opts *opts) { + /* Try parsing with offset first: NxM@X,Y */ + if (sscanf(optarg, "%ix%i@%i,%i", &(opts->hor_res), &(opts->ver_res), + &(opts->x_offset), &(opts->y_offset)) == 4) { + return 0; + } + + /* Try parsing without offset: NxM */ + if (sscanf(optarg, "%ix%i", &(opts->hor_res), &(opts->ver_res)) == 2) { + return 0; + } + + bbx_log(BBX_LOG_LEVEL_ERROR, "Invalid geometry argument \"%s\"", optarg); + return -1; +} + +int bbx_cli_parse_dpi(const char *optarg, bbx_cli_common_opts *opts) { + if (sscanf(optarg, "%i", &(opts->dpi)) != 1) { + bbx_log(BBX_LOG_LEVEL_ERROR, "Invalid dpi argument \"%s\"", optarg); + return -1; + } + return 0; +} + +void bbx_cli_print_version_and_exit(const char *program_name) { + fprintf(stderr, "%s %s\n", program_name, PROJECT_VERSION); + exit(0); +} diff --git a/shared/cli_common.h b/shared/cli_common.h new file mode 100644 index 0000000..1dba3fa --- /dev/null +++ b/shared/cli_common.h @@ -0,0 +1,58 @@ +/** + * Copyright 2025 buffybox contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef BBX_CLI_COMMON_H +#define BBX_CLI_COMMON_H + +#include + +/** + * Common CLI options shared across buffybox tools + */ +typedef struct { + /* Display geometry */ + int hor_res; + int ver_res; + int x_offset; + int y_offset; + /* DPI override */ + int dpi; + /* Verbose logging */ + bool verbose; +} bbx_cli_common_opts; + +/** + * Initialize common CLI options with default values. + * + * @param opts pointer to the options struct + */ +void bbx_cli_init_common_opts(bbx_cli_common_opts *opts); + +/** + * Parse geometry argument in format "NxM[@X,Y]". + * + * @param optarg the argument string + * @param opts pointer to options struct to populate + * @return 0 on success, -1 on failure + */ +int bbx_cli_parse_geometry(const char *optarg, bbx_cli_common_opts *opts); + +/** + * Parse DPI argument. + * + * @param optarg the argument string + * @param opts pointer to options struct to populate + * @return 0 on success, -1 on failure + */ +int bbx_cli_parse_dpi(const char *optarg, bbx_cli_common_opts *opts); + +/** + * Print version information and exit. + * + * @param program_name name of the program + */ +void bbx_cli_print_version_and_exit(const char *program_name); + +#endif /* BBX_CLI_COMMON_H */ diff --git a/shared/display.c b/shared/display.c new file mode 100644 index 0000000..b6b0ae0 --- /dev/null +++ b/shared/display.c @@ -0,0 +1,91 @@ +/** + * Copyright 2025 buffybox contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "display.h" +#include "log.h" + +#include +#include +#include + +lv_display_t *bbx_display_create(bbx_backends_backend_id_t backend_id, bbx_display_config_t *config) { + lv_display_t *disp = NULL; + + switch (backend_id) { +#if LV_USE_LINUX_FBDEV + case BBX_BACKENDS_BACKEND_FBDEV: + bbx_log(BBX_LOG_LEVEL_VERBOSE, "Using framebuffer backend"); + disp = lv_linux_fbdev_create(); + if (!disp) { + bbx_log(BBX_LOG_LEVEL_ERROR, "Failed to create framebuffer display"); + return NULL; + } + + if (access("/dev/fb0", F_OK) != 0) { + bbx_log(BBX_LOG_LEVEL_ERROR, "/dev/fb0 is not available"); + return NULL; + } + + lv_linux_fbdev_set_file(disp, "/dev/fb0"); + if (config && config->fbdev_force_refresh) { + lv_linux_fbdev_set_force_refresh(disp, true); + } + break; +#endif /* LV_USE_LINUX_FBDEV */ + +#if LV_USE_LINUX_DRM + case BBX_BACKENDS_BACKEND_DRM: + bbx_log(BBX_LOG_LEVEL_VERBOSE, "Using DRM backend"); + disp = lv_linux_drm_create(); + if (!disp) { + bbx_log(BBX_LOG_LEVEL_ERROR, "Failed to create DRM display"); + return NULL; + } + + char drm_path[16]; + bool found = false; + for (int i = 0; i < 9; i++) { + sprintf(drm_path, "/dev/dri/card%d", i); + + if (access(drm_path, F_OK) == 0) { + found = true; + break; + } + } + if (!found) { + bbx_log(BBX_LOG_LEVEL_ERROR, "/dev/dri/card* are not available"); + return NULL; + } + + lv_linux_drm_set_file(disp, drm_path, -1); + break; +#endif /* LV_USE_LINUX_DRM */ + + default: + bbx_log(BBX_LOG_LEVEL_ERROR, "Unable to find suitable backend"); + return NULL; + } + + /* Apply configuration overrides if provided */ + if (config) { + /* Set display offset */ + lv_display_set_offset(disp, config->x_offset, config->y_offset); + + /* Override resolution if specified */ + if (config->hor_res > 0 || config->ver_res > 0) { + lv_display_set_physical_resolution(disp, + lv_display_get_horizontal_resolution(disp), + lv_display_get_vertical_resolution(disp)); + lv_display_set_resolution(disp, config->hor_res, config->ver_res); + } + + /* Override DPI if specified */ + if (config->dpi > 0) { + lv_display_set_dpi(disp, config->dpi); + } + } + + return disp; +} diff --git a/shared/display.h b/shared/display.h new file mode 100644 index 0000000..95746e3 --- /dev/null +++ b/shared/display.h @@ -0,0 +1,37 @@ +/** + * Copyright 2025 buffybox contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef BBX_DISPLAY_H +#define BBX_DISPLAY_H + +#include "backends.h" +#include "lvgl/lvgl.h" + +/** + * Display configuration options + */ +typedef struct { + /* Display resolution override */ + int hor_res; + int ver_res; + /* Display offset */ + int x_offset; + int y_offset; + /* DPI override */ + int dpi; + /* Framebuffer force refresh quirk */ + bool fbdev_force_refresh; +} bbx_display_config_t; + +/** + * Initialize LVGL display with the specified backend and configuration. + * + * @param backend_id the backend to use + * @param config display configuration options + * @return initialized display or NULL on failure + */ +lv_display_t *bbx_display_create(bbx_backends_backend_id_t backend_id, bbx_display_config_t *config); + +#endif /* BBX_DISPLAY_H */ diff --git a/shared/header.c b/shared/header.c new file mode 100644 index 0000000..a49b237 --- /dev/null +++ b/shared/header.c @@ -0,0 +1,88 @@ +/** + * Copyright 2025 buffybox contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "header.h" + +void bbx_header_init_config(bbx_header_config_t *config) { + config->show_theme_toggle = true; + config->show_keyboard_toggle = true; + config->show_layout_dropdown = true; + config->show_shutdown_button = true; + config->dropdown_options = "Option 1\nOption 2\nOption 3"; + config->dropdown_width = 90; + config->theme_symbol = LV_SYMBOL_SETTINGS; + config->keyboard_symbol = LV_SYMBOL_KEYBOARD; + config->shutdown_symbol = LV_SYMBOL_POWER; +} + +lv_obj_t *bbx_header_create(lv_obj_t *parent, bbx_header_config_t *config, bbx_header_widgets_t *widgets) { + lv_memzero(widgets, sizeof(bbx_header_widgets_t)); + + /* Create header flexbox */ + lv_obj_t *header = lv_obj_create(parent); + widgets->header = header; + + /* Theme toggle button */ + if (config->show_theme_toggle) { + lv_obj_t *btn = lv_button_create(header); + widgets->theme_toggle_btn = btn; + + lv_obj_t *label = lv_label_create(btn); + lv_label_set_text(label, config->theme_symbol); + lv_obj_center(label); + } + + /* Keyboard toggle button */ + if (config->show_keyboard_toggle) { + lv_obj_t *btn = lv_button_create(header); + widgets->keyboard_toggle_btn = btn; + + lv_obj_t *label = lv_label_create(btn); + lv_label_set_text(label, config->keyboard_symbol); + lv_obj_center(label); + } + + /* Layout dropdown */ + if (config->show_layout_dropdown) { + lv_obj_t *dropdown = lv_dropdown_create(header); + widgets->layout_dropdown = dropdown; + + lv_dropdown_set_options(dropdown, config->dropdown_options); + lv_obj_set_width(dropdown, config->dropdown_width); + } + + /* Spacer */ + lv_obj_t *spacer = lv_obj_create(header); + lv_obj_set_height(spacer, 0); + lv_obj_set_flex_grow(spacer, 1); + + /* Shutdown button */ + if (config->show_shutdown_button) { + lv_obj_t *btn = lv_button_create(header); + widgets->shutdown_btn = btn; + + lv_obj_t *label = lv_label_create(btn); + lv_label_set_text(label, config->shutdown_symbol); + lv_obj_center(label); + } + + /* Size buttons to match dropdown height */ + if (widgets->layout_dropdown) { + lv_obj_update_layout(widgets->layout_dropdown); + const int32_t dropdown_height = lv_obj_get_height(widgets->layout_dropdown); + + if (widgets->theme_toggle_btn) { + lv_obj_set_size(widgets->theme_toggle_btn, dropdown_height, dropdown_height); + } + if (widgets->keyboard_toggle_btn) { + lv_obj_set_size(widgets->keyboard_toggle_btn, dropdown_height, dropdown_height); + } + if (widgets->shutdown_btn) { + lv_obj_set_size(widgets->shutdown_btn, dropdown_height, dropdown_height); + } + } + + return header; +} diff --git a/shared/header.h b/shared/header.h new file mode 100644 index 0000000..f2c9b39 --- /dev/null +++ b/shared/header.h @@ -0,0 +1,60 @@ +/** + * Copyright 2025 buffybox contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef BBX_HEADER_H +#define BBX_HEADER_H + +#include "lvgl/lvgl.h" +#include + +/** + * Header configuration options + */ +typedef struct { + /* Which elements to include */ + bool show_theme_toggle; + bool show_keyboard_toggle; + bool show_layout_dropdown; + bool show_shutdown_button; + + /* Dropdown options (if enabled) */ + const char *dropdown_options; + int dropdown_width; + + /* Button symbols */ + const char *theme_symbol; + const char *keyboard_symbol; + const char *shutdown_symbol; +} bbx_header_config_t; + +/** + * Header widget references for attaching callbacks + */ +typedef struct { + lv_obj_t *header; + lv_obj_t *theme_toggle_btn; + lv_obj_t *keyboard_toggle_btn; + lv_obj_t *layout_dropdown; + lv_obj_t *shutdown_btn; +} bbx_header_widgets_t; + +/** + * Create a header bar with configurable elements. + * + * @param parent parent object (usually screen) + * @param config header configuration + * @param widgets output struct for widget references + * @return header object + */ +lv_obj_t *bbx_header_create(lv_obj_t *parent, bbx_header_config_t *config, bbx_header_widgets_t *widgets); + +/** + * Initialize header config with default values. + * + * @param config config struct to initialize + */ +void bbx_header_init_config(bbx_header_config_t *config); + +#endif /* BBX_HEADER_H */ diff --git a/shared/keyboard.c b/shared/keyboard.c new file mode 100644 index 0000000..79e08b5 --- /dev/null +++ b/shared/keyboard.c @@ -0,0 +1,59 @@ +/** + * Copyright 2025 buffybox contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "keyboard.h" +#include "theme.h" +#include "../squeek2lvgl/sq2lv.h" + +void bbx_keyboard_init_config(bbx_keyboard_config_t *config) { + config->mode = LV_KEYBOARD_MODE_TEXT_LOWER; + config->layout_id = 0; /* Default to first layout */ + config->popovers = false; + config->height = -1; /* Auto-calculate */ + config->value_changed_callback = NULL; + config->ready_callback = NULL; +} + +lv_obj_t *bbx_keyboard_create(lv_obj_t *parent, lv_obj_t *textarea, bbx_keyboard_config_t *config) { + lv_obj_t *keyboard = lv_keyboard_create(parent); + + lv_keyboard_set_mode(keyboard, config->mode); + lv_keyboard_set_textarea(keyboard, textarea); + + /* Remove default event callback and add custom ones */ + uint32_t num_events = lv_obj_get_event_count(keyboard); + for(uint32_t i = 0; i < num_events; ++i) { + if(lv_event_dsc_get_cb(lv_obj_get_event_dsc(keyboard, i)) == lv_keyboard_def_event_cb) { + lv_obj_remove_event(keyboard, i); + break; + } + } + + if (config->value_changed_callback) { + lv_obj_add_event_cb(keyboard, config->value_changed_callback, LV_EVENT_VALUE_CHANGED, NULL); + } + + if (config->ready_callback) { + lv_obj_add_event_cb(keyboard, config->ready_callback, LV_EVENT_READY, NULL); + } + + /* Set size */ + if (config->height > 0) { + lv_obj_set_size(keyboard, LV_PCT(100), config->height); + } + + /* Apply theme preparation */ + bbx_theme_prepare_keyboard(keyboard); + + /* Set layout */ + sq2lv_switch_layout(keyboard, config->layout_id); + + /* Enable popovers if requested */ + if (config->popovers) { + lv_keyboard_set_popovers(keyboard, true); + } + + return keyboard; +} diff --git a/shared/keyboard.h b/shared/keyboard.h new file mode 100644 index 0000000..0e67f2a --- /dev/null +++ b/shared/keyboard.h @@ -0,0 +1,19 @@ +#ifndef BBX_KEYBOARD_H +#define BBX_KEYBOARD_H + +#include "lvgl/lvgl.h" +#include + +typedef struct { + lv_keyboard_mode_t mode; + int layout_id; + bool popovers; + int32_t height; + lv_event_cb_t value_changed_callback; + lv_event_cb_t ready_callback; +} bbx_keyboard_config_t; + +lv_obj_t *bbx_keyboard_create(lv_obj_t *parent, lv_obj_t *textarea, bbx_keyboard_config_t *config); +void bbx_keyboard_init_config(bbx_keyboard_config_t *config); + +#endif /* BBX_KEYBOARD_H */ diff --git a/unl0kr/terminal.c b/shared/terminal.c similarity index 93% rename from unl0kr/terminal.c rename to shared/terminal.c index 1501216..2f959f2 100644 --- a/unl0kr/terminal.c +++ b/shared/terminal.c @@ -30,7 +30,7 @@ static int original_kb_mode = -1; * Public functions */ -void ul_terminal_prepare_current_terminal(bool enable_graphics_mode, bool disable_keyboard_input) { +void bbx_terminal_prepare_current_terminal(bool enable_graphics_mode, bool disable_keyboard_input) { /* Exit early if there is nothing to do */ if (!enable_graphics_mode && !disable_keyboard_input) { return; @@ -66,7 +66,7 @@ void ul_terminal_prepare_current_terminal(bool enable_graphics_mode, bool disabl } } -void ul_terminal_reset_current_terminal(void) { +void bbx_terminal_reset_current_terminal(void) { /* If we haven't previously opened the current terminal, exit */ if (current_fd < 0) { bbx_log(BBX_LOG_LEVEL_WARNING, "Could not reset current terminal"); diff --git a/unl0kr/terminal.h b/shared/terminal.h similarity index 65% rename from unl0kr/terminal.h rename to shared/terminal.h index ee35438..c40bf28 100644 --- a/unl0kr/terminal.h +++ b/shared/terminal.h @@ -4,8 +4,8 @@ */ -#ifndef UL_TERMINAL_H -#define UL_TERMINAL_H +#ifndef BBX_TERMINAL_H +#define BBX_TERMINAL_H #include @@ -15,11 +15,11 @@ * @param enable_graphics_mode if true, switch terminal into graphics mode (hides command prompt) * @param disable_keyboard_input if true, disable terminal keyboard input (hides entered text) */ -void ul_terminal_prepare_current_terminal(bool enable_graphics_mode, bool disable_keyboard_input); +void bbx_terminal_prepare_current_terminal(bool enable_graphics_mode, bool disable_keyboard_input); /** * Reset the current TTY to text output. */ -void ul_terminal_reset_current_terminal(void); +void bbx_terminal_reset_current_terminal(void); -#endif /* UL_TERMINAL_H */ +#endif /* BBX_TERMINAL_H */ diff --git a/shared/theme.c b/shared/theme.c index 6637953..c93e68a 100644 --- a/shared/theme.c +++ b/shared/theme.c @@ -136,7 +136,7 @@ static void init_styles(const bbx_theme *theme) { reset_style(&(styles.textarea)); lv_style_set_text_color(&(styles.textarea), lv_color_hex(theme->textarea.fg_color)); lv_style_set_bg_opa(&(styles.textarea), LV_OPA_COVER); - lv_style_set_bg_color(&(styles.textarea), lv_color_hex(theme->textarea.bg_color)); + lv_style_set_bg_color(&(styles.textarea), lv_color_hex(theme->textarea.bg_color)); lv_style_set_border_side(&(styles.textarea), LV_BORDER_SIDE_FULL); lv_style_set_border_width(&(styles.textarea), lv_dpx(theme->textarea.border_width)); lv_style_set_border_color(&(styles.textarea), lv_color_hex(theme->textarea.border_color)); @@ -230,6 +230,10 @@ static void apply_theme_cb(lv_theme_t *theme, lv_obj_t *obj) { if (lv_obj_has_flag(obj, BBX_WIDGET_HEADER)) { lv_obj_add_style(obj, &(styles.header), 0); +#if LV_USE_FLEX + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW); + lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT); +#endif return; } diff --git a/unl0kr/backends.h b/unl0kr/backends.h deleted file mode 100644 index 268c8dd..0000000 --- a/unl0kr/backends.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright 2022 Eugenio Paolantonio (g7) - * SPDX-License-Identifier: GPL-3.0-or-later - */ - - -#ifndef UL_BACKENDS_H -#define UL_BACKENDS_H - -#include "lvgl/lvgl.h" - -/** - * Backend identifiers - * - * Only UL_BACKENDS_BACKEND_NONE should have an explicit value assigned - */ -typedef enum { - UL_BACKENDS_BACKEND_NONE = -1, -#if LV_USE_LINUX_FBDEV - UL_BACKENDS_BACKEND_FBDEV, -#endif /* LV_USE_LINUX_FBDEV */ -#if LV_USE_LINUX_DRM - UL_BACKENDS_BACKEND_DRM, -#endif /* LV_USE_LINUX_DRM */ -} ul_backends_backend_id_t; - -/** - * Actual backends - */ -extern const char *ul_backends_backends[]; - -/** - * Find the first backend with a given name. - * - * @param name backend name - * @return ID of the first matching backend or UL_BACKENDS_BACKEND_NONE if no backend matched - */ -ul_backends_backend_id_t ul_backends_find_backend_with_name(const char *name); - -#endif /* UL_BACKENDS_H */ diff --git a/unl0kr/command_line.c b/unl0kr/command_line.c index 6030574..c079e86 100644 --- a/unl0kr/command_line.c +++ b/unl0kr/command_line.c @@ -38,16 +38,11 @@ static void print_usage(); */ static void init_opts(ul_cli_opts *opts) { + bbx_cli_init_common_opts(&opts->common); opts->num_config_files = 0; opts->config_files = NULL; opts->message = NULL; - opts->hor_res = -1; - opts->ver_res = -1; - opts->x_offset = 0; - opts->y_offset = 0; - opts->dpi = 0; opts->newline = true; - opts->verbose = false; } static void print_usage() { @@ -115,16 +110,12 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) { opts->num_config_files++; break; case 'g': - if (sscanf(optarg, "%ix%i@%i,%i", &(opts->hor_res), &(opts->ver_res), &(opts->x_offset), &(opts->y_offset)) != 4) { - if (sscanf(optarg, "%ix%i", &(opts->hor_res), &(opts->ver_res)) != 2) { - bbx_log(BBX_LOG_LEVEL_ERROR, "Invalid geometry argument \"%s\"\n", optarg); - exit(EXIT_FAILURE); - } + if (bbx_cli_parse_geometry(optarg, &opts->common) != 0) { + exit(EXIT_FAILURE); } break; case 'd': - if (sscanf(optarg, "%i", &(opts->dpi)) != 1) { - bbx_log(BBX_LOG_LEVEL_ERROR, "Invalid dpi argument \"%s\"\n", optarg); + if (bbx_cli_parse_dpi(optarg, &opts->common) != 0) { exit(EXIT_FAILURE); } break; @@ -135,11 +126,11 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) { opts->newline = false; break; case 'v': - opts->verbose = true; + opts->common.verbose = true; break; case 'V': - fprintf(stderr, "unl0kr %s\n", PROJECT_VERSION); - exit(0); + bbx_cli_print_version_and_exit("unl0kr"); + break; default: print_usage(); exit(EXIT_FAILURE); diff --git a/unl0kr/command_line.h b/unl0kr/command_line.h index b18d524..3ab7a92 100644 --- a/unl0kr/command_line.h +++ b/unl0kr/command_line.h @@ -7,32 +7,23 @@ #ifndef UL_COMMAND_LINE_H #define UL_COMMAND_LINE_H +#include "../shared/cli_common.h" + #include /** * Options parsed from command line arguments */ typedef struct { + /* Common cli options */ + bbx_cli_common_opts common; /* Number of config files */ int num_config_files; /* Paths of config file */ const char **config_files; /* Message for a user */ const char *message; - /* Horizontal display resolution */ - int hor_res; - /* Vertical display resolution */ - int ver_res; - /* Horizontal display offset */ - int x_offset; - /* Vertical display offset */ - int y_offset; - /* DPI */ - int dpi; - /* If true, append a newline character to a password */ bool newline; - /* Verbose mode. If true, provide more detailed logging output on STDERR. */ - bool verbose; } ul_cli_opts; /** diff --git a/unl0kr/config.c b/unl0kr/config.c index 018a31c..12a9390 100644 --- a/unl0kr/config.c +++ b/unl0kr/config.c @@ -46,8 +46,8 @@ static int parsing_handler(void* user_data, const char* section, const char* key return 1; } } else if (strcmp(key, "backend") == 0) { - ul_backends_backend_id_t id = ul_backends_find_backend_with_name(value); - if (id != UL_BACKENDS_BACKEND_NONE) { + bbx_backends_backend_id_t id = bbx_backends_find_backend_with_name(value); + if (id != BBX_BACKENDS_BACKEND_NONE) { opts->general.backend = id; return 1; } @@ -139,7 +139,7 @@ static int parsing_handler(void* user_data, const char* section, const char* key void ul_config_init_opts(ul_config_opts *opts) { opts->general.animations = false; - opts->general.backend = ul_backends_backends[0] == NULL ? UL_BACKENDS_BACKEND_NONE : 0; + opts->general.backend = bbx_backends_backends[0] == NULL ? BBX_BACKENDS_BACKEND_NONE : 0; opts->general.timeout = 0; opts->keyboard.autohide = true; opts->keyboard.layout_id = SQ2LV_LAYOUT_US; diff --git a/unl0kr/config.h b/unl0kr/config.h index e4ff5b9..f5b3055 100644 --- a/unl0kr/config.h +++ b/unl0kr/config.h @@ -7,8 +7,8 @@ #ifndef UL_CONFIG_H #define UL_CONFIG_H -#include "backends.h" +#include "../shared/backends.h" #include "../shared/themes.h" #include "sq2lv_layouts.h" @@ -23,7 +23,7 @@ typedef struct { /* If true, use animations */ bool animations; /* Backend to use */ - ul_backends_backend_id_t backend; + bbx_backends_backend_id_t backend; /* Timeout (in seconds) - once elapsed, the device will shutdown. 0 (default) to disable */ uint16_t timeout; } ul_config_opts_general; diff --git a/unl0kr/main.c b/unl0kr/main.c index 5c52955..fb8c7a3 100644 --- a/unl0kr/main.c +++ b/unl0kr/main.c @@ -4,14 +4,17 @@ */ -#include "backends.h" #include "command_line.h" #include "config.h" #include "unl0kr.h" -#include "terminal.h" +#include "../shared/backends.h" +#include "../shared/display.h" +#include "../shared/header.h" #include "../shared/indev.h" +#include "../shared/keyboard.h" #include "../shared/log.h" +#include "../shared/terminal.h" #include "../shared/theme.h" #include "../shared/themes.h" #include "../squeek2lvgl/sq2lv.h" @@ -372,12 +375,12 @@ static void shutdown(void) { static void sigaction_handler(int signum) { LV_UNUSED(signum); - ul_terminal_reset_current_terminal(); + bbx_terminal_reset_current_terminal(); exit(0); } static void exit_failure() { - ul_terminal_reset_current_terminal(); + bbx_terminal_reset_current_terminal(); exit(EXIT_FAILURE); } @@ -391,7 +394,7 @@ int main(int argc, char *argv[]) { ul_cli_parse_opts(argc, argv, &cli_opts); /* Set up log level */ - if (cli_opts.verbose) { + if (cli_opts.common.verbose) { bbx_log_set_level(BBX_LOG_LEVEL_VERBOSE); } @@ -414,7 +417,7 @@ int main(int argc, char *argv[]) { ul_config_parse_files(cli_opts.config_files, cli_opts.num_config_files, &conf_opts); /* Prepare current TTY and clean up on termination */ - ul_terminal_prepare_current_terminal(!conf_opts.quirks.terminal_prevent_graphics_mode, !conf_opts.quirks.terminal_allow_keyboard_input); + bbx_terminal_prepare_current_terminal(!conf_opts.quirks.terminal_prevent_graphics_mode, !conf_opts.quirks.terminal_allow_keyboard_input); struct sigaction action; memset(&action, 0, sizeof(action)); action.sa_handler = sigaction_handler; @@ -425,62 +428,22 @@ int main(int argc, char *argv[]) { lv_init(); lv_log_register_print_cb(bbx_log_print_cb); - /* Initialise display */ - lv_display_t *disp = NULL; - switch (conf_opts.general.backend) { -#if LV_USE_LINUX_FBDEV - case UL_BACKENDS_BACKEND_FBDEV: - bbx_log(BBX_LOG_LEVEL_VERBOSE, "Using framebuffer backend"); - disp = lv_linux_fbdev_create(); - if (access("/dev/fb0", F_OK) != 0) { - bbx_log(BBX_LOG_LEVEL_ERROR, "/dev/fb0 is not available"); - exit_failure(); - } - lv_linux_fbdev_set_file(disp, "/dev/fb0"); - if (conf_opts.quirks.fbdev_force_refresh) { - lv_linux_fbdev_set_force_refresh(disp, true); - } - break; -#endif /* LV_USE_LINUX_FBDEV */ -#if LV_USE_LINUX_DRM - case UL_BACKENDS_BACKEND_DRM: - bbx_log(BBX_LOG_LEVEL_VERBOSE, "Using DRM backend"); - disp = lv_linux_drm_create(); + /* Populate display config */ + bbx_display_config_t display_config = { + .hor_res = cli_opts.common.hor_res, + .ver_res = cli_opts.common.ver_res, + .x_offset = cli_opts.common.x_offset, + .y_offset = cli_opts.common.y_offset, + .dpi = cli_opts.common.dpi, + .fbdev_force_refresh = conf_opts.quirks.fbdev_force_refresh + }; - char drm_path[16]; - bool found = false; - for (int i = 0; i < 9; i++) { - sprintf(drm_path, "/dev/dri/card%d", i); - - if (access(drm_path, F_OK) == 0) { - found = true; - break; - } - } - if (!found) { - bbx_log(BBX_LOG_LEVEL_ERROR, "/dev/dri/card* are not available"); - exit_failure(); - } - - lv_linux_drm_set_file(disp, drm_path, -1); - - break; -#endif /* LV_USE_LINUX_DRM */ - default: - bbx_log(BBX_LOG_LEVEL_ERROR, "Unable to find suitable backend"); + /* Initialize display */ + lv_display_t *disp = bbx_display_create(conf_opts.general.backend, &display_config); + if (!disp) { exit_failure(); } - /* Override display properties with command line options if necessary */ - lv_display_set_offset(disp, cli_opts.x_offset, cli_opts.y_offset); - if (cli_opts.hor_res > 0 || cli_opts.ver_res > 0) { - lv_display_set_physical_resolution(disp, lv_display_get_horizontal_resolution(disp), lv_display_get_vertical_resolution(disp)); - lv_display_set_resolution(disp, cli_opts.hor_res, cli_opts.ver_res); - } - if (cli_opts.dpi > 0) { - lv_display_set_dpi(disp, cli_opts.dpi); - } - /* Prepare for routing physical keyboard input into the textarea */ lv_group_t *keyboard_input_group = lv_group_create(); bbx_indev_set_keyboard_input_group(keyboard_input_group); @@ -507,50 +470,25 @@ int main(int argc, char *argv[]) { lv_obj_set_flex_flow(screen, LV_FLEX_FLOW_COLUMN); lv_obj_remove_flag(screen, LV_OBJ_FLAG_SCROLLABLE); - /* Header flexbox */ - lv_obj_t *header = lv_obj_create(screen); + /* Configure header */ + bbx_header_config_t header_config; + bbx_header_init_config(&header_config); + header_config.theme_symbol = UL_SYMBOL_ADJUST; + header_config.dropdown_options = sq2lv_layout_short_names; + + bbx_header_widgets_t header_widgets; + lv_obj_t *header = bbx_header_create(screen, &header_config, &header_widgets); lv_obj_add_flag(header, BBX_WIDGET_HEADER); - lv_theme_apply(header); /* Force re-apply theme after setting flag so that the widget can be identified */ - lv_obj_set_flex_flow(header, LV_FLEX_FLOW_ROW); - lv_obj_set_size(header, LV_PCT(100), LV_SIZE_CONTENT); - /* Theme switcher button */ - lv_obj_t *toggle_theme_btn = lv_button_create(header); - lv_obj_add_event_cb(toggle_theme_btn, toggle_theme_btn_clicked_cb, LV_EVENT_CLICKED, NULL); - lv_obj_t *toggle_theme_btn_label = lv_label_create(toggle_theme_btn); - lv_label_set_text(toggle_theme_btn_label, UL_SYMBOL_ADJUST); - lv_obj_center(toggle_theme_btn_label); + /* Add theme toggle to distinguish this widget type */ + lv_obj_add_flag(header, BBX_WIDGET_HEADER); + lv_theme_apply(header); - /* Show / hide keyboard button */ - lv_obj_t *toggle_kb_btn = lv_button_create(header); - lv_obj_add_event_cb(toggle_kb_btn, toggle_kb_btn_clicked_cb, LV_EVENT_CLICKED, NULL); - lv_obj_t *toggle_kb_btn_label = lv_label_create(toggle_kb_btn); - lv_label_set_text(toggle_kb_btn_label, LV_SYMBOL_KEYBOARD); - lv_obj_center(toggle_kb_btn_label); - - /* Keyboard layout dropdown */ - lv_obj_t *layout_dropdown = lv_dropdown_create(header); - lv_dropdown_set_options(layout_dropdown, sq2lv_layout_short_names); - lv_obj_add_event_cb(layout_dropdown, layout_dropdown_value_changed_cb, LV_EVENT_VALUE_CHANGED, NULL); - lv_obj_set_width(layout_dropdown, 90); - - /* Spacer */ - lv_obj_t *spacer = lv_obj_create(header); - lv_obj_set_height(spacer, 0); - lv_obj_set_flex_grow(spacer, 1); - - /* Shutdown button */ - lv_obj_t *shutdown_btn = lv_button_create(header); - lv_obj_add_event_cb(shutdown_btn, shutdown_btn_clicked_cb, LV_EVENT_CLICKED, NULL); - lv_obj_t *shutdown_btn_label = lv_label_create(shutdown_btn); - lv_label_set_text(shutdown_btn_label, LV_SYMBOL_POWER); - lv_obj_center(shutdown_btn_label); - - lv_obj_update_layout(layout_dropdown); - const int32_t dropwdown_height = lv_obj_get_height(layout_dropdown); - lv_obj_set_size(toggle_theme_btn, dropwdown_height, dropwdown_height); - lv_obj_set_size(toggle_kb_btn, dropwdown_height, dropwdown_height); - lv_obj_set_size(shutdown_btn, dropwdown_height, dropwdown_height); + /* Attach callbacks */ + lv_obj_add_event_cb(header_widgets.theme_toggle_btn, toggle_theme_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + lv_obj_add_event_cb(header_widgets.keyboard_toggle_btn, toggle_kb_btn_clicked_cb, LV_EVENT_CLICKED, NULL); + lv_obj_add_event_cb(header_widgets.layout_dropdown, layout_dropdown_value_changed_cb, LV_EVENT_VALUE_CHANGED, NULL); + lv_obj_add_event_cb(header_widgets.shutdown_btn, shutdown_btn_clicked_cb, LV_EVENT_CLICKED, NULL); lv_obj_update_layout(header); content_height_without_kb = ver_res - lv_obj_get_height(header); @@ -633,30 +571,22 @@ int main(int argc, char *argv[]) { lv_obj_set_style_pad_bottom(container, is_keyboard_hidden? content_pad_bottom_without_kb : content_pad_bottom_with_kb, LV_PART_MAIN); /* Keyboard (after textarea / label so that key popovers are not drawn over) */ - keyboard = lv_keyboard_create(screen); - lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_TEXT_LOWER); - lv_keyboard_set_textarea(keyboard, textarea); - uint32_t num_keyboard_events = lv_obj_get_event_count(keyboard); - for(uint32_t i = 0; i < num_keyboard_events; ++i) { - if(lv_event_dsc_get_cb(lv_obj_get_event_dsc(keyboard, i)) == lv_keyboard_def_event_cb) { - lv_obj_remove_event(keyboard, i); - break; - } - } - lv_obj_add_event_cb(keyboard, keyboard_value_changed_cb, LV_EVENT_VALUE_CHANGED, NULL); - lv_obj_add_event_cb(keyboard, keyboard_ready_cb, LV_EVENT_READY, NULL); - lv_obj_set_size(keyboard, LV_PCT(100), keyboard_height); - bbx_theme_prepare_keyboard(keyboard); + bbx_keyboard_config_t keyboard_config; + bbx_keyboard_init_config(&keyboard_config); + keyboard_config.layout_id = (int)conf_opts.keyboard.layout_id; + keyboard_config.height = keyboard_height; + keyboard_config.popovers = conf_opts.keyboard.popovers; + keyboard_config.value_changed_callback = keyboard_value_changed_cb; + keyboard_config.ready_callback = keyboard_ready_cb; + + keyboard = bbx_keyboard_create(screen, textarea, &keyboard_config); /* Apply textarea options */ set_password_obscured(conf_opts.textarea.obscured); /* Apply keyboard options */ sq2lv_switch_layout(keyboard, conf_opts.keyboard.layout_id); - lv_dropdown_set_selected(layout_dropdown, conf_opts.keyboard.layout_id); - if (conf_opts.keyboard.popovers) { - lv_keyboard_set_popovers(keyboard, true); - } + lv_dropdown_set_selected(header_widgets.layout_dropdown, conf_opts.keyboard.layout_id); /* Periodically run timer / task handler */ uint32_t timeout = conf_opts.general.timeout * 1000; /* ms */ diff --git a/unl0kr/meson.build b/unl0kr/meson.build index 0255422..6fecd9d 100644 --- a/unl0kr/meson.build +++ b/unl0kr/meson.build @@ -2,12 +2,10 @@ # SPDX-License-Identifier: GPL-3.0-or-later unl0kr_sources = files( - 'backends.c', 'command_line.c', 'config.c', 'main.c', 'sq2lv_layouts.c', - 'terminal.c' ) unl0kr_dependencies = [ @@ -27,7 +25,7 @@ endif executable('unl0kr', include_directories: common_include_dirs, - sources: unl0kr_sources + shared_sources + squeek2lvgl_sources + lvgl_sources, + sources: unl0kr_sources + shared_sources + squeek2lvgl_sources + lvgl_sources + header_sources, dependencies: unl0kr_dependencies, c_args: unl0kr_args, install: true,