Create theming infrastructure and set up default light and dark theme

Relates to: #10
This commit is contained in:
Johannes Marbach
2021-10-05 20:53:37 +02:00
parent 7790becf7c
commit ab2cfdd22a
10 changed files with 908 additions and 89 deletions

1
log.c
View File

@@ -21,6 +21,7 @@
#include "log.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

2
log.h
View File

@@ -21,8 +21,6 @@
#ifndef UL_LOG_H
#define UL_LOG_H
#include <stdio.h>
/**
* Log levels
*/

View File

@@ -488,7 +488,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
# define LV_THEME_DEFAULT_DARK 0
/*1: Enable grow on press*/
# define LV_THEME_DEFAULT_GROW 1
# define LV_THEME_DEFAULT_GROW 0
/*Default transition time in [ms]*/
# define LV_THEME_DEFAULT_TRANSITON_TIME 80

101
main.c
View File

@@ -23,6 +23,8 @@
#include "indev.h"
#include "log.h"
#include "unl0kr.h"
#include "theme.h"
#include "themes.h"
#include "lv_drivers/display/fbdev.h"
@@ -38,15 +40,6 @@
#include <sys/time.h>
/**
* Custom fonts
*/
LV_FONT_DECLARE(montserrat_extended_32);
#define SYMBOL_ADJUST "\xef\x81\x82" // 0xF042 (https://fontawesome.com/v5.15/icons/adjust?style=solid)
/**
* Static variables
*/
@@ -54,14 +47,12 @@ LV_FONT_DECLARE(montserrat_extended_32);
ul_cli_opts cli_opts;
ul_config_opts conf_opts;
bool is_dark_theme = false;
bool is_alternate_theme = false;
bool is_password_obscured = true;
bool is_keyboard_hidden = false;
lv_obj_t *keyboard = NULL;
lv_style_t style_text_normal;
/**
* Static prototypes
@@ -132,13 +123,6 @@ static void set_keyboard_hidden(bool is_hidden);
*/
static void keyboard_anim_y_cb(void *obj, int32_t value);
/**
* Handle LV_EVENT_READY events from the keyboard layout dropdown.
*
* @param event the event object
*/
static void layout_dropdown_ready_cb(lv_event_t *event);
/**
* Handle LV_EVENT_VALUE_CHANGED events from the keyboard layout dropdown.
*
@@ -160,13 +144,6 @@ static void shutdown_btn_clicked_cb(lv_event_t *event);
*/
static void shutdown_mbox_value_changed_cb(lv_event_t *event);
/**
* Handle LV_EVENT_DRAW_PART_BEGIN events from the keyboard widget.
*
* @param event the event object
*/
static void keyboard_draw_part_begin_cb(lv_event_t *event);
/**
* Handle LV_EVENT_VALUE_CHANGED events from the keyboard widget.
*
@@ -191,12 +168,12 @@ static void toggle_theme_btn_clicked_cb(lv_event_t *event) {
}
static void toggle_theme(void) {
is_dark_theme = !is_dark_theme;
set_theme(is_dark_theme);
is_alternate_theme = !is_alternate_theme;
set_theme(is_alternate_theme);
}
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, &montserrat_extended_32);
static void set_theme(bool is_alternate) {
ul_theme_apply(is_alternate ? &ul_themes_breezy_light : &ul_themes_breezy_dark);
}
static void toggle_pw_btn_clicked_cb(lv_event_t *event) {
@@ -249,12 +226,6 @@ static void keyboard_anim_y_cb(void *obj, int32_t value) {
lv_obj_set_y(obj, value);
}
static void layout_dropdown_ready_cb(lv_event_t *event) {
lv_obj_t *dropdown = lv_event_get_target(event);
lv_obj_t *list = lv_dropdown_get_list(dropdown);
lv_obj_add_style(list, &style_text_normal, 0);
}
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);
@@ -277,38 +248,6 @@ static void shutdown_mbox_value_changed_cb(lv_event_t *event) {
lv_msgbox_close(mbox);
}
static void keyboard_draw_part_begin_cb(lv_event_t *event) {
lv_obj_t *obj = lv_event_get_target(event);
lv_btnmatrix_t *btnm = (lv_btnmatrix_t *)obj;
lv_obj_draw_part_dsc_t *dsc = lv_event_get_param(event);
if (dsc->part != LV_PART_ITEMS) {
return;
}
if (lv_btnmatrix_get_selected_btn(obj) == dsc->id) { /* key is held down */
if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_MOD_INACTIVE) == SQ2LV_CTRL_MOD_INACTIVE) {
dsc->rect_dsc->bg_color = lv_palette_lighten(LV_PALETTE_TEAL, 1);
} else if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_MOD_ACTIVE) == SQ2LV_CTRL_MOD_ACTIVE) {
dsc->rect_dsc->bg_color = lv_palette_lighten(LV_PALETTE_TEAL, 1);
} else if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_NON_CHAR) == SQ2LV_CTRL_NON_CHAR) {
dsc->rect_dsc->bg_color = lv_palette_darken(LV_PALETTE_BLUE_GREY, 3);
} else {
dsc->rect_dsc->bg_color = lv_palette_lighten(LV_PALETTE_BLUE_GREY, 1);
}
} else { /* key is not held down */
if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_MOD_INACTIVE) == SQ2LV_CTRL_MOD_INACTIVE) {
dsc->rect_dsc->bg_color = lv_palette_darken(LV_PALETTE_BLUE_GREY, 4);
} else if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_MOD_ACTIVE) == SQ2LV_CTRL_MOD_ACTIVE) {
dsc->rect_dsc->bg_color = lv_palette_main(LV_PALETTE_TEAL);
} else if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_NON_CHAR) == SQ2LV_CTRL_NON_CHAR) {
dsc->rect_dsc->bg_color = lv_palette_darken(LV_PALETTE_BLUE_GREY, 4);
} else {
dsc->rect_dsc->bg_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);
@@ -394,10 +333,8 @@ int main(int argc, char *argv[]) {
is_keyboard_hidden = true;
}
/* Initialise theme and styles */
set_theme(is_dark_theme);
lv_style_init(&style_text_normal);
lv_style_set_text_font(&style_text_normal, &montserrat_extended_32);
/* Initialise theme */
set_theme(is_alternate_theme);
/* Figure out a few numbers for sizing and positioning */
const int keyboard_height = ver_res / 3;
@@ -417,9 +354,8 @@ int main(int argc, char *argv[]) {
lv_obj_set_grid_cell(toggle_theme_btn, LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1);
lv_obj_set_size(toggle_theme_btn, 64, 64);
lv_obj_t *toggle_theme_btn_label = lv_label_create(toggle_theme_btn);
lv_label_set_text(toggle_theme_btn_label, SYMBOL_ADJUST);
lv_label_set_text(toggle_theme_btn_label, UL_SYMBOL_ADJUST);
lv_obj_center(toggle_theme_btn_label);
lv_obj_add_style(toggle_theme_btn_label, &style_text_normal, 0);
/* Show / hide keyboard button */
lv_obj_t *toggle_kb_btn = lv_btn_create(btn_row);
@@ -429,17 +365,14 @@ int main(int argc, char *argv[]) {
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);
lv_obj_add_style(toggle_kb_btn_label, &style_text_normal, 0);
/* Keyboard layout dropdown */
lv_obj_t *layout_dropdown = lv_dropdown_create(btn_row);
lv_dropdown_set_options(layout_dropdown, sq2lv_layout_short_names);
lv_obj_add_event_cb(layout_dropdown, layout_dropdown_ready_cb, LV_EVENT_READY, NULL);
lv_obj_add_event_cb(layout_dropdown, layout_dropdown_value_changed_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_set_grid_cell(layout_dropdown, LV_GRID_ALIGN_START, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1);
lv_obj_set_height(layout_dropdown, 64);
// lv_obj_set_height(layout_dropdown, 64);
lv_obj_set_width(layout_dropdown, 160);
lv_obj_add_style(layout_dropdown, &style_text_normal, 0);
/* Shutdown button */
lv_obj_t *shutdown_btn = lv_btn_create(btn_row);
@@ -449,17 +382,16 @@ int main(int argc, char *argv[]) {
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_add_style(shutdown_btn_label, &style_text_normal, 0);
/* Textarea */
lv_obj_t *textarea = lv_textarea_create(lv_scr_act());
lv_textarea_set_one_line(textarea, true);
lv_textarea_set_password_mode(textarea, true);
lv_textarea_set_placeholder_text(textarea, "Enter password...");
lv_obj_set_size(textarea, hor_res - 60 > 512 ? 512 : hor_res - 60, 64);
// lv_obj_set_size(textarea, hor_res - 60 > 512 ? 512 : hor_res - 60, 64);
lv_obj_set_width(textarea, hor_res - 60 > 512 ? 512 : hor_res - 60);
lv_obj_align(textarea, LV_ALIGN_CENTER, 0, ver_res / 2 - keyboard_height - 3 * row_height / 2);
lv_obj_add_state(textarea, LV_STATE_FOCUSED);
lv_obj_add_style(textarea, &style_text_normal, 0);
/* Route physical keyboard input into textarea */
ul_indev_set_up_textarea_for_keyboard_input(textarea);
@@ -467,12 +399,11 @@ int main(int argc, char *argv[]) {
/* Reveal / obscure password button */
lv_obj_t *toggle_pw_btn = lv_btn_create(lv_scr_act());
lv_obj_align(toggle_pw_btn, LV_ALIGN_CENTER, (hor_res - 60 > 512 ? 512 : hor_res - 60) / 2 + 32, ver_res / 2 - keyboard_height - 3 * row_height / 2);
lv_obj_set_size(toggle_pw_btn, 64, 64);
// lv_obj_set_size(toggle_pw_btn, 64, 64);
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_add_event_cb(toggle_pw_btn, toggle_pw_btn_clicked_cb, LV_EVENT_CLICKED, NULL);
lv_obj_add_style(toggle_pw_btn_label, &style_text_normal, 0);
/* Label */
lv_obj_t *spangroup = lv_spangroup_create(lv_scr_act());
@@ -480,7 +411,6 @@ int main(int argc, char *argv[]) {
lv_spangroup_set_mode(spangroup, LV_SPAN_MODE_BREAK);
lv_obj_set_size(spangroup, hor_res - 40, 2 * row_height);
lv_obj_align(spangroup, LV_ALIGN_CENTER, 0, ver_res / 2 - keyboard_height);
lv_obj_add_style(spangroup, &style_text_normal, 0);
lv_span_t *span1 = lv_spangroup_new_span(spangroup);
lv_span_set_text(span1, "Password required to unlock ");
lv_span_t *span2 = lv_spangroup_new_span(spangroup);
@@ -492,12 +422,11 @@ int main(int argc, char *argv[]) {
lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_TEXT_LOWER);
lv_keyboard_set_textarea(keyboard, textarea);
lv_obj_remove_event_cb(keyboard, lv_keyboard_def_event_cb);
lv_obj_add_event_cb(keyboard, keyboard_draw_part_begin_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
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_pos(keyboard, 0, is_keyboard_hidden ? keyboard_height : 0);
lv_obj_set_size(keyboard, hor_res, keyboard_height);
lv_obj_add_style(keyboard, &style_text_normal, 0);
ul_theme_prepare_keyboard(keyboard);
/* Apply textarea options */
set_password_obscured(conf_opts.textarea.obscured);

View File

@@ -35,6 +35,8 @@ unl0kr_sources = [
'main.c',
'montserrat_extended_32.c',
'sq2lv_layouts.c',
'theme.c',
'themes.c'
]
squeek2lvgl_sources = [

341
theme.c Normal file
View File

@@ -0,0 +1,341 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "theme.h"
#include "log.h"
#include "sq2lv_layouts.h"
#include "unl0kr.h"
#include "lvgl/lvgl.h"
/**
* Static variables
*/
static ul_theme current_theme;
static lv_theme_t lv_theme;
static struct {
lv_style_t widget;
lv_style_t window;
lv_style_t header;
lv_style_t keyboard;
lv_style_t key;
lv_style_t button;
lv_style_t button_pressed;
lv_style_t textarea;
lv_style_t textarea_placeholder;
lv_style_t textarea_cursor;
lv_style_t dropdown;
lv_style_t dropdown_list;
lv_style_t dropdown_list_selected;
lv_style_t label;
lv_style_t msgbox;
lv_style_t msgbox_btnmatrix;
lv_style_t msgbox_background;
} styles;
static bool are_styles_initialised = false;
/**
* Static prototypes
*/
/**
* Set up the static styles for a specific theme.
*
* @param theme theme to derive the styles from
*/
static void init_styles(ul_theme *theme);
/**
* Initialise or reset a style.
*
* @param style style to reset
*/
static void reset_style(lv_style_t *style);
/**
* Apply a theme to an object.
*
* @param theme theme to apply
* @param obj object to style
*/
static void apply_theme_cb(lv_theme_t *theme, lv_obj_t *obj);
/**
* Handle LV_EVENT_DRAW_PART_BEGIN events from the keyboard widget.
*
* @param event the event object
*/
static void keyboard_draw_part_begin_cb(lv_event_t *event);
/**
* Static functions
*/
static void init_styles(ul_theme *theme) {
reset_style(&(styles.widget));
lv_style_set_text_font(&(styles.widget), &montserrat_extended_32);
reset_style(&(styles.window));
lv_style_set_bg_opa(&(styles.window), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.window), lv_color_hex(theme->window.bg_color));
reset_style(&(styles.header));
lv_style_set_bg_opa(&(styles.header), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.header), lv_color_hex(theme->header.bg_color));
lv_style_set_border_side(&(styles.header), LV_BORDER_SIDE_BOTTOM);
lv_style_set_border_width(&(styles.header), lv_dpx(theme->header.border_width));
lv_style_set_border_color(&(styles.header), lv_color_hex(theme->header.border_color));
lv_style_set_pad_all(&(styles.header), lv_dpx(theme->header.pad));
lv_style_set_pad_gap(&(styles.header), lv_dpx(theme->header.gap));
reset_style(&(styles.keyboard));
lv_style_set_bg_opa(&(styles.keyboard), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.keyboard), lv_color_hex(theme->keyboard.bg_color));
lv_style_set_border_side(&(styles.keyboard), LV_BORDER_SIDE_TOP);
lv_style_set_border_width(&(styles.keyboard), lv_dpx(theme->keyboard.border_width));
lv_style_set_border_color(&(styles.keyboard), lv_color_hex(theme->keyboard.border_color));
lv_style_set_pad_all(&(styles.keyboard), lv_dpx(theme->keyboard.pad));
lv_style_set_pad_gap(&(styles.keyboard), lv_dpx(theme->keyboard.gap));
reset_style(&(styles.key));
lv_style_set_bg_opa(&(styles.key), LV_OPA_COVER);
lv_style_set_border_side(&(styles.key), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.key), lv_dpx(theme->keyboard.keys.border_width));
lv_style_set_radius(&(styles.key), lv_dpx(theme->keyboard.keys.corner_radius));
reset_style(&(styles.button));
lv_style_set_text_color(&(styles.button), lv_color_hex(theme->button.normal.fg_color));
lv_style_set_bg_opa(&(styles.button), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.button), lv_color_hex(theme->button.normal.bg_color));
lv_style_set_border_side(&(styles.button), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.button), lv_dpx(theme->button.border_width));
lv_style_set_border_color(&(styles.button), lv_color_hex(theme->button.normal.border_color));
lv_style_set_radius(&(styles.button), lv_dpx(theme->button.corner_radius));
lv_style_set_pad_all(&(styles.button), lv_dpx(theme->button.pad));
reset_style(&(styles.button_pressed));
lv_style_set_text_color(&(styles.button_pressed), lv_color_hex(theme->button.pressed.fg_color));
lv_style_set_bg_color(&(styles.button_pressed), lv_color_hex(theme->button.pressed.bg_color));
lv_style_set_border_color(&(styles.button_pressed), lv_color_hex(theme->button.pressed.border_color));
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_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));
lv_style_set_radius(&(styles.textarea), lv_dpx(theme->textarea.corner_radius));
lv_style_set_pad_all(&(styles.textarea), lv_dpx(theme->textarea.pad));
reset_style(&(styles.textarea_placeholder));
lv_style_set_text_color(&(styles.textarea_placeholder), lv_color_hex(theme->textarea.placeholder_color));
reset_style(&(styles.textarea_cursor));
lv_style_set_border_side(&(styles.textarea_cursor), LV_BORDER_SIDE_LEFT);
lv_style_set_border_width(&(styles.textarea_cursor), lv_dpx(theme->textarea.cursor.width));
lv_style_set_border_color(&(styles.textarea_cursor), lv_color_hex(theme->textarea.cursor.color));
lv_style_set_anim_time(&(styles.textarea_cursor), theme->textarea.cursor.period);
reset_style(&(styles.dropdown));
lv_style_set_text_color(&(styles.dropdown), lv_color_hex(theme->dropdown.box.fg_color));
lv_style_set_bg_opa(&(styles.dropdown), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.dropdown), lv_color_hex(theme->dropdown.box.bg_color));
lv_style_set_border_side(&(styles.dropdown), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.dropdown), lv_dpx(theme->dropdown.box.border_width));
lv_style_set_border_color(&(styles.dropdown), lv_color_hex(theme->dropdown.box.border_color));
lv_style_set_radius(&(styles.dropdown), lv_dpx(theme->dropdown.box.corner_radius));
lv_style_set_pad_all(&(styles.dropdown), lv_dpx(theme->dropdown.box.pad));
reset_style(&(styles.dropdown_list));
lv_style_set_text_color(&(styles.dropdown_list), lv_color_hex(theme->dropdown.list.fg_color));
lv_style_set_bg_opa(&(styles.dropdown_list), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.dropdown_list), lv_color_hex(theme->dropdown.list.bg_color));
lv_style_set_border_side(&(styles.dropdown_list), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.dropdown_list), lv_dpx(theme->dropdown.list.border_width));
lv_style_set_border_color(&(styles.dropdown_list), lv_color_hex(theme->dropdown.list.border_color));
lv_style_set_radius(&(styles.dropdown_list), lv_dpx(theme->dropdown.list.corner_radius));
lv_style_set_pad_all(&(styles.dropdown_list), lv_dpx(theme->dropdown.list.pad));
reset_style(&(styles.dropdown_list_selected));
lv_style_set_text_color(&(styles.dropdown_list_selected), lv_color_hex(theme->dropdown.list.selection_fg_color));
lv_style_set_bg_opa(&(styles.dropdown_list_selected), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.dropdown_list_selected), lv_color_hex(theme->dropdown.list.selection_bg_color));
reset_style(&(styles.label));
lv_style_set_text_color(&(styles.label), lv_color_hex(theme->label.fg_color));
reset_style(&(styles.msgbox));
lv_style_set_text_color(&(styles.msgbox), lv_color_hex(theme->msgbox.fg_color));
lv_style_set_bg_opa(&(styles.msgbox), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.msgbox), lv_color_hex(theme->msgbox.bg_color));
lv_style_set_border_side(&(styles.msgbox), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.msgbox), lv_dpx(theme->msgbox.border_width));
lv_style_set_border_color(&(styles.msgbox), lv_color_hex(theme->msgbox.border_color));
lv_style_set_radius(&(styles.msgbox), lv_dpx(theme->msgbox.corner_radius));
lv_style_set_pad_all(&(styles.msgbox), lv_dpx(theme->msgbox.pad));
reset_style(&(styles.msgbox_btnmatrix));
lv_style_set_pad_top(&(styles.msgbox_btnmatrix), lv_dpx(theme->msgbox.buttons.pad));
lv_style_set_pad_gap(&(styles.msgbox_btnmatrix), lv_dpx(theme->msgbox.buttons.gap));
reset_style(&(styles.msgbox_background));
lv_style_set_bg_color(&(styles.msgbox_background), lv_color_hex(theme->msgbox.dimming.color));
lv_style_set_bg_opa(&(styles.msgbox_background), theme->msgbox.dimming.opacity);
are_styles_initialised = true;
}
static void reset_style(lv_style_t *style) {
if (are_styles_initialised) {
lv_style_reset(style);
} else {
lv_style_init(style);
}
}
static void apply_theme_cb(lv_theme_t *theme, lv_obj_t *obj) {
lv_obj_add_style(obj, &(styles.widget), 0);
if (lv_obj_get_parent(obj) == NULL) {
lv_obj_add_style(obj, &(styles.window), 0);
return;
}
if (lv_obj_check_type(obj, &lv_keyboard_class)) {
lv_obj_add_style(obj, &(styles.keyboard), 0);
lv_obj_add_style(obj, &(styles.key), LV_PART_ITEMS);
return;
}
if (lv_obj_check_type(obj, &lv_btn_class)) {
lv_obj_add_style(obj, &(styles.button), 0);
lv_obj_add_style(obj, &(styles.button_pressed), LV_STATE_PRESSED);
return;
}
if (lv_obj_check_type(obj, &lv_textarea_class)) {
lv_obj_add_style(obj, &(styles.textarea), 0);
lv_obj_add_style(obj, &(styles.textarea_placeholder), LV_PART_TEXTAREA_PLACEHOLDER);
lv_obj_add_style(obj, &(styles.textarea_cursor), LV_PART_CURSOR | LV_STATE_FOCUSED);
return;
}
if (lv_obj_check_type(obj, &lv_dropdown_class)) {
lv_obj_add_style(obj, &(styles.dropdown), 0);
return;
}
if (lv_obj_check_type(obj, &lv_dropdownlist_class)) {
lv_obj_add_style(obj, &(styles.dropdown_list), 0);
lv_obj_add_style(obj, &(styles.dropdown_list_selected), LV_PART_SELECTED | LV_STATE_CHECKED);
lv_obj_add_style(obj, &(styles.dropdown_list_selected), LV_PART_SELECTED | LV_STATE_PRESSED);
return;
}
if (lv_obj_check_type(obj, &lv_label_class) || lv_obj_check_type(obj, &lv_spangroup_class)) {
lv_obj_add_style(obj, &(styles.label), 0);
return;
}
if (lv_obj_check_type(obj, &lv_msgbox_class)) {
lv_obj_add_style(obj, &(styles.msgbox), 0);
return;
}
if (lv_obj_check_type(obj, &lv_btnmatrix_class) && lv_obj_check_type(lv_obj_get_parent(obj), &lv_msgbox_class)) {
lv_obj_add_style(obj, &(styles.msgbox_btnmatrix), 0);
lv_obj_add_style(obj, &(styles.button), LV_PART_ITEMS);
lv_obj_add_style(obj, &(styles.button_pressed), LV_PART_ITEMS | LV_STATE_PRESSED);
return;
}
if (lv_obj_check_type(obj, &lv_msgbox_backdrop_class)) {
lv_obj_add_style(obj, &(styles.msgbox_background), 0);
return;
}
/* If none of the if's above matched, this has to be the header */
lv_obj_add_style(obj, &(styles.header), 0);
}
static void keyboard_draw_part_begin_cb(lv_event_t *event) {
lv_obj_t *obj = lv_event_get_target(event);
lv_btnmatrix_t *btnm = (lv_btnmatrix_t *)obj;
lv_obj_draw_part_dsc_t *dsc = lv_event_get_param(event);
if (dsc->part != LV_PART_ITEMS) {
return;
}
ul_theme_key *key = NULL;
if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_MOD_INACTIVE) == SQ2LV_CTRL_MOD_INACTIVE) {
key = &(current_theme.keyboard.keys.key_mod_inact);
} else if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_MOD_ACTIVE) == SQ2LV_CTRL_MOD_ACTIVE) {
key = &(current_theme.keyboard.keys.key_mod_act);
} else if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_NON_CHAR) == SQ2LV_CTRL_NON_CHAR) {
key = &(current_theme.keyboard.keys.key_non_char);
} else {
key = &(current_theme.keyboard.keys.key_char);
}
bool pressed = lv_btnmatrix_get_selected_btn(obj) == dsc->id;
dsc->label_dsc->color = lv_color_hex((pressed ? key->pressed : key->normal).fg_color);
dsc->rect_dsc->bg_color = lv_color_hex((pressed ? key->pressed : key->normal).bg_color);
dsc->rect_dsc->border_color = lv_color_hex((pressed ? key->pressed : key->normal).border_color);
}
/**
* Public functions
*/
void ul_theme_prepare_keyboard(lv_obj_t *keyboard) {
lv_obj_add_event_cb(keyboard, keyboard_draw_part_begin_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
}
void ul_theme_apply(ul_theme *theme) {
if (!theme) {
ul_log(UL_LOG_LEVEL_ERROR, "Could not apply theme from NULL pointer");
return;
}
lv_theme.disp = NULL;
lv_theme.font_small = &montserrat_extended_32;
lv_theme.font_normal = &montserrat_extended_32;
lv_theme.font_large = &montserrat_extended_32;
lv_theme.apply_cb = apply_theme_cb;
current_theme = *theme;
init_styles(theme);
lv_obj_report_style_change(NULL);
lv_disp_set_theme(NULL, &lv_theme);
lv_theme_apply(lv_scr_act());
}

198
theme.h Normal file
View File

@@ -0,0 +1,198 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_THEME_H
#define UL_THEME_H
#include "lvgl/lvgl.h"
#include <stdbool.h>
#include <stdint.h>
/**
* Theming structs
*/
/* Window theme */
typedef struct {
uint32_t bg_color;
} ul_theme_window;
/* Header theme */
typedef struct {
uint32_t bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t pad;
lv_coord_t gap;
} ul_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;
/* 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;
/* 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;
/* Keyboard theme */
typedef struct {
uint32_t bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t pad;
lv_coord_t gap;
ul_theme_keys keys;
} ul_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;
/* 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;
/* Text area cursor theme */
typedef struct {
lv_coord_t width;
uint32_t color;
int period;
} ul_theme_textarea_cursor;
/* Text area theme */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t corner_radius;
lv_coord_t pad;
uint32_t placeholder_color;
ul_theme_textarea_cursor cursor;
} ul_theme_textarea;
/* Dropdown box theme */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t corner_radius;
lv_coord_t pad;
} ul_theme_dropdown_box;
/* Dropdown list theme */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
uint32_t selection_fg_color;
uint32_t selection_bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t corner_radius;
lv_coord_t pad;
} ul_theme_dropdown_list;
/* Dropdown theme */
typedef struct {
ul_theme_dropdown_box box;
ul_theme_dropdown_list list;
} ul_theme_dropdown;
/* Label */
typedef struct {
uint32_t fg_color;
} ul_theme_label;
/* Message box buttons theme */
typedef struct {
lv_coord_t pad;
lv_coord_t gap;
} ul_theme_msgbox_buttons;
/* Message box dimming theme */
typedef struct {
uint32_t color;
short opacity;
} ul_theme_msgbox_dimming;
/* Message box theme */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t corner_radius;
lv_coord_t pad;
ul_theme_msgbox_buttons buttons;
ul_theme_msgbox_dimming dimming;
} ul_theme_msgbox;
/* Full theme */
typedef struct {
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;
/**
* Prepare a keyboard widget to be themed with a theme.
*
* @param keyboard keyboard widget
*/
void ul_theme_prepare_keyboard(lv_obj_t *keyboard);
/**
* Apply a UI theme.
*
* @param theme the theme to apply
*/
void ul_theme_apply(ul_theme *theme);
#endif /* UL_THEME_H */

311
themes.c Normal file
View File

@@ -0,0 +1,311 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "themes.h"
/**
* Breezy light (based on KDE Breeze color palette, see https://develop.kde.org/hig/style/color/default/)
*/
ul_theme ul_themes_breezy_light = {
.window = {
.bg_color = 0xeff0f1
},
.header = {
.bg_color = 0xfcfcfc,
.border_width = 1,
.border_color = 0xbdc3c7,
.pad = 10,
.gap = 10
},
.keyboard = {
.bg_color = 0xfcfcfc,
.border_width = 1,
.border_color = 0xbdc3c7,
.pad = 10,
.gap = 10,
.keys = {
.border_width = 1,
.corner_radius = 5,
.key_char = {
.normal = {
.fg_color = 0x232629,
.bg_color = 0xeff0f1,
.border_color = 0xbdc3c7
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_non_char = {
.normal = {
.fg_color = 0x232629,
.bg_color = 0xbdc3c7,
.border_color = 0x7f8c8d
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_mod_act = {
.normal = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_mod_inact = {
.normal = {
.fg_color = 0x232629,
.bg_color = 0xbdc3c7,
.border_color = 0x7f8c8d
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
}
}
},
.button = {
.border_width = 1,
.corner_radius = 5,
.pad = 5,
.normal = {
.fg_color = 0x232629,
.bg_color = 0xeff0f1,
.border_color = 0xbdc3c7
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.textarea = {
.fg_color = 0x232629,
.bg_color = 0xfcfcfc,
.border_width = 1,
.border_color = 0xbdc3c7,
.corner_radius = 5,
.pad = 5,
.placeholder_color = 0x7f8c8d,
.cursor = {
.width = 1,
.color = 0x232629,
.period = 700
}
},
.dropdown = {
.box = {
.fg_color = 0x232629,
.bg_color = 0xeff0f1,
.border_width = 1,
.border_color = 0xbdc3c7,
.corner_radius = 5,
.pad = 5
},
.list = {
.fg_color = 0x232629,
.bg_color = 0xfcfcfc,
.selection_fg_color = 0x232629,
.selection_bg_color = 0x3daee9,
.border_width = 1,
.border_color = 0xbdc3c7,
.corner_radius = 0,
.pad = 0
}
},
.label = {
.fg_color = 0x232629
},
.msgbox = {
.fg_color = 0x232629,
.bg_color = 0xeff0f1,
.border_width = 1,
.border_color = 0xbdc3c7,
.corner_radius = 0,
.pad = 10,
.buttons = {
.pad = 10,
.gap = 5
},
.dimming = {
.color = 0x232629,
.opacity = 178
}
}
};
/**
* Breezy dark (based on KDE Breeze Dark color palette, see https://develop.kde.org/hig/style/color/dark/)
*/
ul_theme ul_themes_breezy_dark = {
.window = {
.bg_color = 0x31363b
},
.header = {
.bg_color = 0x232629,
.border_width = 1,
.border_color = 0x3b4045,
.pad = 10,
.gap = 10
},
.keyboard = {
.bg_color = 0x232629,
.border_width = 1,
.border_color = 0x3b4045,
.pad = 10,
.gap = 10,
.keys = {
.border_width = 1,
.corner_radius = 5,
.key_char = {
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x31363b,
.border_color = 0x3b4045
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_non_char = {
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x4d4d4d,
.border_color = 0x7f8c8d
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_mod_act = {
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_mod_inact = {
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x4d4d4d,
.border_color = 0x7f8c8d
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
}
}
},
.button = {
.border_width = 1,
.corner_radius = 5,
.pad = 5,
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x31363b,
.border_color = 0x3b4045
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.textarea = {
.fg_color = 0xeff0f1,
.bg_color = 0x232629,
.border_width = 1,
.border_color = 0x3b4045,
.corner_radius = 5,
.pad = 5,
.placeholder_color = 0x7f8c8d,
.cursor = {
.width = 1,
.color = 0x232629,
.period = 700
}
},
.dropdown = {
.box = {
.fg_color = 0xeff0f1,
.bg_color = 0x31363b,
.border_width = 1,
.border_color = 0x3b4045,
.corner_radius = 5,
.pad = 5
},
.list = {
.fg_color = 0xeff0f1,
.bg_color = 0x232629,
.selection_fg_color = 0x232629,
.selection_bg_color = 0x3daee9,
.border_width = 1,
.border_color = 0x3b4045,
.corner_radius = 0,
.pad = 0
}
},
.label = {
.fg_color = 0xeff0f1
},
.msgbox = {
.fg_color = 0xeff0f1,
.bg_color = 0x31363b,
.border_width = 1,
.border_color = 0x3b4045,
.corner_radius = 0,
.pad = 10,
.buttons = {
.pad = 10,
.gap = 5
},
.dimming = {
.color = 0x232629,
.opacity = 178
}
}
};

29
themes.h Normal file
View File

@@ -0,0 +1,29 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_THEMES_H
#define UL_THEMES_H
#include "theme.h"
extern ul_theme ul_themes_breezy_light;
extern ul_theme ul_themes_breezy_dark;
#endif /* UL_THEMES_H */

View File

@@ -21,8 +21,18 @@
#ifndef UL_UNL0KR_H
#define UL_UNL0KR_H
#include "lvgl/lvgl.h"
#ifndef UL_VERSION
#define UL_VERSION "?" /* Just to silence IDE warning. Real version injected by meson during build. */
#endif
/**
* Fonts
*/
LV_FONT_DECLARE(montserrat_extended_32);
#define UL_SYMBOL_ADJUST "\xef\x81\x82" // 0xF042 (https://fontawesome.com/v5.15/icons/adjust?style=solid)
#endif /* UL_UNL0KR_H */