Add themes and fbdev force-refresh quirk via config

This commit is contained in:
Johannes Marbach
2024-03-30 08:06:29 +01:00
parent a4a4734317
commit 2987305546
29 changed files with 636 additions and 287 deletions

View File

@@ -10,6 +10,8 @@ If a change only affects particular applications, they are listed in parentheses
## Unreleased
- feat(buffyboard): Add fbdev force-refresh quirk via config
- feat(buffyboard): Allow choosing theme via config and add all themes from unl0kr
- feat(buffyboard): Handle input device connection/disconnection at runtime; adds new dependency libudev
## 3.0.0 (2024-03-22)

View File

@@ -29,6 +29,7 @@ For a growing collection of demo videos, see the [wiki].
## Dependencies
- [inih]
- [lvgl] (git submodule / linked statically)
- [squeek2lvgl] (git submodule / linked statically)
- [libinput]
@@ -129,6 +130,7 @@ The [FontAwesome] font is licensed under the Open Font License version 1.1.
[OpenSans]: https://fonts.google.com/specimen/Open+Sans
[arrow-alt-circle-up]: https://fontawesome.com/v5.15/icons/arrow-alt-circle-up?style=solid
[fbkeyboard]: https://github.com/bakonyiferenc/fbkeyboard
[inih]: https://github.com/benhoyt/inih
[libinput]: https://gitlab.freedesktop.org/libinput/libinput
[libudev]: https://github.com/systemd/systemd/tree/main/src/libudev
[lv_port_linux_frame_buffer]: https://github.com/lvgl/lv_port_linux_frame_buffer

View File

@@ -0,0 +1,5 @@
[general]
theme=breezy-light
#[quirks]
#fbdev_force_refresh=true

View File

@@ -13,11 +13,4 @@
#define BB_VERSION "?" /* Just to silence IDE warning. Real version injected by meson during build. */
#endif
/**
* Fonts
*/
LV_FONT_DECLARE(font_32);
#endif /* BB_BUFFYBOARD_H */

View File

@@ -8,6 +8,8 @@
#include "buffyboard.h"
#include "../shared/log.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
@@ -44,15 +46,21 @@ static void print_usage() {
"Usage: buffyboard [OPTION]\n"
"\n"
"Mandatory arguments to long options are mandatory for short options too.\n"
" -r, --rotate=[0-3] Rotate the UI to the given orientation.\n"
" 0 - normal orientation (0 degree)\n"
" 1 - clockwise orientation (90 degrees)\n"
" 2 - upside down orientation (180 degrees)\n"
" 3 - counterclockwise orientation (270 degrees)\n"
" The values match the ones provided by the kernel in\n"
" /sys/class/graphics/fbcon/rotate.\n"
" -h, --help Print this message and exit\n"
" -V, --version Print the buffyboard version and exit\n");
" -C, --config-override Path to a config override file. Can be supplied\n"
" multiple times. Config files are merged in the\n"
" following order:\n"
" * /etc/buffyboard.conf\n"
" * /etc/buffyboard.conf.d/* (alphabetically)\n"
" * Override files (in supplied order)\n"
" -r, --rotate=[0-3] Rotate the UI to the given orientation. The\n"
" values match the ones provided by the kernel in\n"
" /sys/class/graphics/fbcon/rotate.\n"
" * 0 - normal orientation (0 degree)\n"
" * 1 - clockwise orientation (90 degrees)\n"
" * 2 - upside down orientation (180 degrees)\n"
" * 3 - counterclockwise orientation (270 degrees)\n"
" -h, --help Print this message and exit\n"
" -V, --version Print the buffyboard version and exit\n");
/*-------------------------------- 78 CHARS --------------------------------*/
}
@@ -65,16 +73,26 @@ void bb_cli_parse_opts(int argc, char *argv[], bb_cli_opts *opts) {
init_opts(opts);
struct option long_opts[] = {
{ "rotate", required_argument, NULL, 'r' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "config-override", required_argument, NULL, 'C' },
{ "rotate", required_argument, NULL, 'r' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
int opt, index = 0;
while ((opt = getopt_long(argc, argv, "r:hV", long_opts, &index)) != -1) {
while ((opt = getopt_long(argc, argv, "C:r:hV", long_opts, &index)) != -1) {
switch (opt) {
case 'C':
opts->config_files = realloc(opts->config_files, (opts->num_config_files + 1) * sizeof(char *));
if (!opts->config_files) {
bb_log(BB_LOG_LEVEL_ERROR, "Could not allocate memory for config file paths");
exit(EXIT_FAILURE);
}
opts->config_files[opts->num_config_files] = optarg;
opts->num_config_files++;
break;
case 'r': {
int orientation;
if (sscanf(optarg, "%i", &orientation) != 1 || orientation < 0 || orientation > 3) {

View File

@@ -13,6 +13,10 @@
* Options parsed from command line arguments
*/
typedef struct {
/* Number of config files */
int num_config_files;
/* Paths of config file */
const char **config_files;
/* Display rotation */
lv_display_rotation_t rotation;
} bb_cli_opts;

218
buffyboard/config.c Normal file
View File

@@ -0,0 +1,218 @@
/**
* Copyright 2021 Johannes Marbach
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "config.h"
#include "../shared/log.h"
#include "../squeek2lvgl/sq2lv.h"
#include "lvgl/lvgl.h"
#include <dirent.h>
#include <ini.h>
#include <stdlib.h>
#include <string.h>
/**
* Static prototypes
*/
/**
* Compares two strings from opaque types.
*
* @param a first string as void pointer
* @param b second string as void pointer
* @return a positive integer if a > b, a negative integer if a < b and 0 otherwise
*/
static int compare_strings(const void* a, const void* b);
/**
* Checks whether a string ends with a suffix
*
* @param string string to check
* @param suffix suffix to compare to
* @return true if the suffix matches at the end of the string, false otherwise
*/
static bool string_ends_with(const char *string, const char *suffix);
/**
* Non-recursively searches a directory for configuration files.
*
* @param path folder to search in
* @param found pointer to write found configuration file names into (to be freed by the caller)
* @param num_found pointer to write number of found files into
*/
static void find_files(const char *path, char ***found, int *num_found);
/**
* 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);
/**
* Attempt to parse a boolean value.
*
* @param value string to parse
* @param result pointer to write result into if parsing is successful
* @return true on success, false otherwise
*/
static bool parse_bool(const char *value, bool *result);
/**
* Static functions
*/
static int compare_strings(const void* a, const void* b) {
return strcmp(*(const char**)a, *(const char**)b);
}
static bool string_ends_with(const char *string, const char *suffix) {
if (!string || !suffix || strlen(suffix) > strlen(string)) {
return false;
}
return strncmp(string + strlen(string) - strlen(suffix), suffix, strlen(suffix)) == 0;
}
static void find_files(const char *path, char ***found, int *num_found) {
/* Initialise output variables */
*found = NULL;
*num_found = 0;
/* Count length of directory path */
const int path_length = strlen(path);
/* Open directory */
DIR *d = opendir(path);
if (!d) {
bb_log(BB_LOG_LEVEL_WARNING, "Could not read contents of folder %s", path);
return;
}
/* Loop over directory contents */
struct dirent *dir;
while ((dir = readdir(d)) != NULL) {
/* Ignore anything except for .conf files */
if (dir->d_type != DT_REG || !string_ends_with(dir->d_name, ".conf")) {
continue;
}
/* Grow output array */
char **tmp = realloc(*found, (*num_found + 1) * sizeof(char *));
if (!tmp) {
bb_log(BB_LOG_LEVEL_ERROR, "Could not reallocate memory for configuration file paths");
break;
}
*found = tmp;
/* Extract file name and length */
char *name = dir->d_name;
int name_length = strlen(name);
/* Allocate memory for full path */
char *found_path = malloc(path_length + name_length + 2); /* +1 for path separator and null terminator, respectively */
if (!found_path) {
bb_log(BB_LOG_LEVEL_ERROR, "Could not allocate memory for configuration file path");
break;
}
/* Build full path */
memcpy(found_path, path, path_length);
found_path[path_length] = '/';
memcpy(found_path + path_length + 1, dir->d_name, name_length + 1); /* +1 for path separator and null terminator, respectively */
/* Store file path */
(*found)[*num_found] = found_path;
*num_found += 1;
}
/* Close directory */
closedir(d);
}
static int parsing_handler(void* user_data, const char* section, const char* key, const char* value) {
bb_config_opts *opts = (bb_config_opts *)user_data;
if (strcmp(section, "general") == 0) {
if (strcmp(key, "theme") == 0) {
bb_themes_theme_id_t id = bb_themes_find_theme_with_name(value);
if (id != BB_THEMES_THEME_NONE) {
opts->general.theme_id = id;
return 1;
}
}
} else if (strcmp(section, "quirks") == 0) {
if (strcmp(key, "fbdev_force_refresh") == 0) {
if (parse_bool(value, &(opts->quirks.fbdev_force_refresh))) {
return 1;
}
}
}
bb_log(BB_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 (e.g. file not found) */
}
static bool parse_bool(const char *value, bool *result) {
if (strcmp(value, "true") == 0) {
*result = true;
return true;
}
if (strcmp(value, "false") == 0) {
*result = false;
return true;
}
return false;
}
/**
* Public functions
*/
void bb_config_init_opts(bb_config_opts *opts) {
opts->general.theme_id = BB_THEMES_THEME_BREEZY_DARK;
opts->quirks.fbdev_force_refresh = false;
}
void bb_config_parse_directory(const char *path, bb_config_opts *opts) {
/* Find files in directory */
char **found = NULL;
int num_found = 0;
find_files(path, &found, &num_found);
/* Sort and parse files */
qsort(found, num_found, sizeof(char *), compare_strings);
bb_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 bb_config_parse_files(const char **files, int num_files, bb_config_opts *opts) {
for (int i = 0; i < num_files; ++i) {
bb_config_parse_file(files[i], opts);
}
}
void bb_config_parse_file(const char *path, bb_config_opts *opts) {
bb_log(BB_LOG_LEVEL_VERBOSE, "Parsing config file %s", path);
if (ini_parse(path, parsing_handler, opts) != 0) {
bb_log(BB_LOG_LEVEL_ERROR, "Ignoring invalid config file %s", path);
}
}

72
buffyboard/config.h Normal file
View File

@@ -0,0 +1,72 @@
/**
* Copyright 2021 Johannes Marbach
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef BB_CONFIG_H
#define BB_CONFIG_H
#include "../shared/themes.h"
#include "sq2lv_layouts.h"
/**
* General options
*/
typedef struct {
/* Theme */
bb_themes_theme_id_t theme_id;
} bb_config_opts_general;
/**
* (Normally unneeded) quirky options
*/
typedef struct {
/* If true and using the framebuffer backend, force a refresh on every draw operation */
bool fbdev_force_refresh;
} bb_config_opts_quirks;
/**
* Options parsed from config file(s)
*/
typedef struct {
/* General options */
bb_config_opts_general general;
/* Options related to (normally unneeded) quirks */
bb_config_opts_quirks quirks;
} bb_config_opts;
/**
* Initialise a config options struct with default values.
*
* @param opts pointer to the options struct
*/
void bb_config_init_opts(bb_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 bb_config_parse_directory(const char *path, bb_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 bb_config_parse_files(const char **files, int num_files, bb_config_opts *opts);
/**
* Parse a configuration file.
*
* @param path path to configuration file
* @param opts pointer for writing the parsed options into
*/
void bb_config_parse_file(const char *path, bb_config_opts *opts);
#endif /* BB_CONFIG_H */

View File

@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 32 px
* Bpp: 4
* Opts: --bpp 4 --size 32 --no-compress -o font_32.c --format lvgl --font OpenSans-Regular.ttf --range 0x0020-0x007F --range 0x00A0-0x00FF --range 0x0100-0x017F --range 0x0370-0x03FF --range 0x2000-0x206F --range 0x20A0-0x20CF --range 0x2200-0x22FF --font FontAwesome5-Solid+Brands+Regular.woff --range 0xF001,0xF008,0xF00B,0xF00C,0xF00D,0xF011,0xF013,0xF015,0xF019,0xF01C,0xF021,0xF026,0xF027,0xF028,0xF03E,0xF0E0,0xF304,0xF043,0xF048,0xF04B,0xF04C,0xF04D,0xF051,0xF052,0xF053,0xF054,0xF067,0xF068,0xF06E,0xF070,0xF071,0xF074,0xF077,0xF078,0xF079,0xF07B,0xF093,0xF095,0xF0C4,0xF0C5,0xF0C7,0xF0C9,0xF0E7,0xF0EA,0xF0F3,0xF11C,0xF124,0xF158,0xF1EB,0xF240,0xF241,0xF242,0xF243,0xF244,0xF287,0xF293,0xF2ED,0xF55A,0xF7C2,0xF8A2 --range 0xF35B
* Opts: --bpp 4 --size 32 --no-compress -o font_32.c --format lvgl --font OpenSans-Regular.ttf --range 0x0020-0x007F --range 0x00A0-0x00FF --range 0x0100-0x017F --range 0x0370-0x03FF --range 0x2000-0x206F --range 0x20A0-0x20CF --range 0x2200-0x22FF --font FontAwesome5-Solid+Brands+Regular.woff --range 0xF001,0xF008,0xF00B,0xF00C,0xF00D,0xF011,0xF013,0xF015,0xF019,0xF01C,0xF021,0xF026,0xF027,0xF028,0xF03E,0xF0E0,0xF304,0xF043,0xF048,0xF04B,0xF04C,0xF04D,0xF051,0xF052,0xF053,0xF054,0xF067,0xF068,0xF06E,0xF070,0xF071,0xF074,0xF077,0xF078,0xF079,0xF07B,0xF093,0xF095,0xF0C4,0xF0C5,0xF0C7,0xF0C9,0xF0E7,0xF0EA,0xF0F3,0xF11C,0xF124,0xF158,0xF1EB,0xF240,0xF241,0xF242,0xF243,0xF244,0xF287,0xF293,0xF2ED,0xF55A,0xF7C2,0xF8A2 --range 0xF042 --range 0xF35B
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -12341,6 +12341,72 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
0x8, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x80,
/* U+F042 "" */
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x34,
0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x5a, 0xef, 0xff,
0xff, 0xfd, 0x94, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x6e, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xc4, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x2c, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xa0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x3, 0xef, 0xff, 0xff, 0xff, 0xff,
0xcd, 0xff, 0xff, 0xff, 0xfd, 0x10, 0x0, 0x0,
0x0, 0x0, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x5, 0xaf, 0xff, 0xff, 0xe1, 0x0, 0x0,
0x0, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x3, 0xdf, 0xff, 0xfd, 0x0, 0x0,
0x0, 0xd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xa0, 0x0,
0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xf4, 0x0,
0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0xfc, 0x0,
0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0x30,
0xc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0x90,
0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, 0xff, 0xd0,
0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xf0,
0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xff, 0xf2,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, 0xf3,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xff, 0xf4,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, 0xf3,
0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xf1,
0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xf0,
0xe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xff, 0xb0,
0x9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0x60,
0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x9, 0xff, 0xff, 0x0,
0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x5f, 0xff, 0xf8, 0x0,
0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x4, 0xff, 0xff, 0xe0, 0x0,
0x0, 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x0, 0x6f, 0xff, 0xff, 0x30, 0x0,
0x0, 0x0, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0, 0x0, 0x3c, 0xff, 0xff, 0xf6, 0x0, 0x0,
0x0, 0x0, 0xa, 0xff, 0xff, 0xff, 0xff, 0xff,
0x56, 0x9d, 0xff, 0xff, 0xff, 0x70, 0x0, 0x0,
0x0, 0x0, 0x0, 0x8f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf5, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x4, 0xdf, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfb, 0x20, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x5, 0xcf, 0xff, 0xff,
0xff, 0xff, 0xfb, 0x40, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x58, 0xab,
0xba, 0x84, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0,
/* U+F043 "" */
0x0, 0x0, 0x0, 0x0, 0x4, 0xee, 0x40, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd,
@@ -15294,52 +15360,53 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 88772, .adv_w = 384, .box_w = 24, .box_h = 26, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 89084, .adv_w = 576, .box_w = 36, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 89660, .adv_w = 512, .box_w = 32, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 90044, .adv_w = 352, .box_w = 22, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 90396, .adv_w = 448, .box_w = 20, .box_h = 30, .ofs_x = 4, .ofs_y = -3},
{.bitmap_index = 90696, .adv_w = 448, .box_w = 28, .box_h = 34, .ofs_x = 0, .ofs_y = -5},
{.bitmap_index = 91172, .adv_w = 448, .box_w = 28, .box_h = 29, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 91578, .adv_w = 448, .box_w = 28, .box_h = 28, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 91970, .adv_w = 448, .box_w = 20, .box_h = 30, .ofs_x = 4, .ofs_y = -3},
{.bitmap_index = 92270, .adv_w = 448, .box_w = 30, .box_h = 28, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 92690, .adv_w = 320, .box_w = 18, .box_h = 28, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 92942, .adv_w = 320, .box_w = 18, .box_h = 28, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 93194, .adv_w = 448, .box_w = 28, .box_h = 28, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 93586, .adv_w = 448, .box_w = 28, .box_h = 6, .ofs_x = 0, .ofs_y = 9},
{.bitmap_index = 93670, .adv_w = 576, .box_w = 36, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 94102, .adv_w = 640, .box_w = 40, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 94742, .adv_w = 576, .box_w = 38, .box_h = 32, .ofs_x = -1, .ofs_y = -4},
{.bitmap_index = 95350, .adv_w = 512, .box_w = 32, .box_h = 30, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 95830, .adv_w = 448, .box_w = 28, .box_h = 18, .ofs_x = 0, .ofs_y = 3},
{.bitmap_index = 96082, .adv_w = 448, .box_w = 28, .box_h = 18, .ofs_x = 0, .ofs_y = 3},
{.bitmap_index = 96334, .adv_w = 640, .box_w = 40, .box_h = 26, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 96854, .adv_w = 512, .box_w = 32, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 97238, .adv_w = 512, .box_w = 32, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 97750, .adv_w = 512, .box_w = 33, .box_h = 33, .ofs_x = -1, .ofs_y = -4},
{.bitmap_index = 98295, .adv_w = 448, .box_w = 29, .box_h = 28, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 98701, .adv_w = 448, .box_w = 28, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 99149, .adv_w = 448, .box_w = 28, .box_h = 28, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 99541, .adv_w = 448, .box_w = 28, .box_h = 26, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 99905, .adv_w = 512, .box_w = 32, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 100289, .adv_w = 320, .box_w = 22, .box_h = 32, .ofs_x = -1, .ofs_y = -4},
{.bitmap_index = 100641, .adv_w = 448, .box_w = 28, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 101089, .adv_w = 448, .box_w = 28, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 101537, .adv_w = 576, .box_w = 36, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 101969, .adv_w = 512, .box_w = 34, .box_h = 34, .ofs_x = -1, .ofs_y = -5},
{.bitmap_index = 102547, .adv_w = 384, .box_w = 24, .box_h = 28, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 102883, .adv_w = 640, .box_w = 40, .box_h = 29, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 103463, .adv_w = 640, .box_w = 40, .box_h = 20, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 103863, .adv_w = 640, .box_w = 40, .box_h = 20, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 104263, .adv_w = 640, .box_w = 40, .box_h = 20, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 104663, .adv_w = 640, .box_w = 40, .box_h = 20, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 105063, .adv_w = 640, .box_w = 40, .box_h = 20, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 105463, .adv_w = 640, .box_w = 41, .box_h = 26, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 105996, .adv_w = 448, .box_w = 24, .box_h = 32, .ofs_x = 2, .ofs_y = -4},
{.bitmap_index = 106380, .adv_w = 448, .box_w = 28, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 106828, .adv_w = 512, .box_w = 33, .box_h = 33, .ofs_x = -1, .ofs_y = -5},
{.bitmap_index = 107373, .adv_w = 512, .box_w = 32, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 107885, .adv_w = 640, .box_w = 40, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 108365, .adv_w = 384, .box_w = 24, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 108749, .adv_w = 515, .box_w = 33, .box_h = 21, .ofs_x = 0, .ofs_y = 2}
{.bitmap_index = 90044, .adv_w = 512, .box_w = 32, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 90556, .adv_w = 352, .box_w = 22, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 90908, .adv_w = 448, .box_w = 20, .box_h = 30, .ofs_x = 4, .ofs_y = -3},
{.bitmap_index = 91208, .adv_w = 448, .box_w = 28, .box_h = 34, .ofs_x = 0, .ofs_y = -5},
{.bitmap_index = 91684, .adv_w = 448, .box_w = 28, .box_h = 29, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 92090, .adv_w = 448, .box_w = 28, .box_h = 28, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 92482, .adv_w = 448, .box_w = 20, .box_h = 30, .ofs_x = 4, .ofs_y = -3},
{.bitmap_index = 92782, .adv_w = 448, .box_w = 30, .box_h = 28, .ofs_x = -1, .ofs_y = -2},
{.bitmap_index = 93202, .adv_w = 320, .box_w = 18, .box_h = 28, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 93454, .adv_w = 320, .box_w = 18, .box_h = 28, .ofs_x = 1, .ofs_y = -2},
{.bitmap_index = 93706, .adv_w = 448, .box_w = 28, .box_h = 28, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 94098, .adv_w = 448, .box_w = 28, .box_h = 6, .ofs_x = 0, .ofs_y = 9},
{.bitmap_index = 94182, .adv_w = 576, .box_w = 36, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 94614, .adv_w = 640, .box_w = 40, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 95254, .adv_w = 576, .box_w = 38, .box_h = 32, .ofs_x = -1, .ofs_y = -4},
{.bitmap_index = 95862, .adv_w = 512, .box_w = 32, .box_h = 30, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 96342, .adv_w = 448, .box_w = 28, .box_h = 18, .ofs_x = 0, .ofs_y = 3},
{.bitmap_index = 96594, .adv_w = 448, .box_w = 28, .box_h = 18, .ofs_x = 0, .ofs_y = 3},
{.bitmap_index = 96846, .adv_w = 640, .box_w = 40, .box_h = 26, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 97366, .adv_w = 512, .box_w = 32, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 97750, .adv_w = 512, .box_w = 32, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 98262, .adv_w = 512, .box_w = 33, .box_h = 33, .ofs_x = -1, .ofs_y = -4},
{.bitmap_index = 98807, .adv_w = 448, .box_w = 29, .box_h = 28, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 99213, .adv_w = 448, .box_w = 28, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 99661, .adv_w = 448, .box_w = 28, .box_h = 28, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 100053, .adv_w = 448, .box_w = 28, .box_h = 26, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 100417, .adv_w = 512, .box_w = 32, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 100801, .adv_w = 320, .box_w = 22, .box_h = 32, .ofs_x = -1, .ofs_y = -4},
{.bitmap_index = 101153, .adv_w = 448, .box_w = 28, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 101601, .adv_w = 448, .box_w = 28, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 102049, .adv_w = 576, .box_w = 36, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 102481, .adv_w = 512, .box_w = 34, .box_h = 34, .ofs_x = -1, .ofs_y = -5},
{.bitmap_index = 103059, .adv_w = 384, .box_w = 24, .box_h = 28, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 103395, .adv_w = 640, .box_w = 40, .box_h = 29, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 103975, .adv_w = 640, .box_w = 40, .box_h = 20, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 104375, .adv_w = 640, .box_w = 40, .box_h = 20, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 104775, .adv_w = 640, .box_w = 40, .box_h = 20, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 105175, .adv_w = 640, .box_w = 40, .box_h = 20, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 105575, .adv_w = 640, .box_w = 40, .box_h = 20, .ofs_x = 0, .ofs_y = 2},
{.bitmap_index = 105975, .adv_w = 640, .box_w = 41, .box_h = 26, .ofs_x = 0, .ofs_y = -1},
{.bitmap_index = 106508, .adv_w = 448, .box_w = 24, .box_h = 32, .ofs_x = 2, .ofs_y = -4},
{.bitmap_index = 106892, .adv_w = 448, .box_w = 28, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 107340, .adv_w = 512, .box_w = 33, .box_h = 33, .ofs_x = -1, .ofs_y = -5},
{.bitmap_index = 107885, .adv_w = 512, .box_w = 32, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 108397, .adv_w = 640, .box_w = 40, .box_h = 24, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 108877, .adv_w = 384, .box_w = 24, .box_h = 32, .ofs_x = 0, .ofs_y = -4},
{.bitmap_index = 109261, .adv_w = 515, .box_w = 33, .box_h = 21, .ofs_x = 0, .ofs_y = 2}
};
/*---------------------
@@ -15360,13 +15427,13 @@ static const uint16_t unicode_list_5[] = {
0x1cd9, 0x1cda, 0x1cdb, 0x1e31, 0x1e35, 0x1e3e, 0x1e40, 0x1e41,
0x1e44, 0x1e49, 0x1e4d, 0x1e5a, 0x1e77, 0x1e8f, 0x1e93, 0x1e94,
0xec30, 0xec37, 0xec3a, 0xec3b, 0xec3c, 0xec40, 0xec42, 0xec44,
0xec48, 0xec4b, 0xec50, 0xec55, 0xec56, 0xec57, 0xec6d, 0xec72,
0xec77, 0xec7a, 0xec7b, 0xec7c, 0xec80, 0xec81, 0xec82, 0xec83,
0xec96, 0xec97, 0xec9d, 0xec9f, 0xeca0, 0xeca3, 0xeca6, 0xeca7,
0xeca8, 0xecaa, 0xecc2, 0xecc4, 0xecf3, 0xecf4, 0xecf6, 0xecf8,
0xed0f, 0xed16, 0xed19, 0xed22, 0xed4b, 0xed53, 0xed87, 0xee1a,
0xee6f, 0xee70, 0xee71, 0xee72, 0xee73, 0xeeb6, 0xeec2, 0xef1c,
0xef33, 0xef8a, 0xf189, 0xf3f1, 0xf4d1
0xec48, 0xec4b, 0xec50, 0xec55, 0xec56, 0xec57, 0xec6d, 0xec71,
0xec72, 0xec77, 0xec7a, 0xec7b, 0xec7c, 0xec80, 0xec81, 0xec82,
0xec83, 0xec96, 0xec97, 0xec9d, 0xec9f, 0xeca0, 0xeca3, 0xeca6,
0xeca7, 0xeca8, 0xecaa, 0xecc2, 0xecc4, 0xecf3, 0xecf4, 0xecf6,
0xecf8, 0xed0f, 0xed16, 0xed19, 0xed22, 0xed4b, 0xed53, 0xed87,
0xee1a, 0xee6f, 0xee70, 0xee71, 0xee72, 0xee73, 0xeeb6, 0xeec2,
0xef1c, 0xef33, 0xef8a, 0xf189, 0xf3f1, 0xf4d1
};
/*Collect the unicode lists and glyph_id offsets*/
@@ -15394,7 +15461,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
},
{
.range_start = 977, .range_length = 62674, .glyph_id_start = 392,
.unicode_list = unicode_list_5, .glyph_id_ofs_list = NULL, .list_length = 117, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
.unicode_list = unicode_list_5, .glyph_id_ofs_list = NULL, .list_length = 118, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
}
};
@@ -15434,7 +15501,7 @@ static lv_font_fmt_txt_dsc_t font_dsc = {
#if LV_VERSION_CHECK(8, 0, 0)
const lv_font_t font_32 = {
#else
lv_font_t font_32 = {
const lv_font_t font_32 = {
#endif
.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/

View File

@@ -392,10 +392,10 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
/*Optionally declare custom fonts here.
*You can use these fonts as default font too and they will be available globally.
*E.g. #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)*/
#define LV_FONT_CUSTOM_DECLARE
#define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(font_32)
/*Always set a default font*/
#define LV_FONT_DEFAULT &lv_font_montserrat_14
#define LV_FONT_DEFAULT &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.

View File

@@ -6,6 +6,7 @@
#include "buffyboard.h"
#include "command_line.h"
#include "config.h"
#include "sq2lv_layouts.h"
#include "terminal.h"
#include "uinput_device.h"
@@ -13,6 +14,8 @@
#include "lvgl/lvgl.h"
#include "../shared/indev.h"
#include "../shared/theme.h"
#include "../shared/themes.h"
#include "../squeek2lvgl/sq2lv.h"
#include <limits.h>
@@ -29,10 +32,10 @@
*/
bb_cli_opts cli_opts;
bb_config_opts conf_opts;
static bool resize_terminals = false;
static lv_obj_t *keyboard = NULL;
static lv_style_t style_text_normal;
/**
@@ -63,20 +66,6 @@ static void sigaction_handler(int signum);
*/
static void terminal_resize_timer_cb(lv_timer_t *timer);
/**
* Set the UI theme.
*
* @param is_dark true if the dark theme should be applied, false if the light theme should be applied
*/
static void set_theme(bool is_dark);
/**
* Handle LV_EVENT_DRAW_TASK_ADDED events from the keyboard widget.
*
* @param event the event object
*/
static void keyboard_draw_task_added_cb(lv_event_t *event);
/**
* Handle LV_EVENT_VALUE_CHANGED events from the keyboard widget.
*
@@ -120,48 +109,6 @@ static void terminal_resize_timer_cb(lv_timer_t *timer) {
}
}
static void set_theme(bool is_dark) {
lv_theme_default_init(NULL, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_CYAN), is_dark, &font_32);
}
static void keyboard_draw_task_added_cb(lv_event_t *event) {
lv_obj_t *obj = lv_event_get_target(event);
lv_buttonmatrix_t *btnm = (lv_buttonmatrix_t *)obj;
lv_draw_task_t *draw_task = lv_event_get_draw_task(event);
lv_draw_dsc_base_t *dsc = draw_task->draw_dsc;
if (dsc->part != LV_PART_ITEMS) {
return;
}
lv_draw_fill_dsc_t *fill_dsc = lv_draw_task_get_fill_dsc(draw_task);
if (!fill_dsc) {
return;
}
if (lv_btnmatrix_get_selected_btn(obj) == dsc->id1 && lv_obj_has_state(obj, LV_STATE_PRESSED)) {
if ((btnm->ctrl_bits[dsc->id1] & SQ2LV_CTRL_MOD_INACTIVE) == SQ2LV_CTRL_MOD_INACTIVE) {
fill_dsc->color = lv_palette_lighten(LV_PALETTE_TEAL, 1);
} else if ((btnm->ctrl_bits[dsc->id1] & SQ2LV_CTRL_MOD_ACTIVE) == SQ2LV_CTRL_MOD_ACTIVE) {
fill_dsc->color = lv_palette_lighten(LV_PALETTE_TEAL, 1);
} else if ((btnm->ctrl_bits[dsc->id1] & SQ2LV_CTRL_NON_CHAR) == SQ2LV_CTRL_NON_CHAR) {
fill_dsc->color = lv_palette_darken(LV_PALETTE_BLUE_GREY, 3);
} else {
fill_dsc->color = lv_palette_lighten(LV_PALETTE_BLUE_GREY, 1);
}
} else {
if ((btnm->ctrl_bits[dsc->id1] & SQ2LV_CTRL_MOD_INACTIVE) == SQ2LV_CTRL_MOD_INACTIVE) {
fill_dsc->color = lv_palette_darken(LV_PALETTE_BLUE_GREY, 4);
} else if ((btnm->ctrl_bits[dsc->id1] & SQ2LV_CTRL_MOD_ACTIVE) == SQ2LV_CTRL_MOD_ACTIVE) {
fill_dsc->color = lv_palette_main(LV_PALETTE_TEAL);
} else if ((btnm->ctrl_bits[dsc->id1] & SQ2LV_CTRL_NON_CHAR) == SQ2LV_CTRL_NON_CHAR) {
fill_dsc->color = lv_palette_darken(LV_PALETTE_BLUE_GREY, 4);
} else {
fill_dsc->color = lv_palette_main(LV_PALETTE_BLUE_GREY);
}
}
}
static void keyboard_value_changed_cb(lv_event_t *event) {
lv_obj_t *kb = lv_event_get_target(event);
@@ -233,6 +180,12 @@ int main(int argc, char *argv[]) {
/* Parse command line options */
bb_cli_parse_opts(argc, argv, &cli_opts);
/* Parse config files */
bb_config_init_opts(&conf_opts);
bb_config_parse_file("/etc/buffyboard.conf", &conf_opts);
bb_config_parse_directory("/etc/buffyboard.conf.d", &conf_opts);
bb_config_parse_files(cli_opts.config_files, cli_opts.num_config_files, &conf_opts);
/* Prepare for terminal resizing and reset */
resize_terminals = bb_terminal_init(2.0f / 3.0f);
if (resize_terminals) {
@@ -258,6 +211,9 @@ int main(int argc, char *argv[]) {
/* Initialise display */
lv_display_t *disp = lv_linux_fbdev_create();
lv_linux_fbdev_set_file(disp, "/dev/fb0");
if (conf_opts.quirks.fbdev_force_refresh) {
lv_linux_fbdev_set_force_refresh(disp, true);
}
int32_t hor_res_phys = lv_display_get_horizontal_resolution(disp);
int32_t ver_res_phys = lv_display_get_vertical_resolution(disp);
lv_display_set_physical_resolution(disp, hor_res_phys, ver_res_phys);
@@ -282,23 +238,22 @@ int main(int argc, char *argv[]) {
/* Start input device monitor and auto-connect available devices */
bb_indev_start_monitor_and_autoconnect(false, true, true);
/* Initialise theme and styles */
set_theme(true);
lv_style_init(&style_text_normal);
lv_style_set_text_font(&style_text_normal, &font_32);
/* Initialise theme */
bb_theme_apply(bb_themes_themes[conf_opts.general.theme_id]);
/* Add keyboard */
keyboard = lv_keyboard_create(lv_scr_act());
// lv_buttonmatrix_set_popovers(keyboard, true);
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_set_pos(keyboard, 0, 0);
lv_obj_set_size(keyboard, LV_HOR_RES, LV_VER_RES);
lv_obj_add_style(keyboard, &style_text_normal, 0);
/* Set up keyboard event handlers */
lv_obj_remove_event_cb(keyboard, lv_keyboard_def_event_cb);
lv_obj_add_event_cb(keyboard, keyboard_value_changed_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_add_event_cb(keyboard, keyboard_draw_task_added_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
lv_obj_add_flag(keyboard, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
bb_theme_prepare_keyboard(keyboard);
/* Apply default keyboard layout */
sq2lv_switch_layout(keyboard, SQ2LV_LAYOUT_TERMINAL_US);
@@ -306,10 +261,9 @@ int main(int argc, char *argv[]) {
/* Start timer for periodically resizing terminals */
lv_timer_create(terminal_resize_timer_cb, 1000, NULL);
/* Run lvgl in "tickless" mode */
/* Periodically run timer / task handler */
while(1) {
lv_task_handler();
usleep(5000);
lv_timer_periodic_handler();
}
return 0;

View File

@@ -14,6 +14,7 @@ add_project_arguments('-DBB_VERSION="@0@"'.format(meson.project_version()), lang
buffyboard_sources = [
'command_line.c',
'config.c',
'font_32.c',
'main.c',
'sq2lv_layouts.c',
@@ -25,6 +26,8 @@ shared_sources = [
'../shared/cursor/cursor.c',
'../shared/indev.c',
'../shared/log.c',
'../shared/theme.c',
'../shared/themes.c',
]
squeek2lvgl_sources = [
@@ -38,6 +41,7 @@ executable(
sources: buffyboard_sources + shared_sources + squeek2lvgl_sources + lvgl_sources,
include_directories: ['..'],
dependencies: [
dependency('inih'),
dependency('libinput'),
dependency('libudev'),
meson.get_compiler('c').find_library('m', required: false),

19
buffyboard/regenerate-fonts.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/sh -ex
# Copyright 2022 Johannes Marbach
# SPDX-License-Identifier: GPL-3.0-or-later
npx lv_font_conv --bpp 4 --size 32 --no-compress -o font_32.c --format lvgl \
--font OpenSans-Regular.ttf \
--range '0x0020-0x007F' \
--range '0x00A0-0x00FF' \
--range '0x0100-0x017F' \
--range '0x0370-0x03FF' \
--range '0x2000-0x206F' \
--range '0x20A0-0x20CF' \
--range '0x2200-0x22FF' \
--font FontAwesome5-Solid+Brands+Regular.woff \
--range '0xF001,0xF008,0xF00B,0xF00C,0xF00D,0xF011,0xF013,0xF015,0xF019,0xF01C,0xF021,0xF026,0xF027,0xF028,0xF03E,0xF0E0,0xF304,0xF043,0xF048,0xF04B,0xF04C,0xF04D,0xF051,0xF052,0xF053,0xF054,0xF067,0xF068,0xF06E,0xF070,0xF071,0xF074,0xF077,0xF078,0xF079,0xF07B,0xF093,0xF095,0xF0C4,0xF0C5,0xF0C7,0xF0C9,0xF0E7,0xF0EA,0xF0F3,0xF11C,0xF124,0xF158,0xF1EB,0xF240,0xF241,0xF242,0xF243,0xF244,0xF287,0xF293,0xF2ED,0xF55A,0xF7C2,0xF8A2' \
--range '0xF042' \
--range '0xF35B'

View File

@@ -3,6 +3,7 @@
**/
#include "sq2lv_layouts.h"
#include "../squeek2lvgl/sq2lv.h"
#include <linux/input.h>
#define SQ2LV_SYMBOL_SHIFT "\xef\x8d\x9b"

View File

@@ -9,11 +9,6 @@
#define SQ2LV_SCANCODES_ENABLED 1
/* Key attributes */
#define SQ2LV_CTRL_NON_CHAR (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKED)
#define SQ2LV_CTRL_MOD_ACTIVE (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKABLE)
#define SQ2LV_CTRL_MOD_INACTIVE (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKABLE | LV_BUTTONMATRIX_CTRL_CHECKED)
/* Layout IDs, values can be used as indexes into the sq2lv_layouts array */
typedef enum {
SQ2LV_LAYOUT_NONE = -1,

View File

@@ -6,10 +6,8 @@
#include "theme.h"
#include "sq2lv_layouts.h"
#include "unl0kr.h"
#include "../shared/log.h"
#include "log.h"
#include "../squeek2lvgl/sq2lv.h"
#include "lvgl/lvgl.h"
@@ -238,7 +236,7 @@ static void apply_theme_cb(lv_theme_t *theme, lv_obj_t *obj) {
return;
}
if (lv_obj_has_flag(obj, UL_WIDGET_HEADER)) {
if (lv_obj_has_flag(obj, BB_WIDGET_HEADER)) {
lv_obj_add_style(obj, &(styles.header), 0);
return;
}
@@ -331,7 +329,7 @@ static void keyboard_draw_task_added_cb(lv_event_t *event) {
return;
}
ul_theme_key *key = NULL;
bb_theme_key *key = NULL;
if ((btnm->ctrl_bits[dsc->id1] & SQ2LV_CTRL_MOD_INACTIVE) == SQ2LV_CTRL_MOD_INACTIVE) {
key = &(current_theme.keyboard.keys.key_mod_inact);
@@ -366,12 +364,12 @@ static void keyboard_draw_task_added_cb(lv_event_t *event) {
* Public functions
*/
void ul_theme_prepare_keyboard(lv_obj_t *keyboard) {
void bb_theme_prepare_keyboard(lv_obj_t *keyboard) {
lv_obj_add_event_cb(keyboard, keyboard_draw_task_added_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
lv_obj_add_flag(keyboard, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
}
void ul_theme_apply(const ul_theme *theme) {
void bb_theme_apply(const ul_theme *theme) {
if (!theme) {
bb_log(BB_LOG_LEVEL_ERROR, "Could not apply theme from NULL pointer");
return;

View File

@@ -4,15 +4,15 @@
*/
#ifndef UL_THEME_H
#define UL_THEME_H
#ifndef BB_THEME_H
#define BB_THEME_H
#include "lvgl/lvgl.h"
#include <stdbool.h>
#include <stdint.h>
#define UL_WIDGET_HEADER LV_OBJ_FLAG_USER_1
#define BB_WIDGET_HEADER LV_OBJ_FLAG_USER_1
/**
* Theming structs
@@ -21,7 +21,7 @@
/* Window theme */
typedef struct {
uint32_t bg_color;
} ul_theme_window;
} bb_theme_window;
/* Header theme */
typedef struct {
@@ -30,30 +30,30 @@ typedef struct {
uint32_t border_color;
lv_coord_t pad;
lv_coord_t gap;
} ul_theme_header;
} bb_theme_header;
/* Key theme for one specific key type and state */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
uint32_t border_color;
} ul_theme_key_state;
} bb_theme_key_state;
/* Key theme for one specific key type and all states */
typedef struct {
ul_theme_key_state normal;
ul_theme_key_state pressed;
} ul_theme_key;
bb_theme_key_state normal;
bb_theme_key_state pressed;
} bb_theme_key;
/* Key theme */
typedef struct {
lv_coord_t border_width;
lv_coord_t corner_radius;
ul_theme_key key_char;
ul_theme_key key_non_char;
ul_theme_key key_mod_act;
ul_theme_key key_mod_inact;
} ul_theme_keys;
bb_theme_key key_char;
bb_theme_key key_non_char;
bb_theme_key key_mod_act;
bb_theme_key key_mod_inact;
} bb_theme_keys;
/* Keyboard theme */
typedef struct {
@@ -62,31 +62,31 @@ typedef struct {
uint32_t border_color;
lv_coord_t pad;
lv_coord_t gap;
ul_theme_keys keys;
} ul_theme_keyboard;
bb_theme_keys keys;
} bb_theme_keyboard;
/* Button theme for one specific button state */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
uint32_t border_color;
} ul_theme_button_state;
} bb_theme_button_state;
/* Button theme */
typedef struct {
lv_coord_t border_width;
lv_coord_t corner_radius;
lv_coord_t pad;
ul_theme_button_state normal;
ul_theme_button_state pressed;
} ul_theme_button;
bb_theme_button_state normal;
bb_theme_button_state pressed;
} bb_theme_button;
/* Text area cursor theme */
typedef struct {
lv_coord_t width;
uint32_t color;
int period;
} ul_theme_textarea_cursor;
} bb_theme_textarea_cursor;
/* Text area theme */
typedef struct {
@@ -97,8 +97,8 @@ typedef struct {
lv_coord_t corner_radius;
lv_coord_t pad;
uint32_t placeholder_color;
ul_theme_textarea_cursor cursor;
} ul_theme_textarea;
bb_theme_textarea_cursor cursor;
} bb_theme_textarea;
/* Dropdown list theme */
typedef struct {
@@ -110,29 +110,29 @@ typedef struct {
uint32_t border_color;
lv_coord_t corner_radius;
lv_coord_t pad;
} ul_theme_dropdown_list;
} bb_theme_dropdown_list;
/* Dropdown theme */
typedef struct {
ul_theme_button button;
ul_theme_dropdown_list list;
} ul_theme_dropdown;
bb_theme_button button;
bb_theme_dropdown_list list;
} bb_theme_dropdown;
/* Label */
typedef struct {
uint32_t fg_color;
} ul_theme_label;
} bb_theme_label;
/* Message box buttons theme */
typedef struct {
lv_coord_t gap;
} ul_theme_msgbox_buttons;
} bb_theme_msgbox_buttons;
/* Message box dimming theme */
typedef struct {
uint32_t color;
short opacity;
} ul_theme_msgbox_dimming;
} bb_theme_msgbox_dimming;
/* Message box theme */
typedef struct {
@@ -143,35 +143,35 @@ typedef struct {
lv_coord_t corner_radius;
lv_coord_t pad;
lv_coord_t gap;
ul_theme_msgbox_buttons buttons;
ul_theme_msgbox_dimming dimming;
} ul_theme_msgbox;
bb_theme_msgbox_buttons buttons;
bb_theme_msgbox_dimming dimming;
} bb_theme_msgbox;
/* Progress bar indicator theme */
typedef struct {
uint32_t bg_color;
} ul_theme_bar_indicator;
} bb_theme_bar_indicator;
/* Progress bar theme */
typedef struct {
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t corner_radius;
ul_theme_bar_indicator indicator;
} ul_theme_bar;
bb_theme_bar_indicator indicator;
} bb_theme_bar;
/* Full theme */
typedef struct {
char *name;
ul_theme_window window;
ul_theme_header header;
ul_theme_keyboard keyboard;
ul_theme_button button;
ul_theme_textarea textarea;
ul_theme_dropdown dropdown;
ul_theme_label label;
ul_theme_msgbox msgbox;
ul_theme_bar bar;
bb_theme_window window;
bb_theme_header header;
bb_theme_keyboard keyboard;
bb_theme_button button;
bb_theme_textarea textarea;
bb_theme_dropdown dropdown;
bb_theme_label label;
bb_theme_msgbox msgbox;
bb_theme_bar bar;
} ul_theme;
/**
@@ -179,13 +179,13 @@ typedef struct {
*
* @param keyboard keyboard widget
*/
void ul_theme_prepare_keyboard(lv_obj_t *keyboard);
void bb_theme_prepare_keyboard(lv_obj_t *keyboard);
/**
* Apply a UI theme.
*
* @param theme the theme to apply
*/
void ul_theme_apply(const ul_theme *theme);
void bb_theme_apply(const ul_theme *theme);
#endif /* UL_THEME_H */
#endif /* BB_THEME_H */

View File

@@ -6,7 +6,7 @@
#include "themes.h"
#include "../shared/log.h"
#include "log.h"
#include <string.h>
@@ -16,7 +16,7 @@
*/
/* Breezy light (based on KDE Breeze color palette, see https://develop.kde.org/hig/style/color/default/) */
static const ul_theme ul_themes_breezy_light = {
static const ul_theme bb_themes_breezy_light = {
.name = "breezy-light",
.window = {
.bg_color = 0xeff0f1
@@ -174,7 +174,7 @@ static const ul_theme ul_themes_breezy_light = {
/* Breezy dark (based on KDE Breeze Dark color palette, see https://develop.kde.org/hig/style/color/dark/) */
static const ul_theme ul_themes_breezy_dark = {
static const ul_theme bb_themes_breezy_dark = {
.name = "breezy-dark",
.window = {
.bg_color = 0x31363b
@@ -331,7 +331,7 @@ static const ul_theme ul_themes_breezy_dark = {
};
/* pmOS light (based on palette https://coolors.co/009900-395e66-db504a-e3b505-ebf5ee) */
static const ul_theme ul_themes_pmos_light = {
static const ul_theme bb_themes_pmos_light = {
.name = "pmos-light",
.window = {
.bg_color = 0xf2f7f8,
@@ -488,7 +488,7 @@ static const ul_theme ul_themes_pmos_light = {
};
/* pmOS dark (based on palette https://coolors.co/009900-395e66-db504a-e3b505-ebf5ee) */
static const ul_theme ul_themes_pmos_dark = {
static const ul_theme bb_themes_pmos_dark = {
.name = "pmos-dark",
.window = {
.bg_color = 0x070c0d
@@ -648,21 +648,21 @@ static const ul_theme ul_themes_pmos_dark = {
* Public interface
*/
const int ul_themes_num_themes = 4;
const ul_theme *ul_themes_themes[] = {
&ul_themes_breezy_light,
&ul_themes_breezy_dark,
&ul_themes_pmos_light,
&ul_themes_pmos_dark
const int bb_themes_num_themes = 4;
const ul_theme *bb_themes_themes[] = {
&bb_themes_breezy_light,
&bb_themes_breezy_dark,
&bb_themes_pmos_light,
&bb_themes_pmos_dark
};
ul_themes_theme_id_t ul_themes_find_theme_with_name(const char *name) {
for (int i = 0; i < ul_themes_num_themes; ++i) {
if (strcmp(ul_themes_themes[i]->name, name) == 0) {
bb_themes_theme_id_t bb_themes_find_theme_with_name(const char *name) {
for (int i = 0; i < bb_themes_num_themes; ++i) {
if (strcmp(bb_themes_themes[i]->name, name) == 0) {
bb_log(BB_LOG_LEVEL_VERBOSE, "Found theme: %s\n", name);
return i;
}
}
bb_log(BB_LOG_LEVEL_WARNING, "Theme %s not found\n", name);
return UL_THEMES_THEME_NONE;
return BB_THEMES_THEME_NONE;
}

33
shared/themes.h Normal file
View File

@@ -0,0 +1,33 @@
/**
* Copyright 2021 Johannes Marbach
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef BB_THEMES_H
#define BB_THEMES_H
#include "theme.h"
/* Theme IDs, values can be used as indexes into the bb_themes_themes array */
typedef enum {
BB_THEMES_THEME_NONE = -1,
BB_THEMES_THEME_BREEZY_LIGHT = 0,
BB_THEMES_THEME_BREEZY_DARK = 1,
BB_THEMES_THEME_PMOS_LIGHT = 2,
BB_THEMES_THEME_PMOS_DARK = 3
} bb_themes_theme_id_t;
/* Themes */
extern const int bb_themes_num_themes;
extern const ul_theme *bb_themes_themes[];
/**
* Find the first theme with a given name.
*
* @param name theme name
* @return ID of the first matching theme or BB_THEMES_THEME_NONE if no theme matched
*/
bb_themes_theme_id_t bb_themes_find_theme_with_name(const char *name);
#endif /* BB_THEMES_H */

View File

@@ -9,6 +9,11 @@
#include "../sq2lv_layouts.h"
/* Key attributes */
#define SQ2LV_CTRL_NON_CHAR (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKED)
#define SQ2LV_CTRL_MOD_ACTIVE (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKABLE)
#define SQ2LV_CTRL_MOD_INACTIVE (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKABLE | LV_BUTTONMATRIX_CTRL_CHECKED)
/**
* Find the first layout with a given short name.
*

View File

@@ -712,6 +712,7 @@ if __name__ == '__main__':
c_builder = SourceFileBuilder()
c_builder.add_include(outfile_h)
c_builder.add_include('../squeek2lvgl/sq2lv.h')
if args.generate_scancodes:
c_builder.add_system_include('linux/input.h')
c_builder.add_line()
@@ -725,11 +726,6 @@ if __name__ == '__main__':
h_builder.add_line()
h_builder.add_line(f'#define SQ2LV_SCANCODES_ENABLED {1 if args.generate_scancodes else 0}')
h_builder.add_line()
h_builder.add_subsection_comment('Key attributes')
h_builder.add_line('#define SQ2LV_CTRL_NON_CHAR (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKED)')
h_builder.add_line('#define SQ2LV_CTRL_MOD_ACTIVE (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKABLE)')
h_builder.add_line('#define SQ2LV_CTRL_MOD_INACTIVE (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKABLE | LV_BUTTONMATRIX_CTRL_CHECKED)')
h_builder.add_line()
layouts = []
unique_scancodes = {}

View File

@@ -92,7 +92,7 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) {
int opt, index = 0;
while ((opt = getopt_long(argc, argv, "c:C:g:d:hvV", long_opts, &index)) != -1) {
while ((opt = getopt_long(argc, argv, "C:g:d:hvV", long_opts, &index)) != -1) {
switch (opt) {
case 'C':
opts->config_files = realloc(opts->config_files, (opts->num_config_files + 1) * sizeof(char *));

View File

@@ -189,14 +189,14 @@ static int parsing_handler(void* user_data, const char* section, const char* key
}
} else if (strcmp(section, "theme") == 0) {
if (strcmp(key, "default") == 0) {
ul_themes_theme_id_t id = ul_themes_find_theme_with_name(value);
if (id != UL_THEMES_THEME_NONE) {
bb_themes_theme_id_t id = bb_themes_find_theme_with_name(value);
if (id != BB_THEMES_THEME_NONE) {
opts->theme.default_id = id;
return 1;
}
} else if (strcmp(key, "alternate") == 0) {
ul_themes_theme_id_t id = ul_themes_find_theme_with_name(value);
if (id != UL_THEMES_THEME_NONE) {
bb_themes_theme_id_t id = bb_themes_find_theme_with_name(value);
if (id != BB_THEMES_THEME_NONE) {
opts->theme.alternate_id = id;
return 1;
}
@@ -263,8 +263,8 @@ void ul_config_init_opts(ul_config_opts *opts) {
opts->keyboard.popovers = true;
opts->textarea.obscured = true;
opts->textarea.bullet = LV_SYMBOL_BULLET;
opts->theme.default_id = UL_THEMES_THEME_BREEZY_DARK;
opts->theme.alternate_id = UL_THEMES_THEME_BREEZY_LIGHT;
opts->theme.default_id = BB_THEMES_THEME_BREEZY_DARK;
opts->theme.alternate_id = BB_THEMES_THEME_BREEZY_LIGHT;
opts->input.keyboard = true;
opts->input.pointer = true;
opts->input.touchscreen = true;

View File

@@ -9,7 +9,7 @@
#include "backends.h"
#include "themes.h"
#include "../shared/themes.h"
#include "sq2lv_layouts.h"
@@ -55,9 +55,9 @@ typedef struct {
*/
typedef struct {
/* Default theme */
ul_themes_theme_id_t default_id;
bb_themes_theme_id_t default_id;
/* Alternate theme */
ul_themes_theme_id_t alternate_id;
bb_themes_theme_id_t alternate_id;
} ul_config_opts_theme;
/**

View File

@@ -9,11 +9,11 @@
#include "config.h"
#include "unl0kr.h"
#include "terminal.h"
#include "theme.h"
#include "themes.h"
#include "../shared/indev.h"
#include "../shared/log.h"
#include "../shared/theme.h"
#include "../shared/themes.h"
#include "../squeek2lvgl/sq2lv.h"
#include "lvgl/lvgl.h"
@@ -220,11 +220,11 @@ static void toggle_theme(void) {
}
static void set_theme(bool is_alternate) {
ul_theme_apply(get_theme(is_alternate));
bb_theme_apply(get_theme(is_alternate));
}
static const ul_theme * get_theme(bool is_alternate) {
return ul_themes_themes[is_alternate ? conf_opts.theme.alternate_id : conf_opts.theme.default_id];
return bb_themes_themes[is_alternate ? conf_opts.theme.alternate_id : conf_opts.theme.default_id];
}
static void toggle_pw_btn_clicked_cb(lv_event_t *event) {
@@ -462,7 +462,7 @@ int main(int argc, char *argv[]) {
/* Header flexbox */
lv_obj_t *header = lv_obj_create(container);
lv_obj_add_flag(header, UL_WIDGET_HEADER);
lv_obj_add_flag(header, BB_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_flex_align(header, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
@@ -561,7 +561,7 @@ int main(int argc, char *argv[]) {
lv_obj_add_event_cb(keyboard, keyboard_ready_cb, LV_EVENT_READY, NULL);
lv_obj_set_pos(keyboard, 0, is_keyboard_hidden ? keyboard_height : 0);
lv_obj_set_size(keyboard, hor_res, keyboard_height);
ul_theme_prepare_keyboard(keyboard);
bb_theme_prepare_keyboard(keyboard);
/* Apply textarea options */
set_password_obscured(conf_opts.textarea.obscured);

View File

@@ -20,14 +20,14 @@ unl0kr_sources = [
'main.c',
'sq2lv_layouts.c',
'terminal.c',
'theme.c',
'themes.c',
]
shared_sources = [
'../shared/cursor/cursor.c',
'../shared/indev.c',
'../shared/log.c',
'../shared/theme.c',
'../shared/themes.c',
]
squeek2lvgl_sources = [

View File

@@ -3,6 +3,7 @@
**/
#include "sq2lv_layouts.h"
#include "../squeek2lvgl/sq2lv.h"
#define SQ2LV_SYMBOL_SHIFT "\xef\x8d\x9b"

View File

@@ -9,11 +9,6 @@
#define SQ2LV_SCANCODES_ENABLED 0
/* Key attributes */
#define SQ2LV_CTRL_NON_CHAR (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKED)
#define SQ2LV_CTRL_MOD_ACTIVE (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKABLE)
#define SQ2LV_CTRL_MOD_INACTIVE (LV_BUTTONMATRIX_CTRL_CLICK_TRIG | LV_BUTTONMATRIX_CTRL_CHECKABLE | LV_BUTTONMATRIX_CTRL_CHECKED)
/* Layout IDs, values can be used as indexes into the sq2lv_layouts array */
typedef enum {
SQ2LV_LAYOUT_NONE = -1,

View File

@@ -1,33 +0,0 @@
/**
* Copyright 2021 Johannes Marbach
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef UL_THEMES_H
#define UL_THEMES_H
#include "theme.h"
/* Theme IDs, values can be used as indexes into the ul_themes_themes array */
typedef enum {
UL_THEMES_THEME_NONE = -1,
UL_THEMES_THEME_BREEZY_LIGHT = 0,
UL_THEMES_THEME_BREEZY_DARK = 1,
UL_THEMES_THEME_PMOS_LIGHT = 2,
UL_THEMES_THEME_PMOS_DARK = 3
} ul_themes_theme_id_t;
/* Themes */
extern const int ul_themes_num_themes;
extern const ul_theme *ul_themes_themes[];
/**
* Find the first theme with a given name.
*
* @param name theme name
* @return ID of the first matching theme or UL_THEMES_THEME_NONE if no theme matched
*/
ul_themes_theme_id_t ul_themes_find_theme_with_name(const char *name);
#endif /* UL_THEMES_H */