summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Wilgus <wilgus.william@gmail.com>2021-12-15 00:37:04 -0500
committerWilliam Wilgus <me.theuser@yahoo.com>2022-01-01 23:56:51 -0500
commita7703e4926075ee41269ca96d1806444107e65f2 (patch)
treea9b5c6a5df97267c71b0c1ad0613ca0be0d66c4d
parentedc68b06574b57684a7fad4263dd59eed7f65f2f (diff)
downloadrockbox-a7703e4926075ee41269ca96d1806444107e65f2.tar.gz
rockbox-a7703e4926075ee41269ca96d1806444107e65f2.zip
gui lists add callback for owner drawn items
allow the guts of gui_sync_list to be used with owner drawn items WIP printcell_helper-- goal: allow data to be displayed in a spreadsheet format with an easy to use interface printcell_set_columns(gui_synclist, title, icon) sets title and calculates cell widths each column is identified by '$' character ex 3 columns title = "Col1$Col2$Col3" also accepts $*WIDTH$ ex 3 columns varying width title = "$*64$Col1$*128$Col2$Col3 printcell_enable(gui_synclist, enable) sets the printcell function enabled After setting the columns and enabling the printcell function items can be added to the list like normal column items are supplied delimited by '$' ex item = "Item1$item2$item3" they will be placed in cells defined by set_columns and scroll if the cell is too small --Fixed for 1 bit & 2 bit displays Change-Id: I49bd7903005d7a54e93af4379b0cdea63c860656
-rw-r--r--apps/gui/bitmap/list.c132
-rw-r--r--apps/gui/list.c1
-rw-r--r--apps/gui/list.h30
-rw-r--r--apps/plugins/lib/SOURCES1
-rw-r--r--apps/plugins/lib/printcell_helper.c493
-rw-r--r--apps/plugins/lib/printcell_helper.h45
-rw-r--r--apps/plugins/rb_info.c110
7 files changed, 763 insertions, 49 deletions
diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index 194f4c008b..1b051cd800 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -90,11 +90,57 @@ static int list_icon_width(enum screen_type screen)
90 return get_icon_width(screen) + ICON_PADDING * 2; 90 return get_icon_width(screen) + ICON_PADDING * 2;
91} 91}
92 92
93static bool draw_title(struct screen *display, struct gui_synclist *list) 93static void _default_listdraw_fn(struct list_putlineinfo_t *list_info)
94{
95 struct screen *display = list_info->display;
96 int x = list_info->x;
97 int y = list_info->y;
98 int item_indent = list_info->item_indent;
99 int item_offset = list_info->item_offset;
100 int icon = list_info->icon;
101 bool is_selected = list_info->is_selected;
102 bool is_title = list_info->is_title;
103 bool show_cursor = list_info->show_cursor;
104 bool have_icons = list_info->have_icons;
105 struct line_desc *linedes = list_info->linedes;
106 char *dsp_text = list_info->dsp_text;
107
108 if (is_title)
109 {
110 if (have_icons)
111 display->put_line(x, y, linedes, "$"ICON_PADDING_S"I$t",
112 icon, dsp_text);
113 else
114 display->put_line(x, y, linedes, "$t", dsp_text);
115 }
116 else if (show_cursor && have_icons)
117 {
118 /* the list can have both, one of or neither of cursor and item icons,
119 * if both don't apply icon padding twice between the icons */
120 display->put_line(x, y,
121 linedes, "$*s$"ICON_PADDING_S"I$i$"ICON_PADDING_S"s$*t",
122 item_indent, is_selected ? Icon_Cursor : Icon_NOICON,
123 icon, item_offset, dsp_text);
124 }
125 else if (show_cursor || have_icons)
126 {
127 display->put_line(x, y, linedes, "$*s$"ICON_PADDING_S"I$*t", item_indent,
128 show_cursor ? (is_selected ? Icon_Cursor:Icon_NOICON):icon,
129 item_offset, dsp_text);
130 }
131 else
132 {
133 display->put_line(x, y, linedes, "$*s$*t", item_indent, item_offset, dsp_text);
134 }
135}
136
137static bool draw_title(struct screen *display,
138 struct gui_synclist *list,
139 list_draw_item *callback_draw_item)
94{ 140{
95 const int screen = display->screen_type; 141 const int screen = display->screen_type;
96 struct viewport *title_text_vp = &title_text[screen]; 142 struct viewport *title_text_vp = &title_text[screen];
97 struct line_desc line = LINE_DESC_DEFINIT; 143 struct line_desc linedes = LINE_DESC_DEFINIT;
98 144
99 if (sb_set_title_text(list->title, list->title_icon, screen)) 145 if (sb_set_title_text(list->title, list->title_icon, screen))
100 return false; /* the sbs is handling the title */ 146 return false; /* the sbs is handling the title */
@@ -102,29 +148,39 @@ static bool draw_title(struct screen *display, struct gui_synclist *list)
102 if (!list_display_title(list, screen)) 148 if (!list_display_title(list, screen))
103 return false; 149 return false;
104 *title_text_vp = *(list->parent[screen]); 150 *title_text_vp = *(list->parent[screen]);
105 line.height = list->line_height[screen]; 151 linedes.height = list->line_height[screen];
106 title_text_vp->height = line.height; 152 title_text_vp->height = linedes.height;
107 153
108#if LCD_DEPTH > 1 154#if LCD_DEPTH > 1
109 /* XXX: Do we want to support the separator on remote displays? */ 155 /* XXX: Do we want to support the separator on remote displays? */
110 if (display->screen_type == SCREEN_MAIN && global_settings.list_separator_height != 0) 156 if (display->screen_type == SCREEN_MAIN && global_settings.list_separator_height != 0)
111 line.separator_height = abs(global_settings.list_separator_height) 157 linedes.separator_height = abs(global_settings.list_separator_height)
112 + (lcd_get_dpi() > 200 ? 2 : 1); 158 + (lcd_get_dpi() > 200 ? 2 : 1);
113#endif 159#endif
114 160
115#ifdef HAVE_LCD_COLOR 161#ifdef HAVE_LCD_COLOR
116 if (list->title_color >= 0) 162 if (list->title_color >= 0)
117 line.style |= (STYLE_COLORED|list->title_color); 163 linedes.style |= (STYLE_COLORED|list->title_color);
118#endif 164#endif
119 line.scroll = true; 165 linedes.scroll = true;
120 166
121 display->set_viewport(title_text_vp); 167 display->set_viewport(title_text_vp);
168 int icon = list->title_icon;
169 int icon_w = list_icon_width(display->screen_type);
170 bool have_icons = false;
171 if (icon != Icon_NOICON && global_settings.show_icons)
172 have_icons = true;
122 173
123 if (list->title_icon != Icon_NOICON && global_settings.show_icons) 174 struct list_putlineinfo_t list_info =
124 put_line(display, 0, 0, &line, "$"ICON_PADDING_S"I$t", 175 {
125 list->title_icon, list->title); 176 .x = 0, .y = 0, .item_indent = 0, .item_offset = 0,
126 else 177 .line = -1, .icon = icon, .icon_width = icon_w,
127 put_line(display, 0, 0, &line, "$t", list->title); 178 .display = display, .vp = title_text_vp, .linedes = &linedes, .list = list,
179 .dsp_text = list->title,
180 .is_selected = false, .is_title = true, .show_cursor = false,
181 .have_icons = have_icons
182 };
183 callback_draw_item(&list_info);
128 184
129 return true; 185 return true;
130} 186}
@@ -133,6 +189,8 @@ void list_draw(struct screen *display, struct gui_synclist *list)
133{ 189{
134 int start, end, item_offset, i; 190 int start, end, item_offset, i;
135 const int screen = display->screen_type; 191 const int screen = display->screen_type;
192 list_draw_item *callback_draw_item;
193
136 const int list_start_item = list->start_item[screen]; 194 const int list_start_item = list->start_item[screen];
137 const bool scrollbar_in_left = (global_settings.scrollbar == SCROLLBAR_LEFT); 195 const bool scrollbar_in_left = (global_settings.scrollbar == SCROLLBAR_LEFT);
138 const bool scrollbar_in_right = (global_settings.scrollbar == SCROLLBAR_RIGHT); 196 const bool scrollbar_in_right = (global_settings.scrollbar == SCROLLBAR_RIGHT);
@@ -145,11 +203,16 @@ void list_draw(struct screen *display, struct gui_synclist *list)
145 struct viewport *list_text_vp = &list_text[screen]; 203 struct viewport *list_text_vp = &list_text[screen];
146 int indent = 0; 204 int indent = 0;
147 205
206 if (list->callback_draw_item != NULL)
207 callback_draw_item = list->callback_draw_item;
208 else
209 callback_draw_item = _default_listdraw_fn;
210
148 struct viewport * last_vp = display->set_viewport(parent); 211 struct viewport * last_vp = display->set_viewport(parent);
149 display->clear_viewport(); 212 display->clear_viewport();
150 display->scroll_stop_viewport(list_text_vp); 213 display->scroll_stop_viewport(list_text_vp);
151 *list_text_vp = *parent; 214 *list_text_vp = *parent;
152 if ((show_title = draw_title(display, list))) 215 if ((show_title = draw_title(display, list, callback_draw_item)))
153 { 216 {
154 int title_height = title_text[screen].height; 217 int title_height = title_text[screen].height;
155 list_text_vp->y += title_height; 218 list_text_vp->y += title_height;
@@ -244,6 +307,16 @@ void list_draw(struct screen *display, struct gui_synclist *list)
244 } 307 }
245 308
246 display->set_viewport(list_text_vp); 309 display->set_viewport(list_text_vp);
310 int icon_w = list_icon_width(screen);
311 int character_width = display->getcharwidth();
312
313 struct list_putlineinfo_t list_info =
314 {
315 .x = 0, .y = 0, .vp = list_text_vp, .list = list,
316 .icon_width = icon_w, .is_title = false, .show_cursor = show_cursor,
317 .have_icons = have_icons, .linedes = &linedes, .display = display
318 };
319
247 for (i=start; i<end && i<list->nb_items; i++) 320 for (i=start; i<end && i<list->nb_items; i++)
248 { 321 {
249 /* do the text */ 322 /* do the text */
@@ -251,7 +324,7 @@ void list_draw(struct screen *display, struct gui_synclist *list)
251 unsigned const char *s; 324 unsigned const char *s;
252 char entry_buffer[MAX_PATH]; 325 char entry_buffer[MAX_PATH];
253 unsigned char *entry_name; 326 unsigned char *entry_name;
254 int text_pos = 0; 327 const int text_pos = 0; /* UNUSED */
255 int line = i - start; 328 int line = i - start;
256 int line_indent = 0; 329 int line_indent = 0;
257 int style = STYLE_DEFAULT; 330 int style = STYLE_DEFAULT;
@@ -268,9 +341,9 @@ void list_draw(struct screen *display, struct gui_synclist *list)
268 if (line_indent) 341 if (line_indent)
269 { 342 {
270 if (global_settings.show_icons) 343 if (global_settings.show_icons)
271 line_indent *= list_icon_width(screen); 344 line_indent *= icon_w;
272 else 345 else
273 line_indent *= display->getcharwidth(); 346 line_indent *= character_width;
274 } 347 }
275 line_indent += indent; 348 line_indent += indent;
276 349
@@ -345,27 +418,22 @@ void list_draw(struct screen *display, struct gui_synclist *list)
345 } 418 }
346 } 419 }
347#endif 420#endif
348
349 linedes.style = style; 421 linedes.style = style;
350 linedes.scroll = is_selected ? true : list->scroll_all; 422 linedes.scroll = is_selected ? true : list->scroll_all;
351 linedes.line = i % list->selected_size; 423 linedes.line = i % list->selected_size;
352 icon = list->callback_get_item_icon ? 424 icon = list->callback_get_item_icon ?
353 list->callback_get_item_icon(i, list->data) : Icon_NOICON; 425 list->callback_get_item_icon(i, list->data) : Icon_NOICON;
354 /* the list can have both, one of or neither of cursor and item icons, 426
355 * if both don't apply icon padding twice between the icons */ 427
356 if (show_cursor && have_icons) 428 list_info.y = line * linedes.height + draw_offset;
357 put_line(display, 0, line * linedes.height + draw_offset, 429 list_info.is_selected = is_selected;
358 &linedes, "$*s$"ICON_PADDING_S"I$i$"ICON_PADDING_S"s$*t", 430 list_info.item_indent = line_indent;
359 line_indent, is_selected ? Icon_Cursor : Icon_NOICON, 431 list_info.line = i;
360 icon, item_offset, entry_name); 432 list_info.icon = icon;
361 else if (show_cursor || have_icons) 433 list_info.dsp_text = entry_name;
362 put_line(display, 0, line * linedes.height + draw_offset, 434 list_info.item_offset = item_offset;
363 &linedes, "$*s$"ICON_PADDING_S"I$*t", line_indent, 435
364 show_cursor ? (is_selected ? Icon_Cursor:Icon_NOICON):icon, 436 callback_draw_item(&list_info);
365 item_offset, entry_name);
366 else
367 put_line(display, 0, line * linedes.height + draw_offset,
368 &linedes, "$*s$*t", line_indent, item_offset, entry_name);
369 } 437 }
370 display->set_viewport(parent); 438 display->set_viewport(parent);
371 display->update_viewport(); 439 display->update_viewport();
diff --git a/apps/gui/list.c b/apps/gui/list.c
index 8ff075da7e..a8055c4581 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -150,6 +150,7 @@ void gui_synclist_init(struct gui_synclist * gui_list,
150 gui_list->callback_get_item_icon = NULL; 150 gui_list->callback_get_item_icon = NULL;
151 gui_list->callback_get_item_name = callback_get_item_name; 151 gui_list->callback_get_item_name = callback_get_item_name;
152 gui_list->callback_speak_item = NULL; 152 gui_list->callback_speak_item = NULL;
153 gui_list->callback_draw_item = NULL;
153 gui_list->nb_items = 0; 154 gui_list->nb_items = 0;
154 gui_list->selected_item = 0; 155 gui_list->selected_item = 0;
155#ifdef HAVE_TOUCHSCREEN 156#ifdef HAVE_TOUCHSCREEN
diff --git a/apps/gui/list.h b/apps/gui/list.h
index 64ff3e3fdd..1f910577a1 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -69,6 +69,35 @@ typedef enum themable_icons list_get_icon(int selected_item, void * data);
69typedef const char * list_get_name(int selected_item, void * data, 69typedef const char * list_get_name(int selected_item, void * data,
70 char * buffer, size_t buffer_len); 70 char * buffer, size_t buffer_len);
71/* 71/*
72 * Draw callback
73 * - display : functions supplied depends on the screen call originated from (typ: MAIN)
74 * - list_info : a pointer to an internal struct containing item display information
75 */
76/* owner drawn lists need to know this info */
77struct list_putlineinfo_t {
78 int x;
79 int y;
80 int item_indent;
81 int item_offset;
82 int line;
83
84 int icon;
85 int icon_width;
86
87 struct screen *display;
88 struct viewport *vp;
89 struct line_desc *linedes;
90 struct gui_synclist * list;
91 char *dsp_text;
92
93 bool is_selected;
94 bool is_title;
95 bool show_cursor;
96 bool have_icons;
97};
98
99typedef void list_draw_item(struct list_putlineinfo_t *list_info);
100/*
72 * Voice callback 101 * Voice callback
73 * - selected_item : an integer that tells the number of the item to speak 102 * - selected_item : an integer that tells the number of the item to speak
74 * - data : a void pointer to the data you gave to the list when you 103 * - data : a void pointer to the data you gave to the list when you
@@ -133,6 +162,7 @@ struct gui_synclist
133 list_get_icon *callback_get_item_icon; 162 list_get_icon *callback_get_item_icon;
134 list_get_name *callback_get_item_name; 163 list_get_name *callback_get_item_name;
135 list_speak_item *callback_speak_item; 164 list_speak_item *callback_speak_item;
165 list_draw_item *callback_draw_item;
136 166
137 /* The data that will be passed to the callback function YOU implement */ 167 /* The data that will be passed to the callback function YOU implement */
138 void * data; 168 void * data;
diff --git a/apps/plugins/lib/SOURCES b/apps/plugins/lib/SOURCES
index 1cd092f8df..bff9017404 100644
--- a/apps/plugins/lib/SOURCES
+++ b/apps/plugins/lib/SOURCES
@@ -14,6 +14,7 @@ rgb_hsv.c
14highscore.c 14highscore.c
15simple_viewer.c 15simple_viewer.c
16display_text.c 16display_text.c
17printcell_helper.c
17strncpy.c 18strncpy.c
18stdio_compat.c 19stdio_compat.c
19 20
diff --git a/apps/plugins/lib/printcell_helper.c b/apps/plugins/lib/printcell_helper.c
new file mode 100644
index 0000000000..27a4b0fc95
--- /dev/null
+++ b/apps/plugins/lib/printcell_helper.c
@@ -0,0 +1,493 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 by William Wilgus
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21/* spreadsheet cells for rockbox lists */
22#include "plugin.h"
23#include "lib/printcell_helper.h"
24
25#ifndef PRINTCELL_MAX_COLUMNS
26#define PRINTCELL_MAX_COLUMNS 16
27#endif
28
29#define COLUMN_ENDLEN 3
30#define TITLE_FLAG 0xFF
31#define SELECTED_FLAG 0x1
32
33#if LCD_DEPTH == 1
34#define BAR_WIDTH (1)
35#else
36#define BAR_WIDTH (COLUMN_ENDLEN)
37#endif
38
39struct printcell_info_t {
40 int offw[NB_SCREENS];
41 int iconw[NB_SCREENS];
42 int selcol_offw[NB_SCREENS];
43 int totalcolw[NB_SCREENS];
44 uint16_t colw[NB_SCREENS][PRINTCELL_MAX_COLUMNS];
45 int ncols;
46 int selcol;
47 int selcol_index;
48 char title[PRINTCELL_MAXLINELEN];
49 bool separator;
50};
51static struct printcell_info_t printcell;
52
53static void parse_dsptext(int ncols, const char *dsp_text, char* buffer, uint16_t *sidx)
54{
55 /*Internal function loads sidx with split offsets indexing
56 the buffer of null terminated strings, splits on '$'
57 _assumptions_:
58 dsp_text[len - 1] = \0,
59 buffer[PRINTCELL_MAXLINELEN],
60 sidx[PRINTCELL_MAX_COLUMNS]
61 */
62 int i = 0;
63 int j = 0;
64 int ch = '$'; /* first column $ is optional */
65 if (*dsp_text == '$')
66 dsp_text++;
67 /* add null to the start of the text buffer */
68 buffer[j++] = '\0';
69 do
70 {
71 if (ch == '$')
72 {
73 sidx[i] = j;
74 if (*dsp_text == '$') /* $$ escaped user must want to display $*/
75 buffer[j++] = *dsp_text++;
76 while (*dsp_text != '\0' && *dsp_text != '$' && j < PRINTCELL_MAXLINELEN - 1)
77 buffer[j++] = *dsp_text++;
78 buffer[j++] = '\0';
79 i++;
80 if (i >= ncols || j >= (PRINTCELL_MAXLINELEN - 1))
81 break;
82 }
83 ch = *dsp_text++;
84 } while (ch != '\0');
85 while (i < ncols)
86 sidx[i++] = 0; /* point to null */
87}
88
89static void draw_selector(struct screen *display, struct line_desc *linedes,
90 int selected_flag, int selected_col,
91 int separator_height, int x, int y, int w, int h)
92{
93 /* Internal function draws the currently selected items row & column styling */
94 if (!(separator_height > 0 || (selected_flag & SELECTED_FLAG)))
95 return;
96 y--;
97 h++;
98 int linestyle = linedes->style & _STYLE_DECO_MASK;
99 bool invert = (selected_flag == SELECTED_FLAG && linestyle >= STYLE_COLORBAR);
100 if (invert || (linestyle & STYLE_INVERT) == STYLE_INVERT)
101 {
102 display->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
103 }
104
105 if (selected_col == printcell.selcol)
106 {
107 if (selected_flag & SELECTED_FLAG)
108 {
109 /* expand left and right bars to show selected column */
110 display->fillrect(x, y, BAR_WIDTH, h);
111 display->fillrect(x + w - BAR_WIDTH + 1, y, BAR_WIDTH, h);
112 display->set_drawmode(DRMODE_FG);
113 }
114 else
115 {
116 /* only draw left and right bars */
117 display->drawrect(x + 1, y, 1, h);
118 display->drawrect(x + w - 1, y, 1, h);
119 return;
120 }
121 }
122 /* draw whole rect outline */
123 display->drawrect(x + 1, y, w - 1, h);
124}
125
126static inline void set_cell_width(struct viewport *vp, int max_w, int new_w)
127{
128 /* Internal function sets cell width if less than the max width */
129 if (new_w > max_w)
130 vp->width = max_w;
131 else
132 vp->width = new_w;
133 vp->width -= COLUMN_ENDLEN;
134}
135
136static inline int printcells(struct screen *display, char* buffer, uint16_t *sidx,
137 struct line_desc *linedes, struct viewport *vp, int vp_w,
138 int separator, int x, int y, int offw, int selected_flag)
139{
140 /* Internal function prints remaining cells */
141 int text_offset = offw + offw;
142 int ncols = printcell.ncols;
143 int screen = display->screen_type;
144 int height = linedes->height;
145 int selsep = (selected_flag == 0) ? 0: separator;
146 uint16_t *screencolwidth = printcell.colw[screen];
147
148 for(int i = 1; i < ncols; i++)
149 {
150 int ny = y;
151 int nw = screencolwidth[i] + text_offset;
152 int nx = x + nw;
153 char *buftext;
154 if (nx > 0 && x < vp_w)
155 {
156 set_cell_width(vp, vp_w, nx);
157
158 if (i == printcell.selcol)
159 linedes->separator_height = selsep;
160 else
161 linedes->separator_height = separator;
162
163 buftext = &buffer[sidx[i]];
164 display->put_line(x + offw, ny, linedes, "$t", buftext);
165 vp->width += COLUMN_ENDLEN + 1;
166 draw_selector(display, linedes, selected_flag, i, separator, x, ny, nw, height);
167 }
168 x = nx;
169 }
170 return x;
171}
172
173static inline int calcvisible(int screen, int vp_w, int text_offset, int sbwidth)
174{
175 /* Internal function determine how many of the previous colums can be shown */
176 uint16_t *screencolwidth = printcell.colw[screen];
177 int screenicnwidth = printcell.iconw[screen];
178 int offset = 0;
179 int selcellw = screencolwidth[printcell.selcol] + text_offset;
180 int maxw = vp_w - (sbwidth + selcellw + 1);
181
182 for (int i = printcell.selcol - 1; i >= 0; i--)
183 {
184 int cw = screencolwidth[i] + text_offset;
185 if (i == 0)
186 cw += screenicnwidth;
187 if (offset > 0 || cw > maxw)
188 offset += cw; /* can not display this cell -- everything left goes here too */
189 else
190 maxw -= cw; /* can display this cell subtract from the max width */
191 }
192 return offset;
193}
194
195static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info)
196{
197/* Internal function callback from the list, draws items as they are requested */
198#define ICON_PADDING 1
199#define ICON_PADDING_S "1"
200 struct screen *display = list_info->display;
201 int screen = display->screen_type;
202 int col_offset_width = printcell.offw[screen];
203 int text_offset = col_offset_width + col_offset_width;
204
205 static char printcell_buffer[PRINTCELL_MAXLINELEN];
206 static uint16_t sidx[PRINTCELL_MAX_COLUMNS]; /*indexes zero terminated strings in buffer*/
207
208 int offset_pos = list_info->list->offset_position[screen];
209 int x = list_info->x - offset_pos;
210 int y = list_info->y;
211 int line_indent = list_info->item_indent;
212 int item_offset = list_info->item_offset;
213 int icon = list_info->icon;
214 int icon_w = list_info->icon_width;
215 bool is_title = list_info->is_title;
216 bool is_selected = list_info->is_selected;
217 bool show_cursor = list_info->show_cursor;
218 bool have_icons = list_info->have_icons;
219 struct line_desc *linedes = list_info->linedes;
220 char *dsp_text = list_info->dsp_text;
221 struct viewport *vp = list_info->vp;
222
223 int selected_flag = ((is_selected || is_title) ?
224 (is_title ? TITLE_FLAG : SELECTED_FLAG) : 0);
225 int vp_w = vp->width;/* save for restore */
226 int saved_separator_height = linedes->separator_height;/* save for restore */
227
228 linedes->separator_height = 0;
229 int separator = saved_separator_height;
230
231 if (printcell.separator || (selected_flag & SELECTED_FLAG))
232 separator = 1;
233
234 int nx = x;
235 int nw, colxw;
236
237 printcell_buffer[0] = '\0';
238 parse_dsptext(printcell.ncols, dsp_text, printcell_buffer, sidx);
239 char *buftext = &printcell_buffer[sidx[0]];
240 uint16_t *screencolwidth = printcell.colw[screen];
241
242 if (is_title)
243 {
244 int sbwidth = 0;
245 if (rb->global_settings->scrollbar == SCROLLBAR_LEFT)
246 sbwidth = rb->global_settings->scrollbar_width;
247
248 printcell.iconw[screen] = have_icons ? ICON_PADDING + icon_w : 0;
249
250 if (printcell.selcol_offw[screen] == 0 && printcell.selcol > 0)
251 printcell.selcol_offw[screen] = calcvisible(screen, vp_w, text_offset, sbwidth);
252 nx -= printcell.selcol_offw[screen];
253
254 nw = screencolwidth[0] + printcell.iconw[screen] + text_offset;
255 nw += sbwidth;
256
257 colxw = nx + nw;
258 if (colxw > 0)
259 {
260 set_cell_width(vp, vp_w, colxw);
261 linedes->separator_height = separator;
262
263 if (have_icons)
264 {
265 display->put_line(nx + (COLUMN_ENDLEN/2), y, linedes,
266 "$"ICON_PADDING_S"I$t", icon, buftext);
267 }
268 else
269 {
270 display->put_line(nx + col_offset_width, y, linedes, "$t", buftext);
271 }
272 }
273 }
274 else
275 {
276 int cursor = Icon_NOICON;
277 nx -= printcell.selcol_offw[screen];
278
279 if (selected_flag & SELECTED_FLAG)
280 {
281 printcell.selcol_index = sidx[printcell.selcol]; /* save the item offset*/
282 cursor = Icon_Cursor;
283 /* limit length of selection if columns don't reach end */
284 int maxw = nx + printcell.totalcolw[screen] + printcell.iconw[screen];
285 maxw += text_offset * printcell.ncols;
286 if (vp_w > maxw)
287 vp->width = maxw;
288 /* display a blank line first to draw selector across all cells */
289 display->put_line(x, y, linedes, "$t", "");
290 }
291
292 nw = screencolwidth[0] + printcell.iconw[screen] + text_offset;
293 colxw = nx + nw;
294 if (colxw > 0)
295 {
296 set_cell_width(vp, vp_w, colxw);
297 if (printcell.selcol == 0 && selected_flag == 0)
298 linedes->separator_height = 0;
299 else
300 linedes->separator_height = separator;
301
302 if (show_cursor && have_icons)
303 {
304 /* the list can have both, one of or neither of cursor and item icons,
305 * if both don't apply icon padding twice between the icons */
306 display->put_line(nx, y,
307 linedes, "$*s$"ICON_PADDING_S"I$i$"ICON_PADDING_S"s$*t",
308 line_indent, cursor, icon, item_offset, buftext);
309 }
310 else if (show_cursor || have_icons)
311 {
312 display->put_line(nx, y, linedes, "$*s$"ICON_PADDING_S"I$*t", line_indent,
313 show_cursor ? cursor:icon, item_offset, buftext);
314 }
315 else
316 {
317 display->put_line(nx + col_offset_width, y, linedes,
318 "$*s$*t", line_indent, item_offset, buftext);
319 }
320 }
321 }
322
323 if (colxw > 0) /* draw selector for first column (title or items) */
324 {
325 vp->width += COLUMN_ENDLEN + 1;
326 draw_selector(display, linedes, selected_flag, 0,
327 separator, nx, y, nw, linedes->height);
328 }
329 nx += nw;
330 /* display remaining cells */
331 printcells(display, printcell_buffer, sidx, linedes,
332 vp, vp_w, separator, nx, y, col_offset_width, selected_flag);
333 /* restore settings */
334 linedes->separator_height = saved_separator_height;
335 display->set_drawmode(DRMODE_FG);
336 vp->width = vp_w;
337}
338
339void printcell_enable(struct gui_synclist *gui_list, bool enable, bool separator)
340{
341 printcell.separator = separator;
342#ifdef HAVE_LCD_COLOR
343 static int list_sep_color = INT_MIN;
344 if (enable)
345 {
346 list_sep_color = rb->global_settings->list_separator_color;
347 rb->global_settings->list_separator_color = rb->global_settings->fg_color;
348 gui_list->callback_draw_item = printcell_listdraw_fn;
349 }
350 else
351 {
352 gui_list->callback_draw_item = NULL;
353 if (list_sep_color != INT_MIN)
354 rb->global_settings->list_separator_color = list_sep_color;
355 list_sep_color = INT_MIN;
356 }
357#else
358 if (enable)
359 gui_list->callback_draw_item = printcell_listdraw_fn;
360 else
361 gui_list->callback_draw_item = NULL;
362#endif
363
364}
365
366int printcell_increment_column(struct gui_synclist *gui_list, int increment, bool wrap)
367{
368 int item = printcell.selcol + increment;
369 int imin = -1;
370 int imax = printcell.ncols - 1;
371 if(wrap)
372 {
373 imin = imax;
374 imax = -1;
375 }
376
377 if (item < -1)
378 item = imin;
379 else if (item >= printcell.ncols)
380 item = imax;
381
382 if (item != printcell.selcol)
383 {
384 FOR_NB_SCREENS(n) /* offset needs recalculated */
385 printcell.selcol_offw[n] = 0;
386 printcell.selcol = item;
387 printcell.selcol_index = 0;
388 rb->gui_synclist_draw(gui_list);
389 }
390 return item;
391}
392
393int printcell_set_columns(struct gui_synclist *gui_list,
394 char * title, enum themable_icons icon)
395{
396 if (title == NULL)
397 title = "$PRINTCELL NOT SETUP";
398 uint16_t sidx[PRINTCELL_MAX_COLUMNS]; /* starting position of column in title string */
399 int width, height, user_minwidth;
400 int i = 0;
401 int j = 0;
402 int ch = '$'; /* first column $ is optional */
403
404 rb->memset(&printcell, 0, sizeof(struct printcell_info_t));
405
406 FOR_NB_SCREENS(n)
407 {
408 rb->screens[n]->getstringsize("W", &width, &height);
409 printcell.offw[n] = width; /* set column text offset */
410 }
411
412 if (*title == '$')
413 title++;
414 do
415 {
416 if (ch == '$')
417 {
418 printcell.title[j++] = ch;
419 user_minwidth = 0;
420 if (*title == '*')/* user wants a minimum size for this column */
421 {
422 char *dspst = title++; /* store starting position in case this is wrong */
423 while(isdigit(*title))
424 {
425 user_minwidth = 10*user_minwidth + *title - '0';
426 title++;
427 }
428 if (*title != '$') /* user forgot $ or wants to display '*' */
429 {
430 title = dspst;
431 user_minwidth = 0;
432 }
433 else
434 title++;
435 }
436
437 sidx[i] = j;
438 if (*title == '$') /* $$ escaped user must want to display $*/
439 printcell.title[j++] = *title++;
440
441 while (*title != '\0' && *title != '$' && j < PRINTCELL_MAXLINELEN - 1)
442 printcell.title[j++] = *title++;
443
444 FOR_NB_SCREENS(n)
445 {
446 rb->screens[n]->getstringsize(&printcell.title[sidx[i]], &width, &height);
447 if (width < user_minwidth)
448 width = user_minwidth;
449 printcell.colw[n][i] = width;
450 printcell.totalcolw[n] += width;
451 }
452 if (++i >= PRINTCELL_MAX_COLUMNS - 1)
453 break;
454 }
455 ch = *title++;
456 } while (ch != '\0');
457 printcell.ncols = i;
458 printcell.title[j] = '\0';
459 printcell.selcol = -1;
460 printcell.selcol_index = 0;
461
462 rb->gui_synclist_set_title(gui_list, printcell.title, icon);
463 return printcell.ncols;
464}
465
466char *printcell_get_selected_column_text(struct gui_synclist *gui_list, char *buf, size_t bufsz)
467{
468 int selected = gui_list->selected_item;
469 int index = printcell.selcol_index - 1;
470
471 if (index < 0)
472 index = 0;
473 char *bpos;
474
475 if (gui_list->callback_get_item_name(selected, gui_list->data, buf, bufsz) == buf)
476 {
477 bpos = &buf[index];
478 if (printcell.selcol < 0) /* return entire string incld col formatting '$'*/
479 return bpos;
480 while(bpos < &buf[bufsz - 1])
481 {
482 if (*bpos == '$' || *bpos == '\0')
483 goto success;
484 bpos++;
485 }
486 }
487/*failure*/
488 bpos = buf;
489 index = 0;
490success:
491 *bpos = '\0';
492 return &buf[index];
493}
diff --git a/apps/plugins/lib/printcell_helper.h b/apps/plugins/lib/printcell_helper.h
new file mode 100644
index 0000000000..adc98e5a5f
--- /dev/null
+++ b/apps/plugins/lib/printcell_helper.h
@@ -0,0 +1,45 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 William Wilgus
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _PRINTCELL_LIST_H_
23#define _PRINTCELL_LIST_H_
24#define PRINTCELL_MAXLINELEN MAX_PATH
25
26/* sets the printcell function enabled */
27void printcell_enable(struct gui_synclist *gui_list, bool enable, bool separator);
28
29/* sets title and calculates cell widths each column is identified by '$' character
30 ex 3 columns title = "Col1$Col2$Col3" also accepts $*WIDTH$
31 ex 3 columns varying width title = "$*64$Col1$*128$Col2$Col3
32 returns number of columns
33*/
34int printcell_set_columns(struct gui_synclist *gui_list,
35 char * title, enum themable_icons icon);
36
37/* increments the current selected column negative increment is allowed
38 returns the selected column
39 range: -1(no selection) to ncols - 1 */
40int printcell_increment_column(struct gui_synclist *gui_list, int increment, bool wrap);
41
42/* return the text of currently selected column buffer should be sized
43 * for max item len, buf[PRINTCELL_MAXLINELEN] is a safe bet */
44char *printcell_get_selected_column_text(struct gui_synclist *gui_list, char *buf, size_t bufsz);
45#endif /*_PRINTCELL_LIST_H_*/
diff --git a/apps/plugins/rb_info.c b/apps/plugins/rb_info.c
index f82c80c0cf..e0ec117dfb 100644
--- a/apps/plugins/rb_info.c
+++ b/apps/plugins/rb_info.c
@@ -29,8 +29,9 @@
29#include "lib/action_helper.h" 29#include "lib/action_helper.h"
30#include "lib/button_helper.h" 30#include "lib/button_helper.h"
31#include "lib/pluginlib_actions.h" 31#include "lib/pluginlib_actions.h"
32#include "lib/printcell_helper.h"
32 33
33#define MENU_ID(x) (((void*)&"RPBUTACNGX\0" + x)) 34#define MENU_ID(x) (((void*)&"RPBUTACNGSX\0" + x))
34enum { 35enum {
35 M_ROOT = 0, 36 M_ROOT = 0,
36 M_PATHS, 37 M_PATHS,
@@ -41,6 +42,7 @@ enum {
41 M_CONTEXTS, 42 M_CONTEXTS,
42 M_ACTTEST, 43 M_ACTTEST,
43 M_PLUGINS, 44 M_PLUGINS,
45 M_TESTPUT,
44 M_EXIT, 46 M_EXIT,
45 M_LAST_ITEM //ITEM COUNT 47 M_LAST_ITEM //ITEM COUNT
46}; 48};
@@ -96,7 +98,8 @@ static const struct paths paths[] = {
96 {"Fm Presets", ""FMPRESET_PATH}, 98 {"Fm Presets", ""FMPRESET_PATH},
97 {"MAX_PATH", ""MACROVAL(MAX_PATH)" bytes"}, 99 {"MAX_PATH", ""MACROVAL(MAX_PATH)" bytes"},
98}; 100};
99 101#define TESTPUT_HEADER "$*64$col1$col2$*128$col3$col4$col5$col6$*64$col7$col8"
102static int testput_cols = 0;
100struct mainmenu { const char *name; void *menuid; int items;}; 103struct mainmenu { const char *name; void *menuid; int items;};
101static struct mainmenu mainmenu[M_LAST_ITEM] = { 104static struct mainmenu mainmenu[M_LAST_ITEM] = {
102#define MENU_ITEM(ID, NAME, COUNT) [ID]{NAME, MENU_ID(ID), (int)COUNT} 105#define MENU_ITEM(ID, NAME, COUNT) [ID]{NAME, MENU_ID(ID), (int)COUNT}
@@ -109,6 +112,7 @@ MENU_ITEM(M_ACTIONS, "Actions", LAST_ACTION_PLACEHOLDER),
109MENU_ITEM(M_CONTEXTS, "Contexts", LAST_CONTEXT_PLACEHOLDER ), 112MENU_ITEM(M_CONTEXTS, "Contexts", LAST_CONTEXT_PLACEHOLDER ),
110MENU_ITEM(M_ACTTEST, "Action test", 3), 113MENU_ITEM(M_ACTTEST, "Action test", 3),
111MENU_ITEM(M_PLUGINS, ID2P(LANG_PLUGINS), MENU_ID_PLUGINS_ITEMS), 114MENU_ITEM(M_PLUGINS, ID2P(LANG_PLUGINS), MENU_ID_PLUGINS_ITEMS),
115MENU_ITEM(M_TESTPUT, "Printcell test", 36),
112MENU_ITEM(M_EXIT, ID2P(LANG_MENU_QUIT), 0), 116MENU_ITEM(M_EXIT, ID2P(LANG_MENU_QUIT), 0),
113#undef MENU_ITEM 117#undef MENU_ITEM
114}; 118};
@@ -125,8 +129,16 @@ static const struct mainmenu *mainitem(int selected_item)
125static void cleanup(void *parameter) 129static void cleanup(void *parameter)
126{ 130{
127 (void)parameter; 131 (void)parameter;
132}
128 133
134#if 0
135static enum themable_icons menu_icon_cb(int selected_item, void * data)
136{
137 (void)data;
138 (void)selected_item;
139 return Icon_NOICON;
129} 140}
141#endif
130 142
131static const char *menu_plugin_name_cb(int selected_item, void* data, 143static const char *menu_plugin_name_cb(int selected_item, void* data,
132 char* buf, size_t buf_len) 144 char* buf, size_t buf_len)
@@ -247,7 +259,7 @@ static const char* list_get_name_cb(int selected_item, void* data,
247 buf[0] = '\0'; 259 buf[0] = '\0';
248 if (data == MENU_ID(M_ROOT)) 260 if (data == MENU_ID(M_ROOT))
249 return mainitem(selected_item)->name; 261 return mainitem(selected_item)->name;
250 else if (selected_item == 0) /*header text*/ 262 else if (selected_item == 0 && data != MENU_ID(M_TESTPUT)) /*header text*/
251 return mainitem(main_last_sel)->name; 263 return mainitem(main_last_sel)->name;
252 else if (selected_item >= mainitem(main_last_sel)->items - 1) 264 else if (selected_item >= mainitem(main_last_sel)->items - 1)
253 return ID2P(LANG_BACK); 265 return ID2P(LANG_BACK);
@@ -286,6 +298,11 @@ static const char* list_get_name_cb(int selected_item, void* data,
286 { 298 {
287 return menu_plugin_name_cb(selected_item - 1, data, buf, buf_len); 299 return menu_plugin_name_cb(selected_item - 1, data, buf, buf_len);
288 } 300 }
301 else if (data == MENU_ID(M_TESTPUT))
302 {
303 rb->snprintf(buf, buf_len, "put_line item: [ %d ]$Text %d$Text LONGER TEST text %d $4$5$6$7$8$9", selected_item, 1, 2);
304 return buf;
305 }
289 return buf; 306 return buf;
290} 307}
291 308
@@ -331,16 +348,38 @@ static int list_voice_cb(int list_index, void* data)
331 return 0; 348 return 0;
332} 349}
333 350
334int menu_action_cb(int action, int selected_item, bool* exit, struct gui_synclist *lists) 351int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_synclist *lists)
335{ 352{
336 if (lists->data == MENU_ID(M_ACTTEST)) 353 if (lists->data == MENU_ID(M_TESTPUT) && (selected_item < (mainitem(M_TESTPUT)->items) - 1)/*back*/)
354 {
355 if (*action == ACTION_STD_OK)
356 {
357 printcell_increment_column(lists, 1, true);
358 *action = ACTION_NONE;
359 }
360 else if (*action == ACTION_STD_CANCEL)
361 {
362 if (printcell_increment_column(lists, -1, true) != testput_cols - 1)
363 {
364 *action = ACTION_NONE;
365 }
366 }
367 else if (*action == ACTION_STD_CONTEXT)
368 {
369 char buf[PRINTCELL_MAXLINELEN];
370 char* bufp = buf;
371 bufp = printcell_get_selected_column_text(lists, bufp, PRINTCELL_MAXLINELEN);
372 rb->splashf(HZ * 2, "Item: %s", bufp);
373 }
374 }
375 else if (lists->data == MENU_ID(M_ACTTEST))
337 { 376 {
338 if (selected_item == 2) /* context */ 377 if (selected_item == 2) /* context */
339 { 378 {
340 int ctx = m_test.context; 379 int ctx = m_test.context;
341 if (action == ACTION_STD_OK) 380 if (*action == ACTION_STD_OK)
342 m_test.context++; 381 m_test.context++;
343 else if (action == ACTION_STD_CANCEL) 382 else if (*action == ACTION_STD_CANCEL)
344 m_test.context--; 383 m_test.context--;
345 384
346 if (m_test.context < 0) 385 if (m_test.context < 0)
@@ -353,7 +392,7 @@ int menu_action_cb(int action, int selected_item, bool* exit, struct gui_synclis
353 392
354 goto default_handler; 393 goto default_handler;
355 } 394 }
356 if (action == ACTION_STD_OK) 395 if (*action == ACTION_STD_OK)
357 { 396 {
358 if (selected_item == 1 || selected_item == 3) 397 if (selected_item == 1 || selected_item == 3)
359 { 398 {
@@ -364,7 +403,7 @@ int menu_action_cb(int action, int selected_item, bool* exit, struct gui_synclis
364 } 403 }
365 else if (lists->data == MENU_ID(M_BTNTEST)) 404 else if (lists->data == MENU_ID(M_BTNTEST))
366 { 405 {
367 if (action == ACTION_STD_OK) 406 if (*action == ACTION_STD_OK)
368 { 407 {
369 if (selected_item == 1 || selected_item == 2) 408 if (selected_item == 1 || selected_item == 2)
370 { 409 {
@@ -373,18 +412,38 @@ int menu_action_cb(int action, int selected_item, bool* exit, struct gui_synclis
373 } 412 }
374 } 413 }
375 } 414 }
376 if (action == ACTION_STD_OK) 415/* common */
416 if (*action == ACTION_STD_OK)
377 { 417 {
378 if (lists->data == MENU_ID(M_ROOT)) 418 if (lists->data == MENU_ID(M_ROOT))
379 { 419 {
380 rb->memset(&m_test, 0, sizeof(struct menu_test_t)); 420 rb->memset(&m_test, 0, sizeof(struct menu_test_t));
381 const struct mainmenu *cur = mainitem(selected_item); 421 const struct mainmenu *cur = mainitem(selected_item);
422
382 if (cur->menuid == NULL || cur->menuid == MENU_ID(M_EXIT)) 423 if (cur->menuid == NULL || cur->menuid == MENU_ID(M_EXIT))
383 *exit = true; 424 *exit = true;
384 else 425 else
385 { 426 {
386 main_last_sel = selected_item; 427 main_last_sel = selected_item;
387 synclist_set(cur->menuid, 1, cur->items, 1); 428
429 if (cur->menuid == MENU_ID(M_TESTPUT))
430 {
431 //rb->gui_list_screen_scroll_out_of_view(true);
432 synclist_set(cur->menuid, 0, cur->items, 1);
433#if LCD_DEPTH > 1
434 /* If line sep is set to automatic then outline cells */
435 bool showlinesep = (rb->global_settings->list_separator_height < 0);
436#else
437 bool showlinesep = (rb->global_settings->cursor_style == 0);
438#endif
439 printcell_enable(lists, true, showlinesep);
440 //lists->callback_draw_item = test_listdraw_fn;
441 }
442 else
443 {
444 printcell_enable(lists, false, false);
445 synclist_set(cur->menuid, 1, cur->items, 1);
446 }
388 rb->gui_synclist_draw(lists); 447 rb->gui_synclist_draw(lists);
389 } 448 }
390 } 449 }
@@ -394,7 +453,11 @@ int menu_action_cb(int action, int selected_item, bool* exit, struct gui_synclis
394 } 453 }
395 else if (selected_item >= (mainitem(main_last_sel)->items) - 1)/*back*/ 454 else if (selected_item >= (mainitem(main_last_sel)->items) - 1)/*back*/
396 { 455 {
397 action = ACTION_STD_CANCEL; 456 *action = ACTION_STD_CANCEL;
457 }
458 else if (lists->data == MENU_ID(M_TESTPUT))
459 {
460
398 } 461 }
399 else if (lists->data == MENU_ID(M_ACTIONS) || 462 else if (lists->data == MENU_ID(M_ACTIONS) ||
400 lists->data == MENU_ID(M_CONTEXTS)) 463 lists->data == MENU_ID(M_CONTEXTS))
@@ -406,8 +469,14 @@ int menu_action_cb(int action, int selected_item, bool* exit, struct gui_synclis
406 rb->button_get(true); 469 rb->button_get(true);
407 } 470 }
408 } 471 }
409 if (action == ACTION_STD_CANCEL) 472 if (*action == ACTION_STD_CANCEL)
410 { 473 {
474 if (lists->data == MENU_ID(M_TESTPUT))
475 {
476 //rb->gui_list_screen_scroll_out_of_view(false);
477 //lists->callback_draw_item = NULL;
478 printcell_enable(lists, false, false);
479 }
411 if (lists->data != MENU_ID(M_ROOT)) 480 if (lists->data != MENU_ID(M_ROOT))
412 { 481 {
413 const struct mainmenu *mainm = &mainmenu[0]; 482 const struct mainmenu *mainm = &mainmenu[0];
@@ -418,7 +487,7 @@ int menu_action_cb(int action, int selected_item, bool* exit, struct gui_synclis
418 *exit = true; 487 *exit = true;
419 } 488 }
420default_handler: 489default_handler:
421 if (rb->default_event_handler_ex(action, cleanup, NULL) == SYS_USB_CONNECTED) 490 if (rb->default_event_handler_ex(*action, cleanup, NULL) == SYS_USB_CONNECTED)
422 { 491 {
423 *exit = true; 492 *exit = true;
424 return PLUGIN_USB_CONNECTED; 493 return PLUGIN_USB_CONNECTED;
@@ -436,7 +505,14 @@ static void synclist_set(char* menu_id, int selected_item, int items, int sel_si
436 list_voice_cb(0, menu_id); 505 list_voice_cb(0, menu_id);
437 rb->gui_synclist_init(&lists,list_get_name_cb, 506 rb->gui_synclist_init(&lists,list_get_name_cb,
438 menu_id, false, sel_size, NULL); 507 menu_id, false, sel_size, NULL);
439 508 if (menu_id == MENU_ID(M_TESTPUT))
509 {
510 testput_cols = printcell_set_columns(&lists, TESTPUT_HEADER, Icon_Rockbox);
511 }
512 else
513 {
514 rb->gui_synclist_set_title(&lists, NULL,-1);
515 }
440 rb->gui_synclist_set_icon_callback(&lists,NULL); 516 rb->gui_synclist_set_icon_callback(&lists,NULL);
441 rb->gui_synclist_set_voice_callback(&lists, list_voice_cb); 517 rb->gui_synclist_set_voice_callback(&lists, list_voice_cb);
442 rb->gui_synclist_set_nb_items(&lists,items); 518 rb->gui_synclist_set_nb_items(&lists,items);
@@ -460,7 +536,7 @@ enum plugin_status plugin_start(const void* parameter)
460 /* add header and back item to each submenu */ 536 /* add header and back item to each submenu */
461 for (int i = 1; i < M_LAST_ITEM; i++) 537 for (int i = 1; i < M_LAST_ITEM; i++)
462 mainmenu[i].items += 2; 538 mainmenu[i].items += 2;
463 539 mainmenu[M_TESTPUT].items -= 1;
464 if (!exit) 540 if (!exit)
465 { 541 {
466 const struct mainmenu *mainm = &mainmenu[0]; 542 const struct mainmenu *mainm = &mainmenu[0];
@@ -483,10 +559,10 @@ enum plugin_status plugin_start(const void* parameter)
483 } 559 }
484 else 560 else
485 redraw = true; 561 redraw = true;
562 ret = menu_action_cb(&action, selected_item, &exit, &lists);
486 if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD)) 563 if (rb->gui_synclist_do_button(&lists,&action,LIST_WRAP_UNLESS_HELD))
487 continue; 564 continue;
488 selected_item = rb->gui_synclist_get_sel_pos(&lists); 565 selected_item = rb->gui_synclist_get_sel_pos(&lists);
489 ret = menu_action_cb(action, selected_item, &exit, &lists);
490 } 566 }
491 } 567 }
492 568