10
10
#include <stdint.h>
11
11
#include <m-array.h>
12
12
13
+ #define SCROLL_INTERVAL (333)
13
14
#define ITEM_FIRST_OFFSET 17
14
15
#define ITEM_NEXT_OFFSET 4
15
16
#define ITEM_HEIGHT 14
@@ -35,13 +36,56 @@ typedef struct {
35
36
ButtonMenuItemArray_t items ;
36
37
size_t position ;
37
38
const char * header ;
39
+ size_t scroll_counter ;
40
+ FuriTimer * scroll_timer ;
38
41
} ButtonMenuModel ;
39
42
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
+
40
83
static void button_menu_draw_control_button (
41
84
Canvas * canvas ,
42
85
uint8_t item_position ,
43
86
const char * text ,
44
- bool selected ) {
87
+ bool selected ,
88
+ ButtonMenuModel * model ) {
45
89
furi_assert (canvas );
46
90
furi_assert (text );
47
91
@@ -54,20 +98,16 @@ static void button_menu_draw_control_button(
54
98
elements_slightly_rounded_box (canvas , item_x , item_y , ITEM_WIDTH , ITEM_HEIGHT );
55
99
canvas_set_color (canvas , ColorWhite );
56
100
}
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 );
64
103
}
65
104
66
105
static void button_menu_draw_common_button (
67
106
Canvas * canvas ,
68
107
uint8_t item_position ,
69
108
const char * text ,
70
- bool selected ) {
109
+ bool selected ,
110
+ ButtonMenuModel * model ) {
71
111
furi_assert (canvas );
72
112
furi_assert (text );
73
113
@@ -83,19 +123,7 @@ static void button_menu_draw_common_button(
83
123
canvas_draw_rframe (canvas , item_x , item_y , ITEM_WIDTH , ITEM_HEIGHT , 5 );
84
124
}
85
125
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 );
99
127
}
100
128
101
129
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) {
120
148
if (model -> header ) {
121
149
FuriString * disp_str ;
122
150
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
+
126
162
furi_string_free (disp_str );
127
163
}
128
164
@@ -137,13 +173,15 @@ static void button_menu_view_draw_callback(Canvas* canvas, void* _model) {
137
173
canvas ,
138
174
item_position % BUTTONS_PER_SCREEN ,
139
175
ButtonMenuItemArray_cref (it )-> label ,
140
- (item_position == model -> position ));
176
+ (item_position == model -> position ),
177
+ model );
141
178
} else if (ButtonMenuItemArray_cref (it )-> type == ButtonMenuItemTypeCommon ) {
142
179
button_menu_draw_common_button (
143
180
canvas ,
144
181
item_position % BUTTONS_PER_SCREEN ,
145
182
ButtonMenuItemArray_cref (it )-> label ,
146
- (item_position == model -> position ));
183
+ (item_position == model -> position ),
184
+ model );
147
185
}
148
186
}
149
187
}
@@ -158,8 +196,10 @@ static void button_menu_process_up(ButtonMenu* button_menu) {
158
196
{
159
197
if (model -> position > 0 ) {
160
198
model -> position -- ;
199
+ model -> scroll_counter = 0 ;
161
200
} else {
162
201
model -> position = ButtonMenuItemArray_size (model -> items ) - 1 ;
202
+ model -> scroll_counter = 0 ;
163
203
}
164
204
},
165
205
true);
@@ -174,8 +214,10 @@ static void button_menu_process_down(ButtonMenu* button_menu) {
174
214
{
175
215
if (model -> position < (ButtonMenuItemArray_size (model -> items ) - 1 )) {
176
216
model -> position ++ ;
217
+ model -> scroll_counter = 0 ;
177
218
} else {
178
219
model -> position = 0 ;
220
+ model -> scroll_counter = 0 ;
179
221
}
180
222
},
181
223
true);
@@ -193,8 +235,10 @@ static void button_menu_process_right(ButtonMenu* button_menu) {
193
235
position_candidate -= position_candidate % BUTTONS_PER_SCREEN ;
194
236
if (position_candidate < (ButtonMenuItemArray_size (model -> items ))) {
195
237
model -> position = position_candidate ;
238
+ model -> scroll_counter = 0 ;
196
239
} else {
197
240
model -> position = 0 ;
241
+ model -> scroll_counter = 0 ;
198
242
}
199
243
}
200
244
},
@@ -217,6 +261,7 @@ static void button_menu_process_left(ButtonMenu* button_menu) {
217
261
};
218
262
position_candidate -= position_candidate % BUTTONS_PER_SCREEN ;
219
263
model -> position = position_candidate ;
264
+ model -> scroll_counter = 0 ;
220
265
}
221
266
},
222
267
true);
@@ -314,6 +359,7 @@ void button_menu_reset(ButtonMenu* button_menu) {
314
359
ButtonMenuItemArray_reset (model -> items );
315
360
model -> position = 0 ;
316
361
model -> header = NULL ;
362
+ model -> scroll_counter = 0 ;
317
363
},
318
364
true);
319
365
}
@@ -351,6 +397,12 @@ ButtonMenuItem* button_menu_add_item(
351
397
return item ;
352
398
}
353
399
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
+
354
406
ButtonMenu * button_menu_alloc (void ) {
355
407
ButtonMenu * button_menu = malloc (sizeof (ButtonMenu ));
356
408
button_menu -> view = view_alloc ();
@@ -367,6 +419,10 @@ ButtonMenu* button_menu_alloc(void) {
367
419
ButtonMenuItemArray_init (model -> items );
368
420
model -> position = 0 ;
369
421
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 );
370
426
},
371
427
true);
372
428
@@ -380,7 +436,11 @@ void button_menu_free(ButtonMenu* button_menu) {
380
436
with_view_model (
381
437
button_menu -> view ,
382
438
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
+ },
384
444
true);
385
445
view_free (button_menu -> view );
386
446
free (button_menu );
0 commit comments