Skip to content

Commit 5c54be4

Browse files
956MBhedger
andauthored
Infrared: Add text scroll to remote buttons (#4210)
* Infrared: Add text scroll to universal remote buttons Replaces center aligned text in the infrared universal remote with scrollable text if wider than the button and is cut off. Allows long descriptive button functions to be seen in some remotes. * linter fixes --------- Co-authored-by: hedger <hedger@users.noreply.github.com> Co-authored-by: hedger <hedger@nanode.su>
1 parent 973fb26 commit 5c54be4

File tree

1 file changed

+88
-28
lines changed

1 file changed

+88
-28
lines changed

applications/services/gui/modules/button_menu.c

Lines changed: 88 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stdint.h>
1111
#include <m-array.h>
1212

13+
#define SCROLL_INTERVAL (333)
1314
#define ITEM_FIRST_OFFSET 17
1415
#define ITEM_NEXT_OFFSET 4
1516
#define ITEM_HEIGHT 14
@@ -35,13 +36,56 @@ typedef struct {
3536
ButtonMenuItemArray_t items;
3637
size_t position;
3738
const char* header;
39+
size_t scroll_counter;
40+
FuriTimer* scroll_timer;
3841
} ButtonMenuModel;
3942

43+
static void button_menu_draw_text(
44+
Canvas* canvas,
45+
uint8_t item_x,
46+
uint8_t item_y,
47+
const char* text,
48+
bool selected,
49+
ButtonMenuModel* model) {
50+
FuriString* disp_str;
51+
disp_str = furi_string_alloc_set(text);
52+
bool draw_static = true;
53+
54+
if(selected) {
55+
size_t text_width = canvas_string_width(canvas, furi_string_get_cstr(disp_str));
56+
if(text_width >= ITEM_WIDTH - 8) {
57+
elements_scrollable_text_line(
58+
canvas,
59+
item_x + 4,
60+
item_y + ITEM_HEIGHT - 4,
61+
ITEM_WIDTH - 8,
62+
disp_str,
63+
model->scroll_counter,
64+
false);
65+
draw_static = false;
66+
}
67+
}
68+
69+
if(draw_static) {
70+
elements_string_fit_width(canvas, disp_str, ITEM_WIDTH - 6);
71+
canvas_draw_str_aligned(
72+
canvas,
73+
item_x + (ITEM_WIDTH / 2),
74+
item_y + (ITEM_HEIGHT / 2),
75+
AlignCenter,
76+
AlignCenter,
77+
furi_string_get_cstr(disp_str));
78+
}
79+
80+
furi_string_free(disp_str);
81+
}
82+
4083
static void button_menu_draw_control_button(
4184
Canvas* canvas,
4285
uint8_t item_position,
4386
const char* text,
44-
bool selected) {
87+
bool selected,
88+
ButtonMenuModel* model) {
4589
furi_assert(canvas);
4690
furi_assert(text);
4791

@@ -54,20 +98,16 @@ static void button_menu_draw_control_button(
5498
elements_slightly_rounded_box(canvas, item_x, item_y, ITEM_WIDTH, ITEM_HEIGHT);
5599
canvas_set_color(canvas, ColorWhite);
56100
}
57-
canvas_draw_str_aligned(
58-
canvas,
59-
item_x + (ITEM_WIDTH / 2),
60-
item_y + (ITEM_HEIGHT / 2),
61-
AlignCenter,
62-
AlignCenter,
63-
text);
101+
102+
button_menu_draw_text(canvas, item_x, item_y, text, selected, model);
64103
}
65104

66105
static void button_menu_draw_common_button(
67106
Canvas* canvas,
68107
uint8_t item_position,
69108
const char* text,
70-
bool selected) {
109+
bool selected,
110+
ButtonMenuModel* model) {
71111
furi_assert(canvas);
72112
furi_assert(text);
73113

@@ -83,19 +123,7 @@ static void button_menu_draw_common_button(
83123
canvas_draw_rframe(canvas, item_x, item_y, ITEM_WIDTH, ITEM_HEIGHT, 5);
84124
}
85125

86-
FuriString* disp_str;
87-
disp_str = furi_string_alloc_set(text);
88-
elements_string_fit_width(canvas, disp_str, ITEM_WIDTH - 6);
89-
90-
canvas_draw_str_aligned(
91-
canvas,
92-
item_x + (ITEM_WIDTH / 2),
93-
item_y + (ITEM_HEIGHT / 2),
94-
AlignCenter,
95-
AlignCenter,
96-
furi_string_get_cstr(disp_str));
97-
98-
furi_string_free(disp_str);
126+
button_menu_draw_text(canvas, item_x, item_y, text, selected, model);
99127
}
100128

101129
static void button_menu_view_draw_callback(Canvas* canvas, void* _model) {
@@ -120,9 +148,17 @@ static void button_menu_view_draw_callback(Canvas* canvas, void* _model) {
120148
if(model->header) {
121149
FuriString* disp_str;
122150
disp_str = furi_string_alloc_set(model->header);
123-
elements_string_fit_width(canvas, disp_str, ITEM_WIDTH - 6);
124-
canvas_draw_str_aligned(
125-
canvas, 32, 10, AlignCenter, AlignCenter, furi_string_get_cstr(disp_str));
151+
size_t header_width = canvas_string_width(canvas, furi_string_get_cstr(disp_str));
152+
153+
if(header_width >= ITEM_WIDTH - 8) {
154+
elements_scrollable_text_line(
155+
canvas, 3, 13, ITEM_WIDTH - 8, disp_str, model->scroll_counter, false);
156+
} else {
157+
elements_string_fit_width(canvas, disp_str, ITEM_WIDTH - 8);
158+
canvas_draw_str_aligned(
159+
canvas, 32, 10, AlignCenter, AlignCenter, furi_string_get_cstr(disp_str));
160+
}
161+
126162
furi_string_free(disp_str);
127163
}
128164

@@ -137,13 +173,15 @@ static void button_menu_view_draw_callback(Canvas* canvas, void* _model) {
137173
canvas,
138174
item_position % BUTTONS_PER_SCREEN,
139175
ButtonMenuItemArray_cref(it)->label,
140-
(item_position == model->position));
176+
(item_position == model->position),
177+
model);
141178
} else if(ButtonMenuItemArray_cref(it)->type == ButtonMenuItemTypeCommon) {
142179
button_menu_draw_common_button(
143180
canvas,
144181
item_position % BUTTONS_PER_SCREEN,
145182
ButtonMenuItemArray_cref(it)->label,
146-
(item_position == model->position));
183+
(item_position == model->position),
184+
model);
147185
}
148186
}
149187
}
@@ -158,8 +196,10 @@ static void button_menu_process_up(ButtonMenu* button_menu) {
158196
{
159197
if(model->position > 0) {
160198
model->position--;
199+
model->scroll_counter = 0;
161200
} else {
162201
model->position = ButtonMenuItemArray_size(model->items) - 1;
202+
model->scroll_counter = 0;
163203
}
164204
},
165205
true);
@@ -174,8 +214,10 @@ static void button_menu_process_down(ButtonMenu* button_menu) {
174214
{
175215
if(model->position < (ButtonMenuItemArray_size(model->items) - 1)) {
176216
model->position++;
217+
model->scroll_counter = 0;
177218
} else {
178219
model->position = 0;
220+
model->scroll_counter = 0;
179221
}
180222
},
181223
true);
@@ -193,8 +235,10 @@ static void button_menu_process_right(ButtonMenu* button_menu) {
193235
position_candidate -= position_candidate % BUTTONS_PER_SCREEN;
194236
if(position_candidate < (ButtonMenuItemArray_size(model->items))) {
195237
model->position = position_candidate;
238+
model->scroll_counter = 0;
196239
} else {
197240
model->position = 0;
241+
model->scroll_counter = 0;
198242
}
199243
}
200244
},
@@ -217,6 +261,7 @@ static void button_menu_process_left(ButtonMenu* button_menu) {
217261
};
218262
position_candidate -= position_candidate % BUTTONS_PER_SCREEN;
219263
model->position = position_candidate;
264+
model->scroll_counter = 0;
220265
}
221266
},
222267
true);
@@ -314,6 +359,7 @@ void button_menu_reset(ButtonMenu* button_menu) {
314359
ButtonMenuItemArray_reset(model->items);
315360
model->position = 0;
316361
model->header = NULL;
362+
model->scroll_counter = 0;
317363
},
318364
true);
319365
}
@@ -351,6 +397,12 @@ ButtonMenuItem* button_menu_add_item(
351397
return item;
352398
}
353399

400+
static void button_menu_process_timer_callback(void* context) {
401+
ButtonMenu* button_menu = context;
402+
with_view_model(
403+
button_menu->view, ButtonMenuModel * model, { model->scroll_counter++; }, true);
404+
}
405+
354406
ButtonMenu* button_menu_alloc(void) {
355407
ButtonMenu* button_menu = malloc(sizeof(ButtonMenu));
356408
button_menu->view = view_alloc();
@@ -367,6 +419,10 @@ ButtonMenu* button_menu_alloc(void) {
367419
ButtonMenuItemArray_init(model->items);
368420
model->position = 0;
369421
model->header = NULL;
422+
model->scroll_counter = 0;
423+
model->scroll_timer = furi_timer_alloc(
424+
button_menu_process_timer_callback, FuriTimerTypePeriodic, button_menu);
425+
furi_timer_start(model->scroll_timer, SCROLL_INTERVAL);
370426
},
371427
true);
372428

@@ -380,7 +436,11 @@ void button_menu_free(ButtonMenu* button_menu) {
380436
with_view_model(
381437
button_menu->view,
382438
ButtonMenuModel * model,
383-
{ ButtonMenuItemArray_clear(model->items); },
439+
{
440+
ButtonMenuItemArray_clear(model->items);
441+
furi_timer_stop(model->scroll_timer);
442+
furi_timer_free(model->scroll_timer);
443+
},
384444
true);
385445
view_free(button_menu->view);
386446
free(button_menu);

0 commit comments

Comments
 (0)