GUI: Checkerboard overlay behind popup elements (#380)

* GUI: Checkerboard overlay behind popup elements

Adds setting 'Popup Overlay' (default ON) which draws a checkerboard pattern behind popups, like the Archive actions menu, keypad/pin lock modal, and the varitemlist locked message. Gives the illusion of separation from the popup element and the background content and is an aesthetic improvement.

* Refactor

* Update changelog

---------

Co-authored-by: Willy-JL <49810075+Willy-JL@users.noreply.github.com>
This commit is contained in:
Alexander Bays
2025-04-12 21:59:28 -05:00
committed by GitHub
parent 21c9852666
commit 16fb7e44df
10 changed files with 127 additions and 57 deletions

View File

@@ -37,7 +37,9 @@
- Add item count to directory info scene (#378 by @956MB)
- OFW: Pinning of settings options (by @portasynthinca3)
- Clock: 12 hour "midnight format" in Momentum Settings (#341 by @956MB)
- GUI: Add marquee 'Text Scroll' option in Momentum Settings (#363 by @956MB)
- GUI:
- Add marquee 'Text Scroll' option in Momentum Settings (#363 by @956MB)
- Checkerboard overlay behind popup elements, can be disabled in Momentum Settings (#380 by @956MB)
- UL: Input: Vibro on Button press option (by @Dmitry422)
- Desktop:
- UL: Option to prevent Auto Lock when connected to USB/RPC (by @Dmitry422)

View File

@@ -194,9 +194,9 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
const uint8_t calc_height = menu_height - ((MENU_ITEMS - size_menu - 1) * line_height);
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 72, 2, 56, calc_height + 4);
canvas_draw_rbox(canvas, 72, 2, 56, calc_height + 4, 3);
canvas_set_color(canvas, ColorBlack);
elements_slightly_rounded_frame(canvas, 71, 2, 57, calc_height + 4);
canvas_draw_rframe(canvas, 71, 2, 57, calc_height + 4, 3);
canvas_draw_str_aligned(
canvas, 100, 11, AlignCenter, AlignBottom, model->menu_manage ? "Manage:" : "Actions:");
@@ -246,75 +246,93 @@ static void archive_draw_loading(Canvas* canvas, ArchiveBrowserViewModel* model)
canvas_draw_icon(canvas, x, y, &A_Loading_24);
}
static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
furi_assert(model);
static void draw_list_item(
Canvas* canvas,
ArchiveBrowserViewModel* model,
bool scrollbar,
uint32_t i,
int32_t idx) {
size_t array_size = files_array_size(model->files);
bool scrollbar = model->item_cnt > 4;
for(uint32_t i = 0; i < MIN(model->item_cnt, MENU_ITEMS); ++i) {
FuriString* str_buf;
str_buf = furi_string_alloc();
int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->item_cnt, 0u);
uint8_t x_offset = (model->move_fav && model->item_idx == idx) ? MOVE_OFFSET : 0;
FuriString* str_buf;
str_buf = furi_string_alloc();
uint8_t x_offset = (model->move_fav && model->item_idx == idx) ? MOVE_OFFSET : 0;
ArchiveFileTypeEnum file_type = ArchiveFileTypeLoading;
uint8_t* custom_icon_data = NULL;
ArchiveFileTypeEnum file_type = ArchiveFileTypeLoading;
uint8_t* custom_icon_data = NULL;
if(!model->list_loading && archive_is_item_in_array(model, idx)) {
ArchiveFile_t* file = files_array_get(
model->files, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0));
file_type = file->type;
bool ext = model->tab_idx == ArchiveTabBrowser ||
model->tab_idx == ArchiveTabInternal ||
model->tab_idx == ArchiveTabDiskImage || model->tab_idx == ArchiveTabSearch;
if(file_type == ArchiveFileTypeApplication) {
if(file->custom_icon_data) {
custom_icon_data = file->custom_icon_data;
furi_string_set(str_buf, file->custom_name);
} else {
file_type = ArchiveFileTypeUnknown;
path_extract_filename(file->path, str_buf, !ext);
}
if(!model->list_loading && archive_is_item_in_array(model, idx)) {
ArchiveFile_t* file = files_array_get(
model->files, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0));
file_type = file->type;
bool ext = model->tab_idx == ArchiveTabBrowser || model->tab_idx == ArchiveTabInternal ||
model->tab_idx == ArchiveTabDiskImage || model->tab_idx == ArchiveTabSearch;
if(file_type == ArchiveFileTypeApplication) {
if(file->custom_icon_data) {
custom_icon_data = file->custom_icon_data;
furi_string_set(str_buf, file->custom_name);
} else {
file_type = ArchiveFileTypeUnknown;
path_extract_filename(file->path, str_buf, !ext);
}
} else {
furi_string_set(str_buf, "---");
path_extract_filename(file->path, str_buf, !ext);
}
} else {
furi_string_set(str_buf, "---");
}
size_t scroll_counter = model->scroll_counter;
size_t scroll_counter = model->scroll_counter;
if(!model->list_loading && model->item_idx == idx) {
archive_draw_frame(canvas, i, scrollbar, model->move_fav);
if(scroll_counter < SCROLL_DELAY) {
scroll_counter = 0;
} else {
scroll_counter -= SCROLL_DELAY;
}
} else {
canvas_set_color(canvas, ColorBlack);
if(!model->list_loading && model->item_idx == idx) {
archive_draw_frame(canvas, i, scrollbar, model->move_fav);
if(scroll_counter < SCROLL_DELAY) {
scroll_counter = 0;
}
if(custom_icon_data) {
canvas_draw_bitmap(
canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, 11, 10, custom_icon_data);
} else {
canvas_draw_icon(
canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file_type]);
scroll_counter -= SCROLL_DELAY;
}
} else {
canvas_set_color(canvas, ColorBlack);
scroll_counter = 0;
}
elements_scrollable_text_line(
canvas,
15 + x_offset,
24 + i * FRAME_HEIGHT,
((scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX) - x_offset),
str_buf,
scroll_counter,
(model->item_idx != idx));
if(custom_icon_data) {
canvas_draw_bitmap(canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, 11, 10, custom_icon_data);
} else {
canvas_draw_icon(canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file_type]);
}
furi_string_free(str_buf);
elements_scrollable_text_line(
canvas,
15 + x_offset,
24 + i * FRAME_HEIGHT,
((scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX) - x_offset),
str_buf,
scroll_counter,
(model->item_idx != idx));
furi_string_free(str_buf);
}
static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
furi_assert(model);
bool scrollbar = model->item_cnt > 4;
for(uint32_t i = 0; i < MIN(model->item_cnt, MENU_ITEMS); ++i) {
int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->item_cnt, 0u);
if(model->item_idx == idx) continue;
draw_list_item(canvas, model, scrollbar, i, idx);
}
if(momentum_settings.popup_overlay && model->menu) {
canvas_draw_overlay(canvas);
}
for(uint32_t i = 0; i < MIN(model->item_cnt, MENU_ITEMS); ++i) {
int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->item_cnt, 0u);
if(model->item_idx != idx) continue;
draw_list_item(canvas, model, scrollbar, i, idx);
}
if(scrollbar) {
@@ -361,7 +379,7 @@ static void archive_render_status_bar(Canvas* canvas, ArchiveBrowserViewModel* m
9,
45,
model->archive->browser->formatted_path,
model->scroll_counter,
model->menu ? 0 : model->scroll_counter,
false,
true);
}

View File

@@ -26,6 +26,14 @@ static void momentum_app_scene_interface_general_midnight_format_changed(Variabl
app->save_settings = true;
}
static void momentum_app_scene_interface_general_popup_overlay_changed(VariableItem* item) {
MomentumApp* app = variable_item_get_context(item);
bool value = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, value ? "ON" : "OFF");
momentum_settings.popup_overlay = value;
app->save_settings = true;
}
void momentum_app_scene_interface_general_on_enter(void* context) {
MomentumApp* app = context;
VariableItemList* var_item_list = app->var_item_list;
@@ -51,6 +59,15 @@ void momentum_app_scene_interface_general_on_enter(void* context) {
variable_item_set_current_value_text(
item, momentum_settings.midnight_format_00 ? "00:XX" : "12:XX");
item = variable_item_list_add(
var_item_list,
"Popup Overlay",
2,
momentum_app_scene_interface_general_popup_overlay_changed,
app);
variable_item_set_current_value_index(item, momentum_settings.popup_overlay);
variable_item_set_current_value_text(item, momentum_settings.popup_overlay ? "ON" : "OFF");
variable_item_list_set_enter_callback(
var_item_list, momentum_app_scene_interface_general_var_item_list_callback, app);

View File

@@ -167,6 +167,9 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) {
}
if(m->show_lock_popup) {
if(momentum_settings.popup_overlay) {
canvas_draw_overlay(canvas);
}
canvas_set_font(canvas, FontSecondary);
elements_bold_rounded_frame(canvas, 24, 4, 80, 56);
canvas_draw_str_aligned(canvas, 64, 16, AlignCenter, AlignCenter, "Keypad Lock");

View File

@@ -484,6 +484,22 @@ void canvas_draw_dot(Canvas* canvas, int32_t x, int32_t y) {
u8g2_DrawPixel(&canvas->fb, x, y);
}
void canvas_draw_overlay(Canvas* canvas) {
furi_check(canvas);
uint8_t original = canvas->fb.draw_color;
canvas_set_color(canvas, ColorWhite);
for(size_t j = 0; j < canvas->height; j++) {
bool draw_pixel = (j % 2) == 0;
for(size_t i = 0; i < canvas->width; i += 2) {
size_t x = i + (draw_pixel ? 0 : 1);
if(x < canvas->width) {
canvas_draw_dot(canvas, x, j);
}
}
}
canvas->fb.draw_color = original;
}
void canvas_draw_box(Canvas* canvas, int32_t x, int32_t y, size_t width, size_t height) {
furi_check(canvas);
x += canvas->offset_x;

View File

@@ -346,6 +346,12 @@ void canvas_draw_xbm_ex(
*/
void canvas_draw_dot(Canvas* canvas, int32_t x, int32_t y);
/** Draw overlay
*
* @param canvas Canvas instance
*/
void canvas_draw_overlay(Canvas* canvas);
/** Draw box of width, height at x,y
*
* @param canvas Canvas instance

View File

@@ -5,6 +5,7 @@
#include <assets_icons.h>
#include <m-array.h>
#include <stdint.h>
#include <momentum/settings.h>
struct VariableItem {
FuriString* label;
@@ -146,6 +147,9 @@ static void variable_item_list_draw_callback(Canvas* canvas, void* _model) {
elements_scrollbar(canvas, model->position, VariableItemArray_size(model->items));
if(model->locked_message_visible) {
if(momentum_settings.popup_overlay) {
canvas_draw_overlay(canvas);
}
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 8, 10, 110, 48);
canvas_set_color(canvas, ColorBlack);

View File

@@ -37,6 +37,7 @@ MomentumSettings momentum_settings = {
.rgb_backlight = false, // OFF
.butthurt_timer = 21600, // 6 H
.midnight_format_00 = true, // 00:XX
.popup_overlay = true, // ON
.spi_cc1101_handle = SpiDefault, // &furi_hal_spi_bus_handle_external
.spi_nrf24_handle = SpiDefault, // &furi_hal_spi_bus_handle_external
.uart_esp_channel = FuriHalSerialIdUsart, // pin 13,14
@@ -109,6 +110,7 @@ static const struct {
{setting_bool(rgb_backlight)},
{setting_uint(butthurt_timer, 0, 172800)},
{setting_bool(midnight_format_00)},
{setting_bool(popup_overlay)},
{setting_enum(spi_cc1101_handle, SpiCount)},
{setting_enum(spi_nrf24_handle, SpiCount)},
{setting_enum(uart_esp_channel, FuriHalSerialIdMax)},

View File

@@ -94,6 +94,7 @@ typedef struct {
bool rgb_backlight;
uint32_t butthurt_timer;
bool midnight_format_00;
bool popup_overlay;
SpiHandle spi_cc1101_handle;
SpiHandle spi_nrf24_handle;
FuriHalSerialId uart_esp_channel;

View File

@@ -849,6 +849,7 @@ Function,+,canvas_draw_icon_animation,void,"Canvas*, int32_t, int32_t, IconAnima
Function,+,canvas_draw_icon_animation_ex,void,"Canvas*, int32_t, int32_t, int32_t, int32_t, IconAnimation*"
Function,+,canvas_draw_icon_ex,void,"Canvas*, int32_t, int32_t, const Icon*, IconRotation"
Function,+,canvas_draw_line,void,"Canvas*, int32_t, int32_t, int32_t, int32_t"
Function,+,canvas_draw_overlay,void,Canvas*
Function,+,canvas_draw_rbox,void,"Canvas*, int32_t, int32_t, size_t, size_t, size_t"
Function,+,canvas_draw_rframe,void,"Canvas*, int32_t, int32_t, size_t, size_t, size_t"
Function,+,canvas_draw_str,void,"Canvas*, int32_t, int32_t, const char*"
1 entry status name type params
849 Function + canvas_draw_icon_animation_ex void Canvas*, int32_t, int32_t, int32_t, int32_t, IconAnimation*
850 Function + canvas_draw_icon_ex void Canvas*, int32_t, int32_t, const Icon*, IconRotation
851 Function + canvas_draw_line void Canvas*, int32_t, int32_t, int32_t, int32_t
852 Function + canvas_draw_overlay void Canvas*
853 Function + canvas_draw_rbox void Canvas*, int32_t, int32_t, size_t, size_t, size_t
854 Function + canvas_draw_rframe void Canvas*, int32_t, int32_t, size_t, size_t, size_t
855 Function + canvas_draw_str void Canvas*, int32_t, int32_t, const char*