diff --git a/config/boards/shields/nice_view/CMakeLists.txt b/config/boards/shields/nice_view/CMakeLists.txt new file mode 100644 index 0000000..4d4fb05 --- /dev/null +++ b/config/boards/shields/nice_view/CMakeLists.txt @@ -0,0 +1,12 @@ +if(CONFIG_ZMK_DISPLAY AND CONFIG_CUSTOM_WIDGET_STATUS) + zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include) + zephyr_library_sources(custom_status_screen.c) + target_sources(app PRIVATE widgets/bolt.c) + target_sources(app PRIVATE widgets/util.c) + target_sources(app PRIVATE widgets/art.c) + if(NOT CONFIG_ZMK_SPLIT OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + target_sources(app PRIVATE widgets/status.c) + else() + target_sources(app PRIVATE widgets/peripheral_status.c) + endif() +endif() diff --git a/config/boards/shields/nice_view/Kconfig.defconfig b/config/boards/shields/nice_view/Kconfig.defconfig new file mode 100644 index 0000000..a3e31b9 --- /dev/null +++ b/config/boards/shields/nice_view/Kconfig.defconfig @@ -0,0 +1,48 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_NICE_VIEW + +choice ZMK_DISPLAY_STATUS_SCREEN + default ZMK_DISPLAY_STATUS_SCREEN_CUSTOM +endchoice + + +if ZMK_DISPLAY + +config LV_Z_VDB_SIZE + default 100 + +config LV_Z_DPI + default 161 + +config LV_Z_BITS_PER_PIXEL + default 1 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_1 +endchoice + +endif # ZMK_DISPLAY + +config CUSTOM_WIDGET_STATUS + bool "Custom status widget" + default y if ZMK_DISPLAY_STATUS_SCREEN_CUSTOM + select LV_FONT_MONTSERRAT_16 + select LV_USE_IMG + select LV_USE_CANVAS + +if !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL + +config CUSTOM_WIDGET_STATUS + select LV_FONT_MONTSERRAT_18 + select LV_FONT_MONTSERRAT_14 + select LV_FONT_UNSCII_16 + select ZMK_WPM + +endif # !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL + +config CUSTOM_WIDGET_INVERTED + bool "Invert custom status widget" + +endif diff --git a/config/boards/shields/nice_view/Kconfig.shield b/config/boards/shields/nice_view/Kconfig.shield new file mode 100644 index 0000000..fbe4fde --- /dev/null +++ b/config/boards/shields/nice_view/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_NICE_VIEW + def_bool $(shields_list_contains,nice_view) diff --git a/config/boards/shields/nice_view/README.md b/config/boards/shields/nice_view/README.md new file mode 100644 index 0000000..fa90953 --- /dev/null +++ b/config/boards/shields/nice_view/README.md @@ -0,0 +1,5 @@ +# nice!view + +The nice!view is a low-power, high refresh rate display meant to replace I2C OLEDs traditionally used. + +This shield requires that an `&nice_view_spi` labeled SPI bus is provided with _at least_ MOSI, SCK, and CS pins defined. diff --git a/config/boards/shields/nice_view/custom_status_screen.c b/config/boards/shields/nice_view/custom_status_screen.c new file mode 100644 index 0000000..05d0e71 --- /dev/null +++ b/config/boards/shields/nice_view/custom_status_screen.c @@ -0,0 +1,29 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include "widgets/status.h" +#include "custom_status_screen.h" + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_STATUS) +static struct zmk_widget_status status_widget; +#endif + +lv_obj_t *zmk_display_status_screen() { + + lv_obj_t *screen; + screen = lv_obj_create(NULL); + +#if IS_ENABLED(CONFIG_CUSTOM_WIDGET_STATUS) + zmk_widget_status_init(&status_widget, screen); + lv_obj_align(zmk_widget_status_obj(&status_widget), LV_ALIGN_TOP_LEFT, 0, 0); +#endif + + return screen; +} diff --git a/config/boards/shields/nice_view/custom_status_screen.h b/config/boards/shields/nice_view/custom_status_screen.h new file mode 100644 index 0000000..ebcb828 --- /dev/null +++ b/config/boards/shields/nice_view/custom_status_screen.h @@ -0,0 +1,12 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include + +lv_obj_t *zmk_display_status_screen(); diff --git a/config/boards/shields/nice_view/nice_view.conf b/config/boards/shields/nice_view/nice_view.conf new file mode 100644 index 0000000..8037a56 --- /dev/null +++ b/config/boards/shields/nice_view/nice_view.conf @@ -0,0 +1,9 @@ +# Enable nice!view +CONFIG_ZMK_DISPLAY=y + +CONFIG_ZMK_WIDGET_BATTERY_STATUS=n +CONFIG_ZMK_WIDGET_OUTPUT_STATUS=n +CONFIG_ZMK_WIDGET_LAYER_STATUS=n +CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS=n +CONFIG_LV_USE_THEME_MONO=n +CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y \ No newline at end of file diff --git a/config/boards/shields/nice_view/nice_view.overlay b/config/boards/shields/nice_view/nice_view.overlay new file mode 100644 index 0000000..49ce0f2 --- /dev/null +++ b/config/boards/shields/nice_view/nice_view.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +&nice_view_spi { + status = "okay"; + nice_view: ls0xx@0 { + compatible = "sharp,ls0xx"; + label = "DISPLAY"; + spi-max-frequency = <1000000>; + reg = <0>; + width = <160>; + height = <68>; + }; +}; + +/ { + chosen { + zephyr,display = &nice_view; + }; +}; diff --git a/config/boards/shields/nice_view/nice_view.zmk.yml b/config/boards/shields/nice_view/nice_view.zmk.yml new file mode 100644 index 0000000..04b98a8 --- /dev/null +++ b/config/boards/shields/nice_view/nice_view.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: nice_view +name: nice!view +type: shield +url: https://nicekeyboards.com/nice-view +requires: [nice_view_header] +features: + - display diff --git a/config/boards/shields/nice_view/widgets/art.c b/config/boards/shields/nice_view/widgets/art.c new file mode 100644 index 0000000..f5ba129 --- /dev/null +++ b/config/boards/shields/nice_view/widgets/art.c @@ -0,0 +1,423 @@ +/* + * + * Copyright (c) 2023 Collin Hodge + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_VIP_JUSTIN +#define LV_ATTRIBUTE_IMG_VIP_JUSTIN +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST + LV_ATTRIBUTE_IMG_VIP_JUSTIN uint8_t vip_justin_map[] = { +#if CONFIG_CUSTOM_WIDGET_INVERTED + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ +#else + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ +#endif + + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xef, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xef, 0xf7, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xfe, 0x70, 0x00, 0x1f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf7, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xfe, 0x70, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xfe, 0x70, 0x00, 0xcf, 0xff, 0xff, + 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0x7f, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x3f, 0xff, 0xcf, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0x80, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf3, 0xfe, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe7, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0xfe, 0x7f, 0xff, 0xff, + 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe7, 0x00, 0x7f, 0xff, 0xff, 0xf1, 0xf8, 0xff, 0xff, 0xff, 0xef, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0x03, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe3, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe1, 0xfe, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0x03, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe7, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd7, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0xfe, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0xc7, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0x00, 0x02, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xf3, 0x1c, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x03, 0x77, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0x3e, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe6, 0x7e, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd7, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe6, 0x76, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe6, 0x76, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0xe6, 0x7f, 0xff, 0xf0, + 0x3f, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe3, 0xee, 0x7f, 0xff, 0xf2, 0x9f, 0xff, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf1, 0xc0, 0x7f, 0xff, 0xfe, + 0xaf, 0xe0, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xf8, 0x06, 0x7f, 0xff, 0xfe, 0xa7, 0xcb, 0x7e, 0xfe, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf0, 0x06, 0x1f, 0xff, 0xfe, + 0xa3, 0x8b, 0xfe, 0xfe, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xf3, 0xff, 0x9f, 0xff, 0xfe, 0xa9, 0xab, 0xfe, 0xfe, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0xff, 0x9f, 0xff, 0xff, + 0xf8, 0x3f, 0xff, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe7, 0xff, 0x9f, 0xff, 0xff, 0xfe, 0x7f, 0x7f, 0x81, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0x06, 0x1f, 0xff, 0xfe, + 0xaa, 0x2b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe7, 0x06, 0x7f, 0xff, 0xfe, 0xa8, 0x8b, 0x7f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf3, 0x06, 0x1f, 0xff, 0xf2, + 0xa1, 0xcb, 0x7c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xfc, 0x0f, 0xe0, 0x7c, 0x1f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0xfe, 0x47, 0xff, 0xff, + 0xff, 0xfe, 0x79, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xff, 0xff, 0xfe, 0x79, 0xdf, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0xfe, 0x47, 0xff, 0xff, + 0xff, 0xff, 0x33, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe7, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0xfc, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe7, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0xfe, 0x7f, 0xff, 0xff, + 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xf0, 0x06, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf0, 0x06, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe0, 0x06, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0xfe, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xf7, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe7, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, +}; + +const lv_img_dsc_t vip_justin = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 140, + .header.h = 68, + .data_size = 1232, + .data = vip_justin_map, +}; + +#ifndef LV_ATTRIBUTE_IMG_CAT_BOTH_DOWN +#define LV_ATTRIBUTE_IMG_CAT_BOTH_DOWN +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST + LV_ATTRIBUTE_IMG_CAT_BOTH_DOWN uint8_t cat_both_down_map[] = { +#if CONFIG_CUSTOM_WIDGET_INVERTED + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ +#else + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ +#endif + // 'Cat Both Down', 68x42px + 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xe6, 0x7f, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xce, 0x3f, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0x9f, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfc, + 0x3f, 0x87, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xf0, 0xff, 0xc0, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xc7, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0x9f, 0xff, 0xff, 0x87, 0xff, 0xff, 0xf0, 0xff, 0xff, 0x3f, + 0xff, 0xff, 0xe1, 0xff, 0xff, 0xf0, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xf8, + 0x7f, 0x9f, 0xf0, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfe, 0x1c, 0x1f, 0xf0, + 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x80, 0xdf, 0xf0, 0xff, 0xe7, 0xff, + 0xff, 0xff, 0xff, 0xe3, 0xdf, 0xf0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xdf, 0xf0, 0xff, 0x9f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, + 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xfe, 0x7f, 0xf8, + 0xdf, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xfc, 0xff, 0xff, 0x83, 0xff, 0xff, + 0xff, 0x3f, 0xf0, 0x01, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0x3f, 0xf0, + 0x81, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0x3f, 0xf0, 0xf3, 0xff, 0xff, + 0xff, 0xfe, 0x7f, 0xff, 0x3f, 0xf0, 0xf3, 0xff, 0xff, 0xff, 0xfc, 0x7f, + 0xff, 0x3f, 0xf0, 0xf3, 0xfe, 0x07, 0xff, 0xfe, 0x7f, 0xff, 0x3f, 0xf0, + 0x91, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0x18, 0x03, 0xfe, + 0x07, 0xff, 0xff, 0xff, 0xdf, 0xf0, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, + 0xff, 0xcf, 0xf0, 0xcf, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xef, 0xf0, + 0xff, 0x7f, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xe7, 0xf0, 0xff, 0x7f, 0xff, + 0xff, 0xfc, 0xff, 0xff, 0xf7, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, + 0xff, 0xf3, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x83, 0xf3, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x78, 0x10, 0x03, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xe7, 0x00, 0xff, 0x01, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, + 0xff, 0xf8, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xe7, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xfd, 0xf3, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0}; + +const lv_img_dsc_t cat_both_down = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 68, + .header.h = 42, + .data_size = 401, + .data = cat_both_down_map, +}; + +#ifndef LV_ATTRIBUTE_IMG_CAT_BOTH_UP +#define LV_ATTRIBUTE_IMG_CAT_BOTH_UP +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST + LV_ATTRIBUTE_IMG_CAT_BOTH_UP uint8_t cat_both_up_map[] = { +#if CONFIG_CUSTOM_WIDGET_INVERTED + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ +#else + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ +#endif + // 'Cat both up', 68x42px + 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xe6, 0x7f, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xce, 0x3f, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0x9f, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfc, + 0x3f, 0x87, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xf0, 0xff, 0xc0, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xc7, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0x9f, 0xff, 0xff, 0x87, 0xff, 0xff, 0xf0, 0xff, 0xff, 0x3f, + 0xff, 0xff, 0xe1, 0xff, 0xff, 0xf0, 0xfe, 0x0c, 0x7f, 0xff, 0xff, 0xf8, + 0x7f, 0x9f, 0xf0, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x1c, 0x1f, 0xf0, + 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x80, 0xdf, 0xf0, 0xf9, 0xfb, 0xff, + 0xff, 0xff, 0xff, 0xe3, 0xdf, 0xf0, 0xfb, 0xf9, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xdf, 0xf0, 0xfb, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, + 0xfb, 0xbf, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xfb, 0xff, 0xf8, + 0xdf, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xfb, 0xff, 0xff, 0x83, 0xff, 0xf9, + 0xff, 0x3f, 0xf0, 0x01, 0xff, 0xff, 0xc0, 0x7f, 0xe0, 0x3f, 0x3f, 0xf0, + 0x80, 0x7f, 0xff, 0xfc, 0x7f, 0xc7, 0x3f, 0x3f, 0xf0, 0xfc, 0x0f, 0xff, + 0xff, 0xfe, 0x4b, 0x9f, 0x3f, 0xf0, 0xff, 0xc0, 0x7f, 0xff, 0xfc, 0x4f, + 0xcf, 0x3f, 0xf0, 0xff, 0xfc, 0x03, 0xff, 0xfe, 0x4f, 0xef, 0x3f, 0xf0, + 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xdd, 0xff, 0x9f, 0xf0, 0xff, 0xff, 0xff, + 0x07, 0xff, 0xdd, 0xff, 0xdf, 0xf0, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xdf, + 0xff, 0xcf, 0xf0, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xcf, 0xff, 0xef, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xe7, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x81, 0xff, 0xf7, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x1f, 0xf3, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xf3, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x80, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0}; + +const lv_img_dsc_t cat_both_up = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 68, + .header.h = 42, + .data_size = 401, + .data = cat_both_up_map, +}; +#ifndef LV_ATTRIBUTE_IMG_CAT_SLAP_LEFT +#define LV_ATTRIBUTE_IMG_CAT_SLAP_LEFT +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST + LV_ATTRIBUTE_IMG_CAT_SLAP_LEFT uint8_t cat_slap_left_map[] = { +#if CONFIG_CUSTOM_WIDGET_INVERTED + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ +#else + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ +#endif + // 'Cat Slap Left', 68x42px + 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xe6, 0x7f, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xce, 0x3f, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0x9f, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfc, + 0x3f, 0x87, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xf0, 0xff, 0xc0, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xc3, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0x8f, 0xff, 0xff, 0x87, 0xff, 0xff, 0xf0, 0xff, 0xfe, 0x3f, + 0xff, 0xff, 0xe1, 0xff, 0xff, 0xf0, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xf8, + 0x7f, 0x9f, 0xf0, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfe, 0x1c, 0x1f, 0xf0, + 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x80, 0xdf, 0xf0, 0xff, 0xe7, 0xff, + 0xff, 0xff, 0xff, 0xe3, 0xdf, 0xf0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xdf, 0xf0, 0xff, 0x9f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, + 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xfe, 0x7f, 0xf8, + 0xdf, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xfc, 0xff, 0xff, 0x83, 0xff, 0xf8, + 0xff, 0x3f, 0xf0, 0x01, 0xff, 0xff, 0xc0, 0x7f, 0xe0, 0x3f, 0x3f, 0xf0, + 0x81, 0xff, 0xff, 0xfc, 0x7f, 0xc7, 0x3f, 0x3f, 0xf0, 0xf3, 0xff, 0xff, + 0xff, 0xfc, 0x4b, 0x9f, 0x3f, 0xf0, 0xf3, 0xff, 0xff, 0xff, 0xfc, 0x4f, + 0xcf, 0x3f, 0xf0, 0xf3, 0xfe, 0x03, 0xff, 0xfe, 0x4f, 0xef, 0x3f, 0xf0, + 0x81, 0xf0, 0x00, 0x3f, 0xff, 0xcd, 0xff, 0x9f, 0xf0, 0x18, 0x03, 0xfe, + 0x03, 0xff, 0xdd, 0xff, 0xdf, 0xf0, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xcf, + 0xff, 0xcf, 0xf0, 0xcf, 0xff, 0xff, 0xfe, 0x01, 0xcf, 0xff, 0xef, 0xf0, + 0xdf, 0x7f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xe7, 0xf0, 0xff, 0x7f, 0xff, + 0xff, 0xff, 0x81, 0xff, 0xf7, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x1f, 0xf3, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xf3, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x03, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0}; + +const lv_img_dsc_t cat_slap_left = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 68, + .header.h = 42, + .data_size = 401, + .data = cat_slap_left_map, +}; +#ifndef LV_ATTRIBUTE_IMG_CAT_SLAP_RIGHT +#define LV_ATTRIBUTE_IMG_CAT_SLAP_RIGHT +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST + LV_ATTRIBUTE_IMG_CAT_SLAP_RIGHT uint8_t cat_slap_right_map[] = { +#if CONFIG_CUSTOM_WIDGET_INVERTED + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ +#else + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ +#endif + // 'Cat Slap Right', 68x42px + 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xe6, 0x7f, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xce, 0x3f, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0x9f, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfc, + 0x3f, 0x87, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xf0, 0xff, 0xc0, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xc7, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0x9f, 0xff, 0xff, 0x87, 0xff, 0xff, 0xf0, 0xff, 0xff, 0x3f, + 0xff, 0xff, 0xe1, 0xff, 0xff, 0xf0, 0xfe, 0x0c, 0x7f, 0xff, 0xff, 0xf8, + 0x7f, 0x9f, 0xf0, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x1c, 0x1f, 0xf0, + 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x80, 0xdf, 0xf0, 0xf9, 0xfb, 0xff, + 0xff, 0xff, 0xff, 0xe3, 0xdf, 0xf0, 0xfb, 0xf9, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xdf, 0xf0, 0xfb, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, + 0xfb, 0xbf, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xfb, 0xff, 0xf8, + 0xdf, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xfb, 0xff, 0xff, 0x83, 0xff, 0xff, + 0xff, 0x3f, 0xf0, 0x01, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0x3f, 0xf0, + 0x80, 0x7f, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0x3f, 0xf0, 0xfc, 0x0f, 0xff, + 0xff, 0xfe, 0x7f, 0xff, 0x3f, 0xf0, 0xff, 0xc0, 0x7f, 0xff, 0xfc, 0x7f, + 0xff, 0x3f, 0xf0, 0xff, 0xfc, 0x03, 0xff, 0xfe, 0x7f, 0xff, 0x3f, 0xf0, + 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xff, 0xff, 0xff, + 0x07, 0xff, 0xff, 0xff, 0xdf, 0xf0, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, + 0xff, 0xcf, 0xf0, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xef, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xe7, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0xff, 0xff, 0xf7, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, + 0xff, 0xf3, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0x83, 0xf3, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x78, 0x10, 0x03, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xe7, 0x00, 0xff, 0x80, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, + 0xff, 0xf8, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xe7, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xfd, 0xf3, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0}; + +const lv_img_dsc_t cat_slap_right = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 68, + .header.h = 42, + .data_size = 401, + .data = cat_slap_right_map, +}; +#ifndef LV_ATTRIBUTE_IMG_CAT_IDLE +#define LV_ATTRIBUTE_IMG_CAT_IDLE +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_CAT_IDLE + uint8_t cat_idle_map[] = { +#if CONFIG_CUSTOM_WIDGET_INVERTED + 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ +#else + 0x00, 0x00, 0x00, 0xff, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ +#endif + // 'Cat Idle', 42x68px + 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xe6, 0x7f, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xce, 0x3f, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0x9f, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfc, + 0x3f, 0x87, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xf0, 0xff, 0xc0, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xc7, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0x9f, 0xff, 0xff, 0x87, 0xff, 0xff, 0xf0, 0xff, 0xff, 0x3f, + 0xff, 0xff, 0xe1, 0xff, 0xff, 0xf0, 0xfe, 0x0c, 0x7f, 0xff, 0xff, 0xf8, + 0x7f, 0x9f, 0xf0, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x1c, 0x1f, 0xf0, + 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x80, 0xdf, 0xf0, 0xf9, 0xfb, 0xff, + 0xff, 0xff, 0xff, 0xe3, 0xdf, 0xf0, 0xfb, 0xf9, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xdf, 0xf0, 0xfb, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, + 0xfb, 0xbf, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xfb, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf0, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xf9, + 0xff, 0x3f, 0xf0, 0x01, 0xff, 0xff, 0xe3, 0xff, 0xe0, 0x3f, 0x3f, 0xf0, + 0x80, 0x7f, 0xff, 0xe3, 0xff, 0xc7, 0x3f, 0x3f, 0xf0, 0xfc, 0x0f, 0xff, + 0xe3, 0xfe, 0x4b, 0x9f, 0x3f, 0xf0, 0xff, 0xc0, 0x7f, 0xff, 0xfc, 0x4f, + 0xcf, 0x3f, 0xf0, 0xff, 0xfc, 0x03, 0xff, 0xfe, 0x4f, 0xef, 0x3f, 0xf0, + 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xdd, 0xff, 0x9f, 0xf0, 0xff, 0xff, 0xff, + 0x07, 0xff, 0xdd, 0xff, 0xdf, 0xf0, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xdf, + 0xff, 0xcf, 0xf0, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xcf, 0xff, 0xef, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xe7, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x81, 0xff, 0xf7, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x1f, 0xf3, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xf3, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x80, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0}; + +const lv_img_dsc_t cat_idle = { + .header.cf = LV_IMG_CF_INDEXED_1BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 68, + .header.h = 42, + .data_size = 401, + .data = cat_idle_map, +}; diff --git a/config/boards/shields/nice_view/widgets/bolt.c b/config/boards/shields/nice_view/widgets/bolt.c new file mode 100644 index 0000000..fa37d07 --- /dev/null +++ b/config/boards/shields/nice_view/widgets/bolt.c @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include + +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN +#endif + +#ifndef LV_ATTRIBUTE_IMG_BOLT +#define LV_ATTRIBUTE_IMG_BOLT +#endif + +const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_BOLT uint8_t bolt_map[] = { +#if CONFIG_CUSTOM_WIDGET_INVERTED + 0x00, 0x00, 0x00, 0x00, /*Color of index 0*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 2*/ + 0x00, 0x00, 0x00, 0x00, /*Color of index 3*/ +#else + 0x00, 0x00, 0x00, 0x00, /*Color of index 0*/ + 0xff, 0xff, 0xff, 0xff, /*Color of index 1*/ + 0x00, 0x00, 0x00, 0xff, /*Color of index 2*/ + 0x00, 0x00, 0x00, 0x00, /*Color of index 3*/ +#endif + + 0x00, 0x14, 0x00, 0x00, 0x64, 0x00, 0x00, 0x64, 0x00, 0x01, 0xa4, 0x00, 0x01, 0xa4, + 0x00, 0x06, 0xa4, 0x00, 0x06, 0xa4, 0x00, 0x1a, 0xa5, 0x54, 0x1a, 0xaa, 0xa4, 0x6a, + 0xaa, 0x90, 0x55, 0x6a, 0x90, 0x00, 0x6a, 0x40, 0x00, 0x6a, 0x40, 0x00, 0x69, 0x00, + 0x00, 0x69, 0x00, 0x00, 0x64, 0x00, 0x00, 0x64, 0x00, 0x00, 0x50, 0x00, +}; + +const lv_img_dsc_t bolt = { + .header.cf = LV_IMG_CF_INDEXED_2BIT, + .header.always_zero = 0, + .header.reserved = 0, + .header.w = 11, + .header.h = 18, + .data_size = 70, + .data = bolt_map, +}; diff --git a/config/boards/shields/nice_view/widgets/peripheral_status.c b/config/boards/shields/nice_view/widgets/peripheral_status.c new file mode 100644 index 0000000..89f2e14 --- /dev/null +++ b/config/boards/shields/nice_view/widgets/peripheral_status.c @@ -0,0 +1,139 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include "peripheral_status.h" +#include +#include +#include +#include +#include +#include +#include +#include + +LV_IMG_DECLARE(vip_justin); + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +struct peripheral_status_state { + bool connected; +}; + +static void draw_top(lv_obj_t *widget, lv_color_t cbuf[], + struct status_state state) { + lv_obj_t *canvas = lv_obj_get_child(widget, 0); + + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_16, + LV_TEXT_ALIGN_RIGHT); + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, DISP_WIDTH, BATTERY_HEIGHT, + &rect_black_dsc); + + // Draw battery + draw_battery(canvas, state); + + // Draw output status + lv_canvas_draw_text(canvas, 0, 0, DISP_WIDTH, &label_dsc, + state.connected ? LV_SYMBOL_WIFI : LV_SYMBOL_CLOSE); + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void set_battery_status(struct zmk_widget_status *widget, + struct battery_status_state state) { +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + widget->state.charging = state.usb_present; +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + widget->state.battery = state.level; + + draw_top(widget->obj, widget->cbuf, widget->state); +} + +static void battery_status_update_cb(struct battery_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { + set_battery_status(widget, state); + } +} + +static struct battery_status_state +battery_status_get_state(const zmk_event_t *eh) { + return (struct battery_status_state) { + .level = bt_bas_get_battery_level(), +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + .usb_present = zmk_usb_is_powered(), +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, + battery_status_update_cb, battery_status_get_state) + +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + +static struct peripheral_status_state get_state(const zmk_event_t *_eh) { + return (struct peripheral_status_state){ + .connected = zmk_split_bt_peripheral_is_connected()}; +} + +static void set_connection_status(struct zmk_widget_status *widget, + struct peripheral_status_state state) { + widget->state.connected = state.connected; + + draw_top(widget->obj, widget->cbuf, widget->state); +} + +static void output_status_update_cb(struct peripheral_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { + set_connection_status(widget, state); + } +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_peripheral_status, + struct peripheral_status_state, + output_status_update_cb, get_state) +ZMK_SUBSCRIPTION(widget_peripheral_status, zmk_split_peripheral_status_changed); + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent) { + widget->obj = lv_obj_create(parent); + lv_obj_set_size(widget->obj, 160, 68); + lv_obj_t *top = lv_canvas_create(widget->obj); + lv_obj_align(top, LV_ALIGN_TOP_RIGHT, BATTERY_OFFSET, 0); + lv_canvas_set_buffer(top, widget->cbuf, DISP_WIDTH, BATTERY_HEIGHT, + LV_IMG_CF_TRUE_COLOR); + + lv_obj_t *art = lv_img_create(widget->obj); + lv_img_set_src(art, &vip_justin); + lv_obj_align(art, LV_ALIGN_TOP_LEFT, 0, 0); + + sys_slist_append(&widgets, &widget->node); + widget_battery_status_init(); + widget_peripheral_status_init(); + + return 0; +} + +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget) { + return widget->obj; +} diff --git a/config/boards/shields/nice_view/widgets/peripheral_status.h b/config/boards/shields/nice_view/widgets/peripheral_status.h new file mode 100644 index 0000000..1db1e02 --- /dev/null +++ b/config/boards/shields/nice_view/widgets/peripheral_status.h @@ -0,0 +1,22 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include +#include +#include "util.h" + +struct zmk_widget_status { + sys_snode_t node; + lv_obj_t *obj; + lv_color_t cbuf[DISP_WIDTH * BATTERY_HEIGHT]; + struct status_state state; +}; + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget); diff --git a/config/boards/shields/nice_view/widgets/status.c b/config/boards/shields/nice_view/widgets/status.c new file mode 100644 index 0000000..77008e7 --- /dev/null +++ b/config/boards/shields/nice_view/widgets/status.c @@ -0,0 +1,421 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include "status.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets); + +// Cat Animation Frames +LV_IMG_DECLARE(cat_idle) +LV_IMG_DECLARE(cat_slap_left) +LV_IMG_DECLARE(cat_slap_right) +LV_IMG_DECLARE(cat_both_up) +LV_IMG_DECLARE(cat_both_down) + +const lv_img_dsc_t *cats_imgs[5] = {&cat_idle, &cat_slap_left, &cat_slap_right, &cat_both_up, + &cat_both_down}; +struct output_status_state { + enum zmk_endpoint selected_endpoint; + bool active_profile_connected; + bool active_profile_bonded; + uint8_t active_profile_index; +}; + +struct layer_status_state { + uint8_t index; + const char *label; +}; + +struct wpm_status_state { + uint8_t wpm; +}; + +struct mods_status_state { + uint8_t mods; +}; + +static uint8_t frame; +static void draw_battery_status(lv_obj_t *widget, lv_color_t cbuf[], struct status_state state) { + lv_obj_t *canvas = lv_obj_get_child(widget, BATTERY_IDX); + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_16, LV_TEXT_ALIGN_RIGHT); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, DISP_WIDTH, BATTERY_HEIGHT, &rect_black_dsc); + + // Draw battery + draw_battery(canvas, state); + + // Draw output status + char output_text[10] = {}; + + switch (state.selected_endpoint) { + case ZMK_ENDPOINT_USB: + strcat(output_text, LV_SYMBOL_USB); + break; + case ZMK_ENDPOINT_BLE: + if (state.active_profile_bonded) { + if (state.active_profile_connected) { + strcat(output_text, LV_SYMBOL_WIFI); + } else { + strcat(output_text, LV_SYMBOL_CLOSE); + } + } else { + strcat(output_text, LV_SYMBOL_SETTINGS); + } + break; + } + lv_canvas_draw_text(canvas, 0, 0, DISP_WIDTH, &label_dsc, output_text); + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} +static void draw_wpm(lv_obj_t *widget, lv_color_t cbuf[], struct status_state state) { + lv_obj_t *canvas = lv_obj_get_child(widget, WPM_IDX); + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_14, LV_TEXT_ALIGN_CENTER); + lv_draw_img_dsc_t img_dsc; + lv_draw_img_dsc_init(&img_dsc); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, DISP_WIDTH, WPM_HEIGHT, &rect_black_dsc); + + // Draw WPM + uint8_t wpm = state.wpm; + if (wpm == 0) { + lv_canvas_draw_img(canvas, 0, 0, cats_imgs[0], &img_dsc); + } else if (wpm < 40) { + switch (frame++ & 0x3) { + case 0: + lv_canvas_draw_img(canvas, 0, 0, &cat_slap_left, &img_dsc); + break; + case 2: + lv_canvas_draw_img(canvas, 0, 0, &cat_slap_right, &img_dsc); + break; + default: + lv_canvas_draw_img(canvas, 0, 0, &cat_both_up, &img_dsc); + } + } else if (wpm < 80) { + if (frame++ & 0x1) { + lv_canvas_draw_img(canvas, 0, 0, cats_imgs[1], &img_dsc); + } else { + lv_canvas_draw_img(canvas, 0, 0, cats_imgs[2], &img_dsc); + } + } else { + if (frame++ & 0x1) { + lv_canvas_draw_img(canvas, 0, 0, cats_imgs[3], &img_dsc); + } else { + lv_canvas_draw_img(canvas, 0, 0, cats_imgs[4], &img_dsc); + } + } + char wpm_text[6] = {}; + snprintf(wpm_text, sizeof(wpm_text), "%d", state.wpm); + lv_canvas_draw_text(canvas, -4, 28, 50, &label_dsc, wpm_text); + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} +static void draw_bt_prof(lv_obj_t *widget, lv_color_t cbuf[], struct status_state state) { + lv_obj_t *canvas = lv_obj_get_child(widget, BT_PROF_IDX); + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + + lv_draw_arc_dsc_t arc_dsc; + init_arc_dsc(&arc_dsc, LVGL_FOREGROUND, 2); + lv_draw_arc_dsc_t arc_dsc_filled; + init_arc_dsc(&arc_dsc_filled, LVGL_FOREGROUND, 9); + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_montserrat_14, LV_TEXT_ALIGN_CENTER); + lv_draw_label_dsc_t label_dsc_black; + init_label_dsc(&label_dsc_black, LVGL_BACKGROUND, &lv_font_montserrat_14, LV_TEXT_ALIGN_CENTER); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, DISP_WIDTH, BT_PROF_HEIGHT, &rect_black_dsc); + + // Draw circles + int circle_offsets[3][2] = {{11, 11}, {34, 11}, {57, 11}}; + + for (int i = 0; i < 3; i++) { + bool selected = state.active_profile_index == i; + + lv_canvas_draw_arc(canvas, circle_offsets[i][0], circle_offsets[i][1], 11, 0, 359, + &arc_dsc); + + if (selected) { + lv_canvas_draw_arc(canvas, circle_offsets[i][0], circle_offsets[i][1], 7, 0, 359, + &arc_dsc_filled); + } + + // Writing the bt profile label + char label[2]; + label[0] = 0x31 + i; + label[1] = '\0'; + lv_canvas_draw_text(canvas, circle_offsets[i][0] - 7, circle_offsets[i][1] - 8, 14, + (selected ? &label_dsc_black : &label_dsc), label); + } + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void draw_mods(lv_obj_t *widget, lv_color_t cbuf[], struct status_state state) { + lv_obj_t *canvas = lv_obj_get_child(widget, MODS_IDX); + + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_rect_dsc_t rect_white_dsc; + init_rect_dsc(&rect_white_dsc, LVGL_FOREGROUND); + lv_draw_label_dsc_t mod_dsc; + init_label_dsc(&mod_dsc, LVGL_FOREGROUND, &lv_font_unscii_8, LV_TEXT_ALIGN_CENTER); + lv_draw_label_dsc_t mod_dsc_black; + init_label_dsc(&mod_dsc_black, LVGL_BACKGROUND, &lv_font_unscii_8, LV_TEXT_ALIGN_CENTER); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, DISP_WIDTH, MODS_HEIGHT, &rect_black_dsc); + + // Mod Labels + char names[4][4] = {"CTL", "SFT", "ALT", "CMD"}; + + // Drawing Mod Boxes + int mod_offsets[4][2] = {{2, 2}, {35, 2}, {2, 22}, {35, 22}}; + lv_canvas_draw_rect(canvas, 0, 0, DISP_WIDTH, 42, &rect_white_dsc); + for (int i = 0; i < 4; i++) { + bool selected = (state.mod_state >> i) & 0x11; + lv_canvas_draw_rect(canvas, mod_offsets[i][0], mod_offsets[i][1], 31, 18, &rect_black_dsc); + if (selected) + lv_canvas_draw_rect(canvas, mod_offsets[i][0] + 2, mod_offsets[i][1] + 2, 27, 14, + &rect_white_dsc); + lv_canvas_draw_text(canvas, mod_offsets[i][0], mod_offsets[i][1] + 4, 32, + (selected ? &mod_dsc_black : &mod_dsc), names[i]); + } + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} + +static void draw_layer(lv_obj_t *widget, lv_color_t cbuf[], struct status_state state) { + lv_obj_t *canvas = lv_obj_get_child(widget, LAYER_IDX); + + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_label_dsc_t label_dsc; + init_label_dsc(&label_dsc, LVGL_FOREGROUND, &lv_font_unscii_16, LV_TEXT_ALIGN_CENTER); + + // Fill background + lv_canvas_draw_rect(canvas, 0, 0, DISP_WIDTH, LAYER_HEIGHT, &rect_black_dsc); + + // Draw layer + if (state.layer_label == NULL) { + char text[9] = {}; + + sprintf(text, "LAYER %i", state.layer_index); + + lv_canvas_draw_text(canvas, 0, 5, 68, &label_dsc, text); + } else { + lv_canvas_draw_text(canvas, 0, 5, 68, &label_dsc, state.layer_label); + } + + // Rotate canvas + rotate_canvas(canvas, cbuf); +} +struct mods_status_state mods_status_get_state(const zmk_event_t *eh) { + // Intentionally useless + return (struct mods_status_state){.mods = 0}; +}; + +void set_mods_state(struct zmk_widget_status *widget, struct mods_status_state state) { + // Had to make call here since status_get_state didn't reliably update the mod state + widget->state.mod_state = zmk_hid_get_explicit_mods(); + draw_mods(widget->obj, widget->mods_buf, widget->state); +} + +void mods_status_update_cb(struct mods_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_mods_state(widget, state); } +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_mods_status, struct mods_status_state, mods_status_update_cb, + mods_status_get_state) +ZMK_SUBSCRIPTION(widget_mods_status, zmk_keycode_state_changed); + +static void set_battery_status(struct zmk_widget_status *widget, + struct battery_status_state state) { +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + widget->state.charging = state.usb_present; +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + + widget->state.battery = state.level; + + draw_battery_status(widget->obj, widget->battery_buf, widget->state); +} + +static void battery_status_update_cb(struct battery_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_battery_status(widget, state); } +} + +static struct battery_status_state battery_status_get_state(const zmk_event_t *eh) { + return (struct battery_status_state) { + .level = bt_bas_get_battery_level(), +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + .usb_present = zmk_usb_is_powered(), +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + }; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_battery_status, struct battery_status_state, + battery_status_update_cb, battery_status_get_state) + +ZMK_SUBSCRIPTION(widget_battery_status, zmk_battery_state_changed); +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed); +#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK) */ + +static void set_output_status(struct zmk_widget_status *widget, struct output_status_state state) { + widget->state.selected_endpoint = state.selected_endpoint; + widget->state.active_profile_connected = state.active_profile_connected; + widget->state.active_profile_bonded = state.active_profile_bonded; + widget->state.active_profile_index = state.active_profile_index; + + draw_battery_status(widget->obj, widget->battery_buf, widget->state); + draw_bt_prof(widget->obj, widget->bt_prof_buf, widget->state); +} + +static void output_status_update_cb(struct output_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_output_status(widget, state); } +} + +static struct output_status_state output_status_get_state(const zmk_event_t *_eh) { + return (struct output_status_state){.selected_endpoint = zmk_endpoints_selected(), + .active_profile_connected = + zmk_ble_active_profile_is_connected(), + .active_profile_bonded = !zmk_ble_active_profile_is_open(), + .active_profile_index = zmk_ble_active_profile_index()}; + ; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_output_status, struct output_status_state, + output_status_update_cb, output_status_get_state) +ZMK_SUBSCRIPTION(widget_output_status, zmk_endpoint_selection_changed); + +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) +ZMK_SUBSCRIPTION(widget_output_status, zmk_usb_conn_state_changed); +#endif +#if defined(CONFIG_ZMK_BLE) +ZMK_SUBSCRIPTION(widget_output_status, zmk_ble_active_profile_changed); +#endif + +static void set_layer_status(struct zmk_widget_status *widget, struct layer_status_state state) { + widget->state.layer_index = state.index; + widget->state.layer_label = state.label; + + draw_layer(widget->obj, widget->layer_buf, widget->state); +} + +static void layer_status_update_cb(struct layer_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_layer_status(widget, state); } +} + +static struct layer_status_state layer_status_get_state(const zmk_event_t *eh) { + uint8_t index = zmk_keymap_highest_layer_active(); + return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_label(index)}; +} + +ZMK_DISPLAY_WIDGET_LISTENER(widget_layer_status, struct layer_status_state, layer_status_update_cb, + layer_status_get_state) + +ZMK_SUBSCRIPTION(widget_layer_status, zmk_layer_state_changed); + +static void set_wpm_status(struct zmk_widget_status *widget, struct wpm_status_state state) { + widget->state.wpm = state.wpm; + draw_wpm(widget->obj, widget->wpm_buf, widget->state); +} + +static void wpm_status_update_cb(struct wpm_status_state state) { + struct zmk_widget_status *widget; + SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_wpm_status(widget, state); } +} + +struct wpm_status_state wpm_status_get_state(const zmk_event_t *eh) { + return (struct wpm_status_state){.wpm = zmk_wpm_get_state()}; +}; + +ZMK_DISPLAY_WIDGET_LISTENER(widget_wpm_status, struct wpm_status_state, wpm_status_update_cb, + wpm_status_get_state) +ZMK_SUBSCRIPTION(widget_wpm_status, zmk_wpm_state_changed); + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent) { + widget->obj = lv_obj_create(parent); + lv_obj_set_size(widget->obj, 160, 68); + + // Bar for battery and output indication + lv_obj_t *battery_area = lv_canvas_create(widget->obj); + lv_obj_align(battery_area, LV_ALIGN_TOP_RIGHT, BATTERY_OFFSET, 0); + lv_canvas_set_buffer(battery_area, widget->battery_buf, DISP_WIDTH, BATTERY_HEIGHT, + LV_IMG_CF_TRUE_COLOR); + + // WPM Widget area + lv_obj_t *wpm_area = lv_canvas_create(widget->obj); + lv_obj_align(wpm_area, LV_ALIGN_TOP_RIGHT, WPM_OFFSET, 0); + lv_canvas_set_buffer(wpm_area, widget->wpm_buf, DISP_WIDTH, WPM_HEIGHT, LV_IMG_CF_TRUE_COLOR); + + // BT Profile area + lv_obj_t *bt_prof_area = lv_canvas_create(widget->obj); + lv_obj_align(bt_prof_area, LV_ALIGN_TOP_RIGHT, BT_PROF_OFFSET, 0); + lv_canvas_set_buffer(bt_prof_area, widget->bt_prof_buf, DISP_WIDTH, BT_PROF_HEIGHT, + LV_IMG_CF_TRUE_COLOR); + + // Modifier Status Area + lv_obj_t *mods_area = lv_canvas_create(widget->obj); + lv_obj_align(mods_area, LV_ALIGN_TOP_RIGHT, MODS_OFFSET, 0); + lv_canvas_set_buffer(mods_area, widget->mods_buf, DISP_WIDTH, MODS_HEIGHT, + LV_IMG_CF_TRUE_COLOR); + // Layer Area + lv_obj_t *layer_area = lv_canvas_create(widget->obj); + lv_obj_align(layer_area, LV_ALIGN_TOP_RIGHT, LAYER_OFFSET, 0); + lv_canvas_set_buffer(layer_area, widget->layer_buf, DISP_WIDTH, LAYER_HEIGHT, + LV_IMG_CF_TRUE_COLOR); + sys_slist_append(&widgets, &widget->node); + widget_battery_status_init(); + widget_wpm_status_init(); + widget_output_status_init(); + widget_mods_status_init(); + widget_layer_status_init(); + + frame = 0; + return 0; +} + +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget) { return widget->obj; } diff --git a/config/boards/shields/nice_view/widgets/status.h b/config/boards/shields/nice_view/widgets/status.h new file mode 100644 index 0000000..ae52cb6 --- /dev/null +++ b/config/boards/shields/nice_view/widgets/status.h @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include +#include +#include "util.h" + +struct zmk_widget_status { + sys_snode_t node; + lv_obj_t *obj; + lv_color_t battery_buf[DISP_WIDTH * BATTERY_HEIGHT]; + lv_color_t wpm_buf[DISP_WIDTH * WPM_HEIGHT]; + lv_color_t bt_prof_buf[DISP_WIDTH * MODS_HEIGHT]; + lv_color_t mods_buf[DISP_WIDTH * MODS_HEIGHT]; + lv_color_t layer_buf[DISP_WIDTH * LAYER_HEIGHT]; + struct status_state state; +}; + +int zmk_widget_status_init(struct zmk_widget_status *widget, lv_obj_t *parent); +lv_obj_t *zmk_widget_status_obj(struct zmk_widget_status *widget); diff --git a/config/boards/shields/nice_view/widgets/util.c b/config/boards/shields/nice_view/widgets/util.c new file mode 100644 index 0000000..3b8a283 --- /dev/null +++ b/config/boards/shields/nice_view/widgets/util.c @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include "util.h" + +LV_IMG_DECLARE(bolt); +// static lv_color_t cbuf_tmp[DISP_WIDTH * DISP_WIDTH]; + +void rotate_canvas(lv_obj_t *canvas, lv_color_t cbuf[]) { + lv_img_set_pivot(canvas, 0, 0); + lv_img_set_angle(canvas, 900); +} + +void draw_battery(lv_obj_t *canvas, struct status_state state) { + lv_draw_rect_dsc_t rect_black_dsc; + init_rect_dsc(&rect_black_dsc, LVGL_BACKGROUND); + lv_draw_rect_dsc_t rect_white_dsc; + init_rect_dsc(&rect_white_dsc, LVGL_FOREGROUND); + + lv_canvas_draw_rect(canvas, 0, 2, 29, 12, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 1, 3, 27, 10, &rect_black_dsc); + lv_canvas_draw_rect(canvas, 2, 4, (state.battery + 2) / 4, 8, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 30, 5, 3, 6, &rect_white_dsc); + lv_canvas_draw_rect(canvas, 31, 6, 1, 4, &rect_black_dsc); + + if (state.charging) { + lv_draw_img_dsc_t img_dsc; + lv_draw_img_dsc_init(&img_dsc); + lv_canvas_draw_img(canvas, 9, -1, &bolt, &img_dsc); + } +} + +void init_label_dsc(lv_draw_label_dsc_t *label_dsc, lv_color_t color, const lv_font_t *font, + lv_text_align_t align) { + lv_draw_label_dsc_init(label_dsc); + label_dsc->color = color; + label_dsc->font = font; + label_dsc->align = align; +} + +void init_rect_dsc(lv_draw_rect_dsc_t *rect_dsc, lv_color_t bg_color) { + lv_draw_rect_dsc_init(rect_dsc); + rect_dsc->bg_color = bg_color; +} + +void init_line_dsc(lv_draw_line_dsc_t *line_dsc, lv_color_t color, uint8_t width) { + lv_draw_line_dsc_init(line_dsc); + line_dsc->color = color; + line_dsc->width = width; +} + +void init_arc_dsc(lv_draw_arc_dsc_t *arc_dsc, lv_color_t color, uint8_t width) { + lv_draw_arc_dsc_init(arc_dsc); + arc_dsc->color = color; + arc_dsc->width = width; +} diff --git a/config/boards/shields/nice_view/widgets/util.h b/config/boards/shields/nice_view/widgets/util.h new file mode 100644 index 0000000..8eeeca9 --- /dev/null +++ b/config/boards/shields/nice_view/widgets/util.h @@ -0,0 +1,69 @@ +/* + * + * Copyright (c) 2023 The ZMK Contributors + * SPDX-License-Identifier: MIT + * + */ + +#include +#include + +#define DISP_WIDTH 68 + +#define PADDING 4 +#define BATTERY_HEIGHT 17 +#define BATTERY_IDX 0 +#define BATTERY_OFFSET 68 + +#define WPM_HEIGHT 42 +#define WPM_IDX 1 +#define WPM_OFFSET (-BATTERY_HEIGHT + BATTERY_OFFSET - PADDING) + +#define BT_PROF_HEIGHT 22 +#define BT_PROF_IDX 2 +#define BT_PROF_OFFSET (-WPM_HEIGHT + WPM_OFFSET - PADDING) + +#define MODS_HEIGHT 42 +#define MODS_IDX 3 +#define MODS_OFFSET (-BT_PROF_HEIGHT + BT_PROF_OFFSET - PADDING) + +#define LAYER_HEIGHT 29 +#define LAYER_IDX 4 +#define LAYER_OFFSET (-MODS_HEIGHT + MODS_OFFSET - PADDING) + +#define LVGL_BACKGROUND \ + IS_ENABLED(CONFIG_CUSTOM_WIDGET_INVERTED) ? lv_color_black() : lv_color_white() +#define LVGL_FOREGROUND \ + IS_ENABLED(CONFIG_CUSTOM_WIDGET_INVERTED) ? lv_color_white() : lv_color_black() + +struct status_state { + uint8_t battery; + bool charging; +#if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) + enum zmk_endpoint selected_endpoint; + bool active_profile_connected; + bool active_profile_bonded; + uint8_t active_profile_index; + uint8_t layer_index; + const char *layer_label; + uint8_t wpm; + uint8_t mod_state; +#else + bool connected; +#endif +}; + +struct battery_status_state { + uint8_t level; +#if IS_ENABLED(CONFIG_USB_DEVICE_STACK) + bool usb_present; +#endif +}; + +void rotate_canvas(lv_obj_t *canvas, lv_color_t cbuf[]); +void draw_battery(lv_obj_t *canvas, struct status_state state); +void init_label_dsc(lv_draw_label_dsc_t *label_dsc, lv_color_t color, const lv_font_t *font, + lv_text_align_t align); +void init_rect_dsc(lv_draw_rect_dsc_t *rect_dsc, lv_color_t bg_color); +void init_line_dsc(lv_draw_line_dsc_t *line_dsc, lv_color_t color, uint8_t width); +void init_arc_dsc(lv_draw_arc_dsc_t *arc_dsc, lv_color_t color, uint8_t width);