summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/keyremap.c29
-rw-r--r--apps/plugins/lastfm_scrobbler.c2
-rw-r--r--apps/plugins/lastfm_scrobbler_viewer.c1033
-rw-r--r--apps/plugins/lib/printcell_helper.c297
-rw-r--r--apps/plugins/lib/printcell_helper.h68
-rw-r--r--apps/plugins/rb_info.c35
-rw-r--r--apps/plugins/viewers.config1
9 files changed, 1356 insertions, 111 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index f2ab4843c2..cb0e407d31 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -50,6 +50,7 @@ keybox,apps
50keyremap,apps 50keyremap,apps
51lamp,apps 51lamp,apps
52lastfm_scrobbler,apps 52lastfm_scrobbler,apps
53lastfm_scrobbler_viewer,viewers
53logo,demos 54logo,demos
54lrcplayer,apps 55lrcplayer,apps
55lua,viewers 56lua,viewers
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index 85227d80d7..28a4bc38f5 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -13,6 +13,7 @@ jackpot.c
13keybox.c 13keybox.c
14keyremap.c 14keyremap.c
15lastfm_scrobbler.c 15lastfm_scrobbler.c
16lastfm_scrobbler_viewer.c
16logo.c 17logo.c
17lrcplayer.c 18lrcplayer.c
18mosaique.c 19mosaique.c
diff --git a/apps/plugins/keyremap.c b/apps/plugins/keyremap.c
index f0b36a735e..202d5fcfa4 100644
--- a/apps/plugins/keyremap.c
+++ b/apps/plugins/keyremap.c
@@ -1422,6 +1422,17 @@ static int list_voice_cb(int list_index, void* data)
1422 else 1422 else
1423 rb->talk_spell(name, true); 1423 rb->talk_spell(name, true);
1424 } 1424 }
1425 else if(data == MENU_ID(M_SETKEYS))
1426 {
1427 char buf[MAX_MENU_NAME];
1428 int selcol = printcell_get_column_selected();
1429 const char* name = printcell_get_column_text(selcol, buf, sizeof(buf));
1430 long id = P2ID((const unsigned char *)name);
1431 if(id>=0)
1432 rb->talk_id(id, true);
1433 else
1434 rb->talk_spell(name, true);
1435 }
1425 else 1436 else
1426 { 1437 {
1427 char buf[MAX_MENU_NAME]; 1438 char buf[MAX_MENU_NAME];
@@ -1606,14 +1617,14 @@ int menu_action_setkeys(int *action, int selected_item, bool* exit, struct gui_s
1606 } 1617 }
1607 else 1618 else
1608 { 1619 {
1609 keyset.view_lastcol = printcell_increment_column(lists, 1, true); 1620 keyset.view_lastcol = printcell_increment_column(1, true);
1610 *action = ACTION_NONE; 1621 *action = ACTION_NONE;
1611 } 1622 }
1612 } 1623 }
1613 } 1624 }
1614 else if (*action == ACTION_STD_CANCEL) 1625 else if (*action == ACTION_STD_CANCEL)
1615 { 1626 {
1616 keyset.view_lastcol = printcell_increment_column(lists, -1, true); 1627 keyset.view_lastcol = printcell_increment_column(-1, true);
1617 if (keyset.view_lastcol != keyset.view_columns - 1) 1628 if (keyset.view_lastcol != keyset.view_columns - 1)
1618 { 1629 {
1619 *action = ACTION_NONE; 1630 *action = ACTION_NONE;
@@ -2038,7 +2049,7 @@ static void synclist_set(int id, int selected_item, int items, int sel_size)
2038 rb->gui_synclist_set_voice_callback(&lists, list_voice_cb); 2049 rb->gui_synclist_set_voice_callback(&lists, list_voice_cb);
2039 rb->gui_synclist_set_nb_items(&lists,items); 2050 rb->gui_synclist_set_nb_items(&lists,items);
2040 rb->gui_synclist_select_item(&lists, selected_item); 2051 rb->gui_synclist_select_item(&lists, selected_item);
2041 printcell_enable(&lists, false, false); 2052 printcell_enable(false);
2042 2053
2043 if (menu_id == MENU_ID(M_ROOT)) 2054 if (menu_id == MENU_ID(M_ROOT))
2044 { 2055 {
@@ -2047,15 +2058,16 @@ static void synclist_set(int id, int selected_item, int items, int sel_size)
2047 } 2058 }
2048 else if (menu_id == MENU_ID(M_SETKEYS)) 2059 else if (menu_id == MENU_ID(M_SETKEYS))
2049 { 2060 {
2050 printcell_enable(&lists, true, true); 2061 keyset.view_columns = printcell_set_columns(&lists, NULL,
2051 keyset.view_columns = printcell_set_columns(&lists, ACTVIEW_HEADER, Icon_Rockbox); 2062 ACTVIEW_HEADER, Icon_Rockbox);
2052 int curcol = printcell_increment_column(&lists, 0, true); 2063 printcell_enable(true);
2064 int curcol = printcell_get_column_selected();
2053 if (keyset.view_lastcol >= keyset.view_columns) 2065 if (keyset.view_lastcol >= keyset.view_columns)
2054 keyset.view_lastcol = -1; 2066 keyset.view_lastcol = -1;
2055 /* restore column position */ 2067 /* restore column position */
2056 while (keyset.view_lastcol > -1 && curcol != keyset.view_lastcol) 2068 while (keyset.view_lastcol > -1 && curcol != keyset.view_lastcol)
2057 { 2069 {
2058 curcol = printcell_increment_column(&lists, 1, true); 2070 curcol = printcell_increment_column(1, true);
2059 } 2071 }
2060 keyset.view_lastcol = curcol; 2072 keyset.view_lastcol = curcol;
2061 } 2073 }
@@ -2065,9 +2077,8 @@ static void synclist_set(int id, int selected_item, int items, int sel_size)
2065 PEEK_MENU_ID(id); 2077 PEEK_MENU_ID(id);
2066 lang_strlcpy(menu_title, mainitem(id)->name, sizeof(menu_title)); 2078 lang_strlcpy(menu_title, mainitem(id)->name, sizeof(menu_title));
2067 rb->gui_synclist_set_title(&lists, menu_title, Icon_Submenu_Entered); 2079 rb->gui_synclist_set_title(&lists, menu_title, Icon_Submenu_Entered);
2068 /* if (menu_title[0] == '$'){ printcell_enable(&lists, true, true); } */ 2080 /* if (menu_title[0] == '$'){ printcell_enable(true); } */
2069 } 2081 }
2070
2071} 2082}
2072 2083
2073static void keyremap_set_buffer(void* buffer, size_t buf_size) 2084static void keyremap_set_buffer(void* buffer, size_t buf_size)
diff --git a/apps/plugins/lastfm_scrobbler.c b/apps/plugins/lastfm_scrobbler.c
index dce6be0d1e..c835533b1f 100644
--- a/apps/plugins/lastfm_scrobbler.c
+++ b/apps/plugins/lastfm_scrobbler.c
@@ -160,6 +160,8 @@ static int config_settings_menu(void)
160 case 3: 160 case 3:
161 rb->set_int("Beep Level", "", UNIT_INT, 161 rb->set_int("Beep Level", "", UNIT_INT,
162 &gConfig.beeplvl, NULL, 1, 0, 10, NULL); 162 &gConfig.beeplvl, NULL, 1, 0, 10, NULL);
163 if (gConfig.beeplvl > 0)
164 rb->beep_play(1500, 100, 100 * gConfig.beeplvl);
163 case 4: /*sep*/ 165 case 4: /*sep*/
164 continue; 166 continue;
165 case 5: 167 case 5:
diff --git a/apps/plugins/lastfm_scrobbler_viewer.c b/apps/plugins/lastfm_scrobbler_viewer.c
new file mode 100644
index 0000000000..8f533ef5f7
--- /dev/null
+++ b/apps/plugins/lastfm_scrobbler_viewer.c
@@ -0,0 +1,1033 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ /
5 * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) (
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2023 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#include "plugin.h"
23#include "lang_enum.h"
24
25#include "lib/printcell_helper.h"
26
27#include "lib/configfile.h"
28#define CFG_FILE "/lastfm_scrobbler_viewer.cfg"
29#define TMP_FILE ""PLUGIN_DATA_DIR "/lscrobbler_viewer_%d.tmp"
30#define CFG_VER 1
31
32#ifdef ROCKBOX_HAS_LOGF
33#define logf rb->logf
34#else
35#define logf(...) do { } while(0)
36#endif
37
38/*#ARTIST #ALBUM #TITLE #TRACKNUM #LENGTH #RATING #TIMESTAMP #MUSICBRAINZ_TRACKID*/
39
40#define SCROBBLE_HDR_FMT "$*%d$%s$*%d$%s$*%d$%s$Track#$Length$Rating$TimeStamp$TrackId"
41//#define SCROBBLE_HDR "$*128$Artist$*128$Album$*128$Title$Track#$Length$Rating$TimeStamp$TrackId"
42
43#define SCROBBLER_MIN_COLUMNS (6) /* a valid scrobbler file should have at least this many columns */
44
45#define GOTO_ACTION_DEFAULT_HANDLER (PLUGIN_OK + 1)
46#define CANCEL_CONTEXT_MENU (PLUGIN_OK + 2)
47#define QUIT_CONTEXT_MENU (PLUGIN_OK + 3)
48/* global lists, for everything */
49static struct gui_synclist lists;
50
51/* printcell data for the current file */
52struct printcell_data_t {
53 int view_columns;
54 int view_lastcol;
55
56 int items_buffered;
57 int items_total;
58 int fd_cur;
59 char *filename;
60
61 char *buf;
62 size_t buf_size;
63 off_t buf_used;
64 char header[PRINTCELL_MAXLINELEN];
65
66};
67
68enum e_find_type {
69 FIND_ALL = 0,
70 FIND_EXCLUDE,
71 FIND_EXCLUDE_CASE,
72 FIND_EXCLUDE_ANY,
73 FIND_INCLUDE,
74 FIND_INCLUDE_CASE,
75 FIND_INCLUDE_ANY,
76 FIND_CUSTOM,
77};
78
79static void synclist_set(int selected_item, int items, int sel_size, struct printcell_data_t *pc_data);
80static void pc_data_set_header(struct printcell_data_t *pc_data);
81
82static void browse_file(char *buf, size_t bufsz)
83{
84 struct browse_context browse = {
85 .dirfilter = SHOW_ALL,
86 .flags = BROWSE_SELECTONLY,
87 .title = "Select a scrobbler log file",
88 .icon = Icon_Playlist,
89 .buf = buf,
90 .bufsize = bufsz,
91 .root = "/",
92 };
93
94 if (rb->rockbox_browse(&browse) != GO_TO_PREVIOUS)
95 {
96 buf[0] = '\0';
97 }
98}
99
100static struct plugin_config
101{
102 bool separator;
103 bool talk;
104 int col_width;
105 uint32_t hidecol_flags;
106} gConfig;
107
108static struct configdata config[] =
109{
110 {TYPE_BOOL, 0, 1, { .bool_p = &gConfig.separator }, "Cell Separator", NULL},
111 {TYPE_BOOL, 0, 1, { .bool_p = &gConfig.talk }, "Voice", NULL},
112 {TYPE_INT, 32, LCD_WIDTH, { .int_p = &gConfig.col_width }, "Cell Width", NULL},
113 {TYPE_INT, INT_MIN, INT_MAX, { .int_p = &gConfig.hidecol_flags }, "Hidden Columns", NULL},
114};
115const int gCfg_sz = sizeof(config)/sizeof(*config);
116/****************** config functions *****************/
117static void config_set_defaults(void)
118{
119 gConfig.col_width = MIN(LCD_WIDTH, 128);
120 gConfig.hidecol_flags = 0;
121 gConfig.separator = true;
122 gConfig.talk = rb->global_settings->talk_menu;
123}
124
125static void config_save(void)
126{
127 configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER);
128}
129
130static int config_settings_menu(struct printcell_data_t *pc_data)
131{
132 int selection = 0;
133
134 struct viewport parentvp[NB_SCREENS];
135 FOR_NB_SCREENS(l)
136 {
137 rb->viewport_set_defaults(&parentvp[l], l);
138 rb->viewport_set_fullscreen(&parentvp[l], l);
139 }
140
141 MENUITEM_STRINGLIST(settings_menu, ID2P(LANG_SETTINGS), NULL,
142 ID2P(LANG_LIST_SEPARATOR),
143 "Cell Width",
144 ID2P(LANG_VOICE),
145 ID2P(VOICE_BLANK),
146 ID2P(VOICE_BLANK),
147 ID2P(LANG_CANCEL_0),
148 ID2P(LANG_SAVE_EXIT));
149
150 do {
151 selection=rb->do_menu(&settings_menu,&selection, parentvp, true);
152 switch(selection) {
153
154 case 0:
155 rb->set_bool(rb->str(LANG_LIST_SEPARATOR), &gConfig.separator);
156 break;
157 case 1:
158 rb->set_int("Cell Width", "", UNIT_INT,
159 &gConfig.col_width, NULL, 1, 32, LCD_WIDTH, NULL );
160 break;
161 case 2:
162 rb->set_bool(rb->str(LANG_VOICE), &gConfig.talk);
163 break;
164 case 3:
165 continue;
166 case 4: /*sep*/
167 continue;
168 case 5:
169 return -1;
170 break;
171 case 6:
172 {
173 pc_data_set_header(pc_data);
174 synclist_set(0, pc_data->items_total, 1, pc_data);
175 int res = configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER);
176 if (res >= 0)
177 {
178 logf("Cfg saved %s %d bytes", CFG_FILE, gCfg_sz);
179 return PLUGIN_OK;
180 }
181 logf("Cfg FAILED (%d) %s", res, CFG_FILE);
182 return PLUGIN_ERROR;
183 }
184 case MENU_ATTACHED_USB:
185 return PLUGIN_USB_CONNECTED;
186 default:
187 return PLUGIN_OK;
188 }
189 } while ( selection >= 0 );
190 return 0;
191}
192
193/* open file pass back file descriptor and return file size */
194static size_t file_open(const char *filename, int *fd)
195{
196 size_t fsize = 0;
197
198 if (filename && fd)
199 {
200 *fd = rb->open(filename, O_RDONLY);
201 if (*fd >= 0)
202 {
203 fsize = rb->filesize(*fd);
204 }
205 }
206 return fsize;
207}
208
209static const char* list_get_name_cb(int selected_item, void* data,
210 char* buf, size_t buf_len)
211{
212 const int slush_pos = 32; /* entries around the current entry to keep buffered */
213 /* keep track of the last position in the buffer */
214 static int buf_line_num = 0;
215 static off_t buf_last_pos = 0;
216 /* keep track of the last position in the file */
217 static int file_line_num = 0;
218 static off_t file_last_seek = 0;
219
220 if (selected_item < 0)
221 {
222 logf("[%s] Reset positions", __func__);
223 buf_line_num = 0;
224 buf_last_pos = 0;
225 file_line_num = 0;
226 file_last_seek = 0;
227 return "";
228 }
229
230 int line_num;
231 struct printcell_data_t *pc_data = (struct printcell_data_t*) data;
232 bool found = false;
233
234 if (pc_data->buf && selected_item < pc_data->items_buffered)
235 {
236 int buf_pos;
237
238 if (buf_line_num > selected_item || buf_last_pos >= pc_data->buf_used
239 || buf_line_num < 0)
240 {
241 logf("[%s] Set pos buffer 0", __func__);
242 buf_line_num = 0;
243 buf_last_pos = 0;
244 }
245 buf_pos = buf_last_pos;
246 line_num = buf_line_num;
247
248 while (buf_pos < pc_data->buf_used
249 && line_num < pc_data->items_buffered)
250 {
251 size_t len = rb->strlen(&pc_data->buf[buf_pos]);
252 if(line_num == selected_item)
253 {
254 rb->strlcpy(buf, &pc_data->buf[buf_pos], MIN(buf_len, len));
255 logf("(%d) in buffer: %s", line_num, buf);
256 found = true;
257 break;
258 }
259 else
260 {
261 buf_pos += len + 1; /* need to go past the NULL terminator */
262 line_num++;
263
264 if (buf_line_num + slush_pos < selected_item)
265 {
266 logf("[%s] Set pos buffer %d", __func__, line_num);
267 buf_line_num = line_num;
268 buf_last_pos = buf_pos;
269 }
270 }
271 }
272 }
273
274 /* didn't find the item try the file */
275 if(!found && pc_data->fd_cur >= 0)
276 {
277 int fd = pc_data->fd_cur;
278
279 if (file_line_num < 0 || file_line_num > selected_item)
280 {
281 logf("[%s] Set seek file 0", __func__);
282 file_line_num = 0;
283 file_last_seek = 0;
284 }
285
286 rb->lseek(fd, file_last_seek, SEEK_SET);
287 line_num = file_line_num;
288
289 while ((rb->read_line(fd, buf, buf_len)) > 0)
290 {
291 if(buf[0] == '#')
292 continue;
293 if(line_num == selected_item)
294 {
295 logf("(%d) in file: %s", line_num, buf);
296 found = true;
297 break;
298 }
299 else
300 {
301 line_num++;
302
303 if (file_line_num + slush_pos < selected_item)
304 {
305 logf("[%s] Set seek file %d", __func__, line_num);
306 file_line_num = line_num;
307 file_last_seek = rb->lseek(fd, 0, SEEK_CUR);
308 }
309 }
310 }
311 }
312
313 if(!found)
314 {
315 logf("(%d) Not Found!", selected_item);
316 buf_line_num = -1;
317 file_line_num = -1;
318 buf[0] = '\0';
319 }
320 return buf;
321}
322
323static int list_voice_cb(int list_index, void* data)
324{
325 (void) list_index;
326 struct printcell_data_t *pc_data = (struct printcell_data_t*) data;
327 if (!gConfig.talk)
328 return -1;
329
330 int selcol = printcell_get_column_selected();
331 char buf[MAX_PATH];
332 char* name;
333 long id;
334
335 if (pc_data->view_lastcol != selcol)
336 {
337 name = printcell_get_title_text(selcol, buf, sizeof(buf));
338
339 id = P2ID((const unsigned char *)name);
340
341 if(id>=0)
342 rb->talk_id(id, true);
343 else if (selcol >= 0)
344 {
345 switch (selcol)
346 {
347 case 0:
348 rb->talk_id(LANG_ID3_ARTIST, true);
349 break;
350 case 1:
351 rb->talk_id(LANG_ID3_ALBUM, true);
352 break;
353 case 2:
354 rb->talk_id(LANG_ID3_TITLE, true);
355 break;
356 case 3:
357 rb->talk_id(LANG_ID3_TRACKNUM, true);
358 break;
359 case 4:
360 rb->talk_id(LANG_ID3_LENGTH, true);
361 break;
362
363 default:
364 rb->talk_spell(name, true);
365 break;
366 }
367 }
368 else
369 rb->talk_id(LANG_ALL, true);
370
371 rb->talk_id(VOICE_PAUSE, true);
372 }
373
374 name = printcell_get_column_text(selcol, buf, sizeof(buf));
375
376 id = P2ID((const unsigned char *)name);
377
378 if(id>=0)
379 rb->talk_id(id, true);
380 else if (selcol >= 0)
381 rb->talk_spell(name, true);
382
383 return 0;
384}
385
386static enum themable_icons list_icon_cb(int selected_item, void *data)
387{
388 struct printcell_data_t *pc_data = (struct printcell_data_t*) data;
389 if (lists.selected_item == selected_item)
390 {
391 if (pc_data->view_lastcol < 0)
392 return Icon_Config;
393 return Icon_Audio;
394 }
395 return Icon_NOICON;
396}
397
398/* load file entries into pc_data buffer, file should already be opened
399 * and will be closed if the whole file was buffered */
400static int file_load_entries(struct printcell_data_t *pc_data)
401{
402 int items = 0;
403 int count = 0;
404 int buffered = 0;
405 unsigned int pos = 0;
406 bool comment = false;
407 char ch;
408 int fd = pc_data->fd_cur;
409 if (fd < 0)
410 return 0;
411
412 rb->lseek(fd, 0, SEEK_SET);
413
414 while (rb->read(fd, &ch, 1) > 0)
415 {
416 if (count++ == 0 && ch == '#') /* skip comments */
417 comment = true;
418 else if (!comment && ch != '\r' && pc_data->buf_size > pos)
419 pc_data->buf[pos++] = ch;
420
421 if (items == 0 && pos > PRINTCELL_MAXLINELEN * 2)
422 break;
423
424 if (ch == '\n')
425 {
426 if (!comment)
427 {
428 pc_data->buf[pos] = '\0';
429 if (pc_data->buf_size > pos)
430 {
431 pos++;
432 buffered++;
433 }
434 items++;
435 }
436 comment = false;
437 count = 0;
438 rb->yield();
439 }
440 }
441
442 logf("[%s] items: %d buffered: %d", __func__, items, buffered);
443
444 pc_data->items_total = items;
445 pc_data->items_buffered = buffered;
446 pc_data->buf[pos] = '\0';
447 pc_data->buf_used = pos;
448
449 if (items == buffered) /* whole file fit into buffer; close file */
450 {
451 rb->close(pc_data->fd_cur);
452 pc_data->fd_cur = -1;
453 }
454
455 list_get_name_cb(-1, NULL, NULL, 0); /* prime name cb */
456 return items;
457}
458
459static int filter_items(struct printcell_data_t *pc_data,
460 enum e_find_type find_type, int col)
461{
462 /* saves filtered items to a temp file and loads it */
463 int fd;
464 bool reload = false;
465 char buf[PRINTCELL_MAXLINELEN];
466 char find_exclude_buf[PRINTCELL_MAXLINELEN];
467 int selcol = printcell_get_column_selected();
468 char *find_exclude = printcell_get_column_text(selcol, find_exclude_buf,
469 sizeof(find_exclude_buf));
470 const char colsep = '\t';
471 int find_len = strlen(find_exclude);
472
473 if (find_type == FIND_CUSTOM || find_len == 0)
474 {
475 int option = 0;
476 struct opt_items find_types[] = {
477 {"Exclude", -1}, {"Exclude Case Sensitive", -1},
478 {"Exclude Any", -1}, {"Include", -1},
479 {"Include Case Sensitive", -1}, {"Include Any", -1}
480 };
481 if (rb->set_option("Find Type", &option, INT,
482 find_types, 6, NULL))
483 {
484 return 0;
485 }
486 switch (option)
487 {
488 case 0:
489 find_type = FIND_EXCLUDE;
490 break;
491 case 1:
492 find_type = FIND_EXCLUDE_CASE;
493 break;
494 case 2:
495 find_type = FIND_EXCLUDE_ANY;
496 break;
497 case 3:
498 find_type = FIND_INCLUDE;
499 break;
500 case 4:
501 find_type = FIND_INCLUDE_CASE;
502 break;
503 case 5:
504 find_type = FIND_INCLUDE_ANY;
505 break;
506 default:
507 find_type = FIND_ALL;
508 break;
509 }
510
511 /* copy data to beginning of buf */
512 rb->memmove(find_exclude_buf, find_exclude, find_len);
513 find_exclude_buf[find_len] = '\0';
514
515 if (rb->kbd_input(find_exclude_buf, sizeof(find_exclude_buf), NULL) < 0)
516 return -1;
517 find_exclude = find_exclude_buf;
518 find_len = strlen(find_exclude);
519 }
520
521 char tmp_filename[MAX_PATH];
522 static int tmp_num = 0;
523 rb->snprintf(tmp_filename, sizeof(tmp_filename), TMP_FILE, tmp_num);
524 tmp_num++;
525
526 fd = rb->open(tmp_filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
527 if(fd >= 0)
528 {
529 rb->splash_progress_set_delay(HZ * 5);
530 for (int i = 0; i < pc_data->items_total; i++)
531 {
532 rb->splash_progress(i, pc_data->items_total, "Filtering...");
533 const char * data = list_get_name_cb(i, pc_data, buf, sizeof(buf));
534
535 if (find_type != FIND_ALL)
536 {
537 int index = col;
538
539 if (index < 0)
540 index = 0;
541 if (find_len > 0)
542 {
543 char *bcol = buf;
544 while (*bcol != '\0' && index > 0)
545 {
546 if (*bcol == colsep)
547 index--;
548 bcol++;
549 }
550 if (index > 0)
551 continue;
552
553 if (find_type == FIND_EXCLUDE)
554 {
555 if (rb->strncasecmp(bcol, find_exclude, find_len) == 0)
556 {
557 logf("[%s] exclude [%s]", find_exclude, bcol);
558 continue;
559 }
560 }
561 else if (find_type == FIND_INCLUDE)
562 {
563 if (rb->strncasecmp(bcol, find_exclude, find_len) != 0)
564 {
565 logf("%s include %s", find_exclude, bcol);
566 continue;
567 }
568 }
569 else if (find_type == FIND_EXCLUDE_CASE)
570 {
571 if (rb->strncmp(bcol, find_exclude, find_len) == 0)
572 {
573 logf("[%s] exclude case [%s]", find_exclude, bcol);
574 continue;
575 }
576 }
577 else if (find_type == FIND_INCLUDE_CASE)
578 {
579 if (rb->strncmp(bcol, find_exclude, find_len) != 0)
580 {
581 logf("%s include case %s", find_exclude, bcol);
582 continue;
583 }
584 }
585 else if (find_type == FIND_EXCLUDE_ANY)
586 {
587 bool found = false;
588 while (*bcol != '\0' && *bcol != colsep)
589 {
590 if (rb->strncasecmp(bcol, find_exclude, find_len) == 0)
591 {
592 logf("[%s] exclude any [%s]", find_exclude, bcol);
593 found = true;
594 break;
595 }
596 bcol++;
597 }
598 if (found)
599 continue;
600 }
601 else if (find_type == FIND_INCLUDE_ANY)
602 {
603 bool found = false;
604 while (*bcol != '\0' && *bcol != colsep)
605 {
606 if (rb->strncasecmp(bcol, find_exclude, find_len) == 0)
607 {
608 found = true;
609 logf("[%s] include any [%s]", find_exclude, bcol);
610 break;
611 }
612 bcol++;
613 }
614 if (!found)
615 continue;
616 }
617 }
618 }
619 int len = strlen(data);
620 if (len > 0)
621 {
622 logf("writing [%d bytes][%s]", len + 1, data);
623 rb->write(fd, data, len);
624 rb->write(fd, "\n", 1);
625 }
626 }
627 reload = true;
628 }
629
630 if (reload)
631 {
632 if (pc_data->fd_cur >= 0)
633 rb->close(pc_data->fd_cur);
634
635 pc_data->fd_cur = fd;
636 int items = file_load_entries(pc_data);
637 if (items >= 0)
638 {
639 lists.selected_item = 0;
640 rb->gui_synclist_set_nb_items(&lists, items);
641 }
642 }
643 logf("Col text '%s'", find_exclude);
644 logf("text '%s'", find_exclude_buf);
645
646 return pc_data->items_total;
647}
648
649static int scrobbler_context_menu(struct printcell_data_t *pc_data)
650{
651 struct viewport parentvp[NB_SCREENS];
652 FOR_NB_SCREENS(l)
653 {
654 rb->viewport_set_defaults(&parentvp[l], l);
655 rb->viewport_set_fullscreen(&parentvp[l], l);
656 }
657
658 int col = printcell_get_column_selected();
659 int selection = 0;
660 int items = 0;
661 uint32_t visible = printcell_get_column_visibility(-1);
662 bool hide_col = PRINTCELL_COLUMN_IS_VISIBLE(visible, col);
663
664 char namebuf[PRINTCELL_MAXLINELEN];
665 enum e_find_type find_type = FIND_ALL;
666
667 char *colname = pc_data->filename;
668 if (col >= 0)
669 colname = printcell_get_title_text(col, namebuf, sizeof(namebuf));
670
671#define MENUITEM_STRINGLIST_CUSTOM(name, str, callback, ... ) \
672 const char *name##_[] = {__VA_ARGS__}; \
673 const struct menu_callback_with_desc name##__ = \
674 {callback,str, Icon_NOICON}; \
675 const struct menu_item_ex name = \
676 {MT_RETURN_ID|MENU_HAS_DESC| \
677 MENU_ITEM_COUNT(sizeof( name##_)/sizeof(*name##_)), \
678 { .strings = name##_},{.callback_and_desc = & name##__}};
679
680 const char *menu_item[4];
681
682 menu_item[0]= hide_col ? "Hide":"Show";
683 menu_item[1]= "Exclude";
684 menu_item[2]= "Include";
685 menu_item[3]= "Custom Filter";
686
687 if (col == -1)
688 {
689 menu_item[0]= hide_col ? "Hide All":"Show All";
690 menu_item[1]= "Open";
691 menu_item[2]= "Reload";
692 menu_item[3]= ID2P(LANG_SETTINGS);
693 }
694
695 MENUITEM_STRINGLIST_CUSTOM(context_menu, colname, NULL,
696 menu_item[0],
697 menu_item[1],
698 menu_item[2],
699 menu_item[3],
700 ID2P(VOICE_BLANK),
701 ID2P(LANG_CANCEL_0),
702 ID2P(LANG_MENU_QUIT));
703
704#undef MENUITEM_STRINGLIST_CUSTOM
705 do {
706 selection=rb->do_menu(&context_menu,&selection, parentvp, true);
707 switch(selection) {
708
709 case 0:
710 {
711 printcell_set_column_visible(col, !hide_col);
712 if (hide_col)
713 {
714 do
715 {
716 col = printcell_increment_column(1, true);
717 } while (col >= 0 && printcell_get_column_visibility(col) == 1);
718 pc_data->view_lastcol = col;
719 }
720 gConfig.hidecol_flags = printcell_get_column_visibility(-1);
721 break;
722 }
723 case 1: /* Exclude / Open */
724 {
725 if (col == -1)/*Open*/
726 {
727 char buf[MAX_PATH];
728 browse_file(buf, sizeof(buf));
729 if (rb->file_exists(buf))
730 {
731 rb->strlcpy(pc_data->filename, buf, MAX_PATH);
732 if (pc_data->fd_cur >= 0)
733 rb->close(pc_data->fd_cur);
734 if (file_open(pc_data->filename, &pc_data->fd_cur) > 0)
735 items = file_load_entries(pc_data);
736 if (items >= 0)
737 synclist_set(0, items, 1, pc_data);
738 }
739 else
740 rb->splash(HZ *2, "Error Opening");
741
742 return CANCEL_CONTEXT_MENU;
743 }
744
745 find_type = FIND_EXCLUDE;
746 }
747 /* fall-through */
748 case 2: /* Include / Reload */
749 {
750 if (col == -1) /*Reload*/
751 {
752 if (pc_data->fd_cur >= 0)
753 rb->close(pc_data->fd_cur);
754 if (file_open(pc_data->filename, &pc_data->fd_cur) > 0)
755 items = file_load_entries(pc_data);
756 if (items >= 0)
757 rb->gui_synclist_set_nb_items(&lists, items);
758 return CANCEL_CONTEXT_MENU;
759 }
760
761 if (find_type == FIND_ALL)
762 find_type = FIND_INCLUDE;
763 /* fall-through */
764 }
765 case 3: /*Custom Filter / Settings */
766 {
767 if (col == -1)/*Settings*/
768 return config_settings_menu(pc_data);
769
770 if (find_type == FIND_ALL)
771 find_type = FIND_CUSTOM;
772 items = filter_items(pc_data, find_type, col);
773
774 if (items >= 0)
775 rb->gui_synclist_set_nb_items(&lists, items);
776 break;
777 }
778 case 4: /*sep*/
779 continue;
780 case 5:
781 return CANCEL_CONTEXT_MENU;
782 break;
783 case 6: /* Quit */
784 return QUIT_CONTEXT_MENU;
785 break;
786 case MENU_ATTACHED_USB:
787 return PLUGIN_USB_CONNECTED;
788 default:
789 return PLUGIN_OK;
790 }
791 } while ( selection < 0 );
792 return 0;
793}
794
795static void cleanup(void *parameter)
796{
797 struct printcell_data_t *pc_data = (struct printcell_data_t*) parameter;
798 if (pc_data->fd_cur >= 0)
799 rb->close(pc_data->fd_cur);
800 pc_data->fd_cur = -1;
801}
802
803static void menu_action_printcell(int *action, int selected_item, bool* exit, struct gui_synclist *lists)
804{
805 (void) exit;
806 struct printcell_data_t *pc_data = (struct printcell_data_t*) lists->data;
807 if (*action == ACTION_STD_OK)
808 {
809 if (selected_item < lists->nb_items)
810 {
811 pc_data->view_lastcol = printcell_increment_column(1, true);
812 *action = ACTION_NONE;
813 }
814 }
815 else if (*action == ACTION_STD_CANCEL)
816 {
817 pc_data->view_lastcol = printcell_increment_column(-1, true);
818 if (pc_data->view_lastcol != pc_data->view_columns - 1)
819 {
820 *action = ACTION_NONE;
821 }
822 }
823 else if (*action == ACTION_STD_CONTEXT)
824 {
825 int ctxret = scrobbler_context_menu(pc_data);
826 if (ctxret == QUIT_CONTEXT_MENU)
827 *exit = true;
828 }
829}
830
831int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_synclist *lists)
832{
833
834 menu_action_printcell(action, selected_item, exit, lists);
835
836 if (rb->default_event_handler_ex(*action, cleanup, lists->data) == SYS_USB_CONNECTED)
837 {
838 *exit = true;
839 return PLUGIN_USB_CONNECTED;
840 }
841 return PLUGIN_OK;
842}
843
844static int count_max_columns(int items, char delimeter,
845 int expected_cols, struct printcell_data_t *pc_data)
846{
847 int max_cols = 0;
848 int cols = 0;
849 char buf[PRINTCELL_MAXLINELEN];
850 for (int i = 0; i < items; i++)
851 {
852 const char *txt = list_get_name_cb(i, pc_data, buf, sizeof(buf));
853 while (*txt != '\0')
854 {
855 if (*txt == delimeter)
856 {
857 cols++;
858 if (cols == expected_cols)
859 {
860 max_cols = cols;
861 break;
862 }
863 }
864 txt++;
865 }
866
867 if(max_cols < expected_cols && i > 32)
868 break;
869
870 if (cols > max_cols)
871 max_cols = cols;
872 cols = 0;
873 }
874 return max_cols;
875}
876
877static void synclist_set(int selected_item, int items, int sel_size, struct printcell_data_t *pc_data)
878{
879 if (items <= 0)
880 return;
881 if (selected_item < 0)
882 selected_item = 0;
883
884 rb->gui_synclist_init(&lists,list_get_name_cb,
885 pc_data, false, sel_size, NULL);
886
887 rb->gui_synclist_set_icon_callback(&lists, list_icon_cb);
888 rb->gui_synclist_set_voice_callback(&lists, list_voice_cb);
889 rb->gui_synclist_set_nb_items(&lists,items);
890 rb->gui_synclist_select_item(&lists, selected_item);
891
892 struct printcell_settings pcs = {.cell_separator = gConfig.separator,
893 .title_delimeter = '$',
894 .text_delimeter = '\t',
895 .hidecol_flags = gConfig.hidecol_flags};
896
897 pc_data->view_columns = printcell_set_columns(&lists, &pcs,
898 pc_data->header, Icon_Rockbox);
899 printcell_enable(true);
900
901
902 int max_cols = count_max_columns(items, pcs.text_delimeter,
903 SCROBBLER_MIN_COLUMNS, pc_data);
904 if (max_cols < SCROBBLER_MIN_COLUMNS) /* not a scrobbler file? */
905 {
906 rb->gui_synclist_set_voice_callback(&lists, NULL);
907 pc_data->view_columns = printcell_set_columns(&lists, NULL,
908 "$*512$", Icon_Questionmark);
909 }
910
911 int curcol = printcell_get_column_selected();
912 while (curcol >= 0)
913 curcol = printcell_increment_column(-1, false);
914
915 if (pc_data->view_lastcol >= pc_data->view_columns)
916 pc_data->view_lastcol = -1;
917
918 /* restore column position */
919 while (pc_data->view_lastcol > -1 && curcol != pc_data->view_lastcol)
920 {
921 curcol = printcell_increment_column(1, true);
922 }
923 pc_data->view_lastcol = curcol;
924 list_voice_cb(0, pc_data);
925}
926
927static void pc_data_set_header(struct printcell_data_t *pc_data)
928{
929 int col_w = gConfig.col_width;
930 rb->snprintf(pc_data->header, PRINTCELL_MAXLINELEN,
931 SCROBBLE_HDR_FMT, col_w, rb->str(LANG_ID3_ARTIST),
932 col_w, rb->str(LANG_ID3_ALBUM),
933 col_w, rb->str(LANG_ID3_TITLE));
934}
935
936enum plugin_status plugin_start(const void* parameter)
937{
938 int ret = PLUGIN_OK;
939 int selected_item = -1;
940 int action;
941 int items = 0;
942#if CONFIG_RTC
943 static char filename[MAX_PATH] = HOME_DIR "/.scrobbler.log";
944#else /* !CONFIG_RTC */
945 static char filename[MAX_PATH] = HOME_DIR "/.scrobbler-timeless.log";
946#endif /* CONFIG_RTC */
947 bool redraw = true;
948 bool exit = false;
949
950 static struct printcell_data_t printcell_data;
951
952 if (parameter)
953 {
954 rb->strlcpy(filename, (const char*)parameter, MAX_PATH);
955 filename[MAX_PATH - 1] = '\0';
956 }
957
958 if (!rb->file_exists(filename))
959 {
960 browse_file(filename, sizeof(filename));
961 if (!rb->file_exists(filename))
962 {
963 rb->splash(HZ, "No Scrobbler file Goodbye.");
964 return PLUGIN_ERROR;
965 }
966
967 }
968
969 config_set_defaults();
970 if (configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER) < 0)
971 {
972 /* If the loading failed, save a new config file */
973 config_set_defaults();
974 configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER);
975
976 rb->splash(HZ, ID2P(LANG_REVERT_TO_DEFAULT_SETTINGS));
977 }
978
979 rb->memset(&printcell_data, 0, sizeof (struct printcell_data_t));
980 printcell_data.fd_cur = -1;
981 printcell_data.view_lastcol = -1;
982
983 if (rb->file_exists(filename))
984 {
985 if (file_open(filename, &printcell_data.fd_cur) == 0)
986 printcell_data.fd_cur = -1;
987 else
988 {
989 size_t buf_size;
990 printcell_data.buf = rb->plugin_get_buffer(&buf_size);
991 printcell_data.buf_size = buf_size;
992 printcell_data.buf_used = 0;
993 printcell_data.filename = filename;
994 items = file_load_entries(&printcell_data);
995 }
996 }
997 int col_w = gConfig.col_width;
998 rb->snprintf(printcell_data.header, PRINTCELL_MAXLINELEN,
999 SCROBBLE_HDR_FMT, col_w, rb->str(LANG_ID3_ARTIST),
1000 col_w, rb->str(LANG_ID3_ALBUM),
1001 col_w, rb->str(LANG_ID3_TITLE));
1002
1003 if (!exit && items > 0)
1004 {
1005 synclist_set(0, items, 1, &printcell_data);
1006 rb->gui_synclist_draw(&lists);
1007
1008 while (!exit)
1009 {
1010 action = rb->get_action(CONTEXT_LIST, HZ / 10);
1011
1012 if (action == ACTION_NONE)
1013 {
1014 if (redraw)
1015 {
1016 action = ACTION_REDRAW;
1017 redraw = false;
1018 }
1019 }
1020 else
1021 redraw = true;
1022
1023 ret = menu_action_cb(&action, selected_item, &exit, &lists);
1024 if (rb->gui_synclist_do_button(&lists, &action))
1025 continue;
1026 selected_item = rb->gui_synclist_get_sel_pos(&lists);
1027
1028 }
1029 }
1030 config_save();
1031 cleanup(&printcell_data);
1032 return ret;
1033}
diff --git a/apps/plugins/lib/printcell_helper.c b/apps/plugins/lib/printcell_helper.c
index 42de444c57..48b8b2c9d2 100644
--- a/apps/plugins/lib/printcell_helper.c
+++ b/apps/plugins/lib/printcell_helper.c
@@ -22,10 +22,6 @@
22#include "plugin.h" 22#include "plugin.h"
23#include "lib/printcell_helper.h" 23#include "lib/printcell_helper.h"
24 24
25#ifndef PRINTCELL_MAX_COLUMNS
26#define PRINTCELL_MAX_COLUMNS 16
27#endif
28
29#define COLUMN_ENDLEN 3 25#define COLUMN_ENDLEN 3
30#define TITLE_FLAG 0xFF 26#define TITLE_FLAG 0xFF
31#define SELECTED_FLAG 0x1 27#define SELECTED_FLAG 0x1
@@ -37,48 +33,54 @@
37#endif 33#endif
38 34
39struct printcell_info_t { 35struct printcell_info_t {
40 int offw[NB_SCREENS]; 36 struct gui_synclist *gui_list; /* list to display */
41 int iconw[NB_SCREENS]; 37 int offw[NB_SCREENS]; /* padding between column boundries and text */
42 int selcol_offw[NB_SCREENS]; 38 int iconw[NB_SCREENS]; /* width of an icon */
43 int totalcolw[NB_SCREENS]; 39 int selcol_offw[NB_SCREENS]; /* offset width calculated for selected item */
44 int firstcolxw[NB_SCREENS]; 40 int totalcolw[NB_SCREENS]; /* total width of all columns */
45 uint16_t colw[NB_SCREENS][PRINTCELL_MAX_COLUMNS]; 41 int firstcolxw[NB_SCREENS]; /* first column x + width, save recalculating */
46 int ncols; 42 int ncols; /* number of columns */
47 int selcol; 43 int selcol; /* selected column (-1 to ncols-1) */
48 int selcol_index; 44 uint32_t hidecol_flags; /*bits 0-31 set bit to 1 to hide a column (1<<col#) */
49 char title[PRINTCELL_MAXLINELEN]; 45 uint16_t colw[NB_SCREENS][PRINTCELL_MAX_COLUMNS]; /* width of title text
50 bool separator; 46 or MIN(or user defined width / screen width) */
47 char title[PRINTCELL_MAXLINELEN]; /* title buffer */
48 char titlesep; /* character that separates title column items (ex '$') */
49 char colsep; /* character that separates text column items (ex ',') */
50 bool separator; /* draw grid */
51}; 51};
52
52static struct printcell_info_t printcell; 53static struct printcell_info_t printcell;
53 54
54static void parse_dsptext(int ncols, const char *dsp_text, char* buffer, uint16_t *sidx) 55static void parse_dsptext(char splitchr, int ncols, const char *dsp_text,
56 char* buffer, size_t bufsz, uint16_t *sidx)
55{ 57{
56 /*Internal function loads sidx with split offsets indexing 58 /*Internal function loads sidx with split offsets indexing
57 the buffer of null terminated strings, splits on '$' 59 the buffer of null terminated strings, splits on 'splitchr'
58 _assumptions_: 60 _assumptions_:
59 dsp_text[len - 1] = \0, 61 dsp_text[len - 1] = \0,
60 buffer[PRINTCELL_MAXLINELEN],
61 sidx[PRINTCELL_MAX_COLUMNS] 62 sidx[PRINTCELL_MAX_COLUMNS]
62 */ 63 */
63 int i = 0; 64 int i = 0;
64 int j = 0; 65 size_t j = 0;
65 int ch = '$'; /* first column $ is optional */ 66 int ch = splitchr; /* first column $ is optional */
66 if (*dsp_text == '$') 67 if (*dsp_text == splitchr)
67 dsp_text++; 68 dsp_text++;
68 /* add null to the start of the text buffer */ 69 /* add null to the start of the text buffer */
69 buffer[j++] = '\0'; 70 buffer[j++] = '\0';
70 do 71 do
71 { 72 {
72 if (ch == '$') 73 if (ch == splitchr)
73 { 74 {
74 sidx[i] = j; 75 sidx[i] = j; /* save start index and copy next column to the buffer */
75 if (*dsp_text == '$') /* $$ escaped user must want to display $*/ 76 while (*dsp_text != '\0' && *dsp_text != splitchr && j < (bufsz - 1))
76 buffer[j++] = *dsp_text++; 77 {
77 while (*dsp_text != '\0' && *dsp_text != '$' && j < PRINTCELL_MAXLINELEN - 1)
78 buffer[j++] = *dsp_text++; 78 buffer[j++] = *dsp_text++;
79 }
79 buffer[j++] = '\0'; 80 buffer[j++] = '\0';
81
80 i++; 82 i++;
81 if (i >= ncols || j >= (PRINTCELL_MAXLINELEN - 1)) 83 if (i >= ncols || j >= (bufsz - 1))
82 break; 84 break;
83 } 85 }
84 ch = *dsp_text++; 86 ch = *dsp_text++;
@@ -146,23 +148,39 @@ static inline void set_cell_width(struct viewport *vp, int max_w, int new_w)
146static inline int printcells(struct screen *display, char* buffer, 148static inline int printcells(struct screen *display, char* buffer,
147 uint16_t *sidx, struct line_desc *linedes, 149 uint16_t *sidx, struct line_desc *linedes,
148 struct viewport *vp, int vp_w, int separator, 150 struct viewport *vp, int vp_w, int separator,
149 int x, int y, int offw, int selected_flag, bool scroll) 151 int x, int y, int offw, int selected_flag, int last_col,
152 bool scroll, bool is_title)
150{ 153{
151 /* Internal function prints remaining cells */ 154 /* Internal function prints remaining cells */
152 int text_offset = offw + offw; 155 int text_offset = offw + offw;
153 int ncols = printcell.ncols;
154 int screen = display->screen_type; 156 int screen = display->screen_type;
155 int height = linedes->height; 157 int height = linedes->height;
156 int selsep = (selected_flag == 0) ? 0: separator; 158 int selsep = (selected_flag == 0) ? 0: separator;
157 uint16_t *screencolwidth = printcell.colw[screen]; 159 uint16_t *screencolwidth = printcell.colw[screen];
158 160
159 for(int i = 1; i < ncols; i++) 161 for(int i = 1; i <= last_col; i++)
160 { 162 {
161 int ny = y; 163 int ny = y;
162 int nw = screencolwidth[i] + text_offset; 164 int nw = screencolwidth[i] + text_offset;
165 int offx = 0;
166
167 if (i == last_col || x + nw >= vp_w - offw + 1)
168 { /* not enough space for next column use up excess */
169 if (nw < (vp_w - x))
170 {
171 if (is_title)
172 offx = ((vp_w - x) - nw) / 2;
173 nw = vp_w - x;
174 }
175 }
176
177 if (!PRINTCELL_COLUMN_IS_VISIBLE(printcell.hidecol_flags, i))
178 nw = 0;
179
163 int nx = x + nw; 180 int nx = x + nw;
164 char *buftext; 181 char *buftext;
165 if (nx > 0 && x < vp_w) 182
183 if (nx > 0 && nw > offw && x < vp_w)
166 { 184 {
167 set_cell_width(vp, vp_w, nx); 185 set_cell_width(vp, vp_w, nx);
168 186
@@ -173,11 +191,15 @@ static inline int printcells(struct screen *display, char* buffer,
173 } 191 }
174 else 192 else
175 { 193 {
194 if (vp_w < x + text_offset)
195 {
196 scroll = false;
197 }
176 linedes->scroll = scroll; 198 linedes->scroll = scroll;
177 linedes->separator_height = separator; 199 linedes->separator_height = separator;
178 } 200 }
179 buftext = &buffer[sidx[i]]; 201 buftext = &buffer[sidx[i]];
180 display->put_line(x + offw, ny, linedes, "$t", buftext); 202 display->put_line(x + offw + offx, ny, linedes, "$t", buftext);
181 vp->width += COLUMN_ENDLEN + 1; 203 vp->width += COLUMN_ENDLEN + 1;
182 draw_selector(display, linedes, selected_flag, i, separator, x, ny, nw, height); 204 draw_selector(display, linedes, selected_flag, i, separator, x, ny, nw, height);
183 } 205 }
@@ -200,6 +222,10 @@ static inline int calcvisible(int screen, int vp_w, int text_offset, int sbwidth
200 for (int i = printcell.selcol - 1; i >= 0; i--) 222 for (int i = printcell.selcol - 1; i >= 0; i--)
201 { 223 {
202 int cw = screencolwidth[i] + text_offset; 224 int cw = screencolwidth[i] + text_offset;
225
226 if (!PRINTCELL_COLUMN_IS_VISIBLE(printcell.hidecol_flags, i))
227 cw = 0;
228
203 if (i == 0) 229 if (i == 0)
204 cw += screenicnwidth; 230 cw += screenicnwidth;
205 if (offset > 0 || cw > maxw) 231 if (offset > 0 || cw > maxw)
@@ -257,15 +283,30 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info)
257 separator = 1; 283 separator = 1;
258 284
259 int nx = x; 285 int nx = x;
286 int last_col = printcell.ncols - 1;
287 int hidden_w = 0;
260 int nw, colxw; 288 int nw, colxw;
261 289 char *buftext;
262 printcell_buffer[0] = '\0'; 290 printcell_buffer[0] = '\0';
263 parse_dsptext(printcell.ncols, dsp_text, printcell_buffer, sidx); 291
264 char *buftext = &printcell_buffer[sidx[0]];
265 uint16_t *screencolwidth = printcell.colw[screen]; 292 uint16_t *screencolwidth = printcell.colw[screen];
293 if (printcell.hidecol_flags > 0)
294 {
295 for (int i = 0; i < printcell.ncols; i++)
296 {
297 if (PRINTCELL_COLUMN_IS_VISIBLE(printcell.hidecol_flags, i))
298 last_col = i;
299 else
300 hidden_w += (screencolwidth[i] + text_offset);
301 }
302 }
266 303
267 if (is_title) 304 if (is_title)
268 { 305 {
306 parse_dsptext(printcell.titlesep, printcell.ncols, dsp_text,
307 printcell_buffer, sizeof(printcell_buffer), sidx);
308
309 buftext = &printcell_buffer[sidx[0]]; /* set to first column text */
269 int sbwidth = 0; 310 int sbwidth = 0;
270 if (rb->global_settings->scrollbar == SCROLLBAR_LEFT) 311 if (rb->global_settings->scrollbar == SCROLLBAR_LEFT)
271 sbwidth = rb->global_settings->scrollbar_width; 312 sbwidth = rb->global_settings->scrollbar_width;
@@ -278,6 +319,9 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info)
278 nx -= printcell.selcol_offw[screen]; 319 nx -= printcell.selcol_offw[screen];
279 320
280 nw = screencolwidth[0] + printcell.iconw[screen] + text_offset; 321 nw = screencolwidth[0] + printcell.iconw[screen] + text_offset;
322
323 if (!PRINTCELL_COLUMN_IS_VISIBLE(printcell.hidecol_flags, 0))
324 nw = printcell.iconw[screen] - 1;
281 nw += sbwidth; 325 nw += sbwidth;
282 326
283 colxw = nx + nw; 327 colxw = nx + nw;
@@ -301,20 +345,21 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info)
301 } 345 }
302 else 346 else
303 { 347 {
348 parse_dsptext(printcell.colsep, printcell.ncols, dsp_text,
349 printcell_buffer, sizeof(printcell_buffer), sidx);
350
351 buftext = &printcell_buffer[sidx[0]]; /* set to first column text */
304 int cursor = Icon_NOICON; 352 int cursor = Icon_NOICON;
305 nx -= printcell.selcol_offw[screen]; 353 nx -= printcell.selcol_offw[screen];
306 354
307 if (selected_flag & SELECTED_FLAG) 355 if (selected_flag & SELECTED_FLAG)
308 { 356 {
309 if (printcell.selcol >= 0)
310 printcell.selcol_index = sidx[printcell.selcol]; /* save the item offset*/
311 else
312 printcell.selcol_index = -1;
313
314 cursor = Icon_Cursor; 357 cursor = Icon_Cursor;
315 /* limit length of selection if columns don't reach end */ 358 /* limit length of selection if columns don't reach end */
316 int maxw = nx + printcell.totalcolw[screen] + printcell.iconw[screen]; 359 int maxw = nx + printcell.totalcolw[screen] + printcell.iconw[screen];
317 maxw += text_offset * printcell.ncols; 360 maxw += text_offset * printcell.ncols;
361 maxw -= hidden_w;
362
318 if (vp_w > maxw) 363 if (vp_w > maxw)
319 vp->width = maxw; 364 vp->width = maxw;
320 /* display a blank line first to draw selector across all cells */ 365 /* display a blank line first to draw selector across all cells */
@@ -364,7 +409,7 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info)
364 nx += nw; 409 nx += nw;
365 /* display remaining cells */ 410 /* display remaining cells */
366 printcells(display, printcell_buffer, sidx, linedes, vp, vp_w, separator, 411 printcells(display, printcell_buffer, sidx, linedes, vp, vp_w, separator,
367 nx, y, col_offset_width, selected_flag, scroll_items); 412 nx, y, col_offset_width, selected_flag, last_col, scroll_items, is_title);
368 413
369 /* draw a line at the bottom of the list */ 414 /* draw a line at the bottom of the list */
370 if (separator > 0 && line == list->nb_items - 1) 415 if (separator > 0 && line == list->nb_items - 1)
@@ -377,14 +422,17 @@ static void printcell_listdraw_fn(struct list_putlineinfo_t *list_info)
377 vp->width = vp_w; 422 vp->width = vp_w;
378} 423}
379 424
380void printcell_enable(struct gui_synclist *gui_list, bool enable, bool separator) 425void printcell_enable(bool enable)
381{ 426{
382 printcell.separator = separator; 427 if (!printcell.gui_list)
428 return;
429 struct gui_synclist *gui_list = printcell.gui_list;
383#ifdef HAVE_LCD_COLOR 430#ifdef HAVE_LCD_COLOR
384 static int list_sep_color = INT_MIN; 431 static int list_sep_color = INT_MIN;
385 if (enable) 432 if (enable)
386 { 433 {
387 list_sep_color = rb->global_settings->list_separator_color; 434 if (list_sep_color == INT_MIN)
435 list_sep_color = rb->global_settings->list_separator_color;
388 rb->global_settings->list_separator_color = rb->global_settings->fg_color; 436 rb->global_settings->list_separator_color = rb->global_settings->fg_color;
389 gui_list->callback_draw_item = printcell_listdraw_fn; 437 gui_list->callback_draw_item = printcell_listdraw_fn;
390 } 438 }
@@ -404,8 +452,11 @@ void printcell_enable(struct gui_synclist *gui_list, bool enable, bool separator
404 452
405} 453}
406 454
407int printcell_increment_column(struct gui_synclist *gui_list, int increment, bool wrap) 455int printcell_increment_column(int increment, bool wrap)
408{ 456{
457 if (!printcell.gui_list)
458 return -1;
459 struct gui_synclist *gui_list = printcell.gui_list;
409 int item = printcell.selcol + increment; 460 int item = printcell.selcol + increment;
410 int imin = -1; 461 int imin = -1;
411 int imax = printcell.ncols - 1; 462 int imax = printcell.ncols - 1;
@@ -425,36 +476,94 @@ int printcell_increment_column(struct gui_synclist *gui_list, int increment, boo
425 FOR_NB_SCREENS(n) /* offset needs recalculated */ 476 FOR_NB_SCREENS(n) /* offset needs recalculated */
426 printcell.selcol_offw[n] = 0; 477 printcell.selcol_offw[n] = 0;
427 printcell.selcol = item; 478 printcell.selcol = item;
428 printcell.selcol_index = 0; 479
429 rb->gui_synclist_draw(gui_list); 480 rb->gui_synclist_draw(gui_list);
481 rb->gui_synclist_speak_item(gui_list);
430 } 482 }
431 return item; 483 return item;
432} 484}
433 485
486int printcell_get_column_selected(void)
487{
488 if (!printcell.gui_list)
489 return -1;
490 return printcell.selcol;
491}
492
493uint32_t printcell_get_column_visibility(int col)
494{
495 if (col >= 0)
496 return (PRINTCELL_COLUMN_IS_VISIBLE(printcell.hidecol_flags, col) ? 0:1);
497 else /* return flag of all columns */
498 return printcell.hidecol_flags;
499}
500
501void printcell_set_column_visible(int col, bool visible)
502{
503 /* visible columns have 0 for the column bit hidden columns have the bit set */
504 if (col >= 0)
505 {
506 if (visible)
507 printcell.hidecol_flags &= ~(PRINTCELL_COLUMN_FLAG(col));
508 else
509 printcell.hidecol_flags |= PRINTCELL_COLUMN_FLAG(col);
510 }
511 else
512 {
513 if (visible) /* set to everything visible */
514 printcell.hidecol_flags = 0;
515 else /* set to everything hidden */
516 printcell.hidecol_flags = ((uint32_t)-1);
517 }
518}
519
434int printcell_set_columns(struct gui_synclist *gui_list, 520int printcell_set_columns(struct gui_synclist *gui_list,
435 char * title, enum themable_icons icon) 521 struct printcell_settings * pcs,
522 char * title, enum themable_icons icon)
436{ 523{
524
437 if (title == NULL) 525 if (title == NULL)
438 title = "$PRINTCELL NOT SETUP"; 526 title = "$PRINTCELL NOT SETUP";
527
528 if (pcs == NULL) /* DEFAULTS */
529 {
530#if LCD_DEPTH > 1
531 /* If line sep is set to automatic then outline cells */
532 bool sep = (rb->global_settings->list_separator_height < 0);
533#else
534 bool sep = (rb->global_settings->cursor_style == 0);
535#endif
536 pcs = &(struct printcell_settings){ .cell_separator = sep,
537 .title_delimeter = '$',
538 .text_delimeter = '$',
539 .hidecol_flags = 0};
540 }
541
439 uint16_t sidx[PRINTCELL_MAX_COLUMNS]; /* starting position of column in title string */ 542 uint16_t sidx[PRINTCELL_MAX_COLUMNS]; /* starting position of column in title string */
440 int width, height, user_minwidth; 543 int width, height, user_minwidth;
441 int i = 0; 544 int i = 0;
442 int j = 0; 545 size_t j = 0;
443 int ch = '$'; /* first column $ is optional */
444
445 rb->memset(&printcell, 0, sizeof(struct printcell_info_t)); 546 rb->memset(&printcell, 0, sizeof(struct printcell_info_t));
446 547
548 printcell.gui_list = gui_list;
549 printcell.separator = pcs->cell_separator;
550 printcell.titlesep = pcs->title_delimeter;
551 printcell.colsep = pcs->text_delimeter;
552 printcell.hidecol_flags = pcs->hidecol_flags;
553
554 int ch = printcell.titlesep; /* first column $ is optional */
555
447 FOR_NB_SCREENS(n) 556 FOR_NB_SCREENS(n)
448 { 557 {
449 rb->screens[n]->getstringsize("W", &width, &height); 558 rb->screens[n]->getstringsize("W", &width, &height);
450 printcell.offw[n] = width; /* set column text offset */ 559 printcell.offw[n] = width; /* set column text offset */
451 } 560 }
452 561
453 if (*title == '$') 562 if (*title == printcell.titlesep)
454 title++; 563 title++;
455 do 564 do
456 { 565 {
457 if (ch == '$') 566 if (ch == printcell.titlesep)
458 { 567 {
459 printcell.title[j++] = ch; 568 printcell.title[j++] = ch;
460 user_minwidth = 0; 569 user_minwidth = 0;
@@ -466,7 +575,7 @@ int printcell_set_columns(struct gui_synclist *gui_list,
466 user_minwidth = 10*user_minwidth + *title - '0'; 575 user_minwidth = 10*user_minwidth + *title - '0';
467 title++; 576 title++;
468 } 577 }
469 if (*title != '$') /* user forgot $ or wants to display '*' */ 578 if (*title != printcell.titlesep) /* user forgot titlesep or wants to display '*' */
470 { 579 {
471 title = dspst; 580 title = dspst;
472 user_minwidth = 0; 581 user_minwidth = 0;
@@ -476,17 +585,25 @@ int printcell_set_columns(struct gui_synclist *gui_list,
476 } 585 }
477 586
478 sidx[i] = j; 587 sidx[i] = j;
479 if (*title == '$') /* $$ escaped user must want to display $*/
480 printcell.title[j++] = *title++;
481 588
482 while (*title != '\0' && *title != '$' && j < PRINTCELL_MAXLINELEN - 1) 589 while (*title != '\0'
590 && *title != printcell.titlesep
591 && j < PRINTCELL_MAXLINELEN - 1)
592 {
483 printcell.title[j++] = *title++; 593 printcell.title[j++] = *title++;
594 }
484 595
485 FOR_NB_SCREENS(n) 596 FOR_NB_SCREENS(n)
486 { 597 {
487 rb->screens[n]->getstringsize(&printcell.title[sidx[i]], &width, &height); 598 rb->screens[n]->getstringsize(&printcell.title[sidx[i]],
599 &width, &height);
600
488 if (width < user_minwidth) 601 if (width < user_minwidth)
489 width = user_minwidth; 602 width = user_minwidth;
603
604 if (width > LCD_WIDTH)
605 width = LCD_WIDTH;
606
490 printcell.colw[n][i] = width; 607 printcell.colw[n][i] = width;
491 printcell.totalcolw[n] += width; 608 printcell.totalcolw[n] += width;
492 } 609 }
@@ -498,37 +615,67 @@ int printcell_set_columns(struct gui_synclist *gui_list,
498 printcell.ncols = i; 615 printcell.ncols = i;
499 printcell.title[j] = '\0'; 616 printcell.title[j] = '\0';
500 printcell.selcol = -1; 617 printcell.selcol = -1;
501 printcell.selcol_index = 0;
502 618
503 rb->gui_synclist_set_title(gui_list, printcell.title, icon); 619 rb->gui_synclist_set_title(gui_list, printcell.title, icon);
504 return printcell.ncols; 620 return printcell.ncols;
505} 621}
506 622
507char *printcell_get_selected_column_text(struct gui_synclist *gui_list, char *buf, size_t bufsz) 623char *printcell_get_title_text(int selcol, char *buf, size_t bufsz)
508{ 624{
509 int selected = gui_list->selected_item; 625 /* note offsets are calculated everytime this function is called
510 int index = printcell.selcol_index - 1; 626 * shouldn't be used in hot code paths */
627 int index = 0;
628 buf[0] = '\0';
629 if (selcol < 0) /* return entire string incld col formatting '$'*/
630 return printcell.title;
631
632 if (selcol < printcell.ncols)
633 {
634 uint16_t sidx[PRINTCELL_MAX_COLUMNS]; /*indexes zero terminated strings in buffer*/
635 parse_dsptext(printcell.titlesep, selcol + 1, printcell.title, buf, bufsz, sidx);
636 index = sidx[selcol];
637 }
638 return &buf[index];
639}
511 640
512 if (index < 0) 641char *printcell_get_column_text(int selcol, char *buf, size_t bufsz)
513 index = 0; 642{
643 int index = 0;
514 char *bpos; 644 char *bpos;
645 struct gui_synclist *gui_list = printcell.gui_list;
515 646
516 if (gui_list->callback_get_item_name(selected, gui_list->data, buf, bufsz) == buf) 647 if (gui_list && gui_list->callback_draw_item == printcell_listdraw_fn)
517 { 648 {
518 bpos = &buf[index]; 649 int col = selcol;
519 if (printcell.selcol < 0) /* return entire string incld col formatting '$'*/ 650 int item = gui_list->selected_item;
520 return bpos; 651 void *data = gui_list->data;
521 while(bpos < &buf[bufsz - 1]) 652
653 if (col < printcell.ncols
654 && gui_list->callback_get_item_name(item, data, buf, bufsz) == buf)
522 { 655 {
523 if (*bpos == '$' || *bpos == '\0') 656 bpos = buf;
524 goto success; 657 if (col < 0) /* return entire string incld col formatting '$'*/
525 bpos++; 658 {
659 return bpos;
660 }
661 bpos++; /* Skip sep/NULL */
662
663 while(bpos < &buf[bufsz - 1])
664 {
665 if (*bpos == printcell.colsep || *bpos == '\0')
666 {
667 if (col-- == 0)
668 goto success;
669 index = bpos - buf + 1; /* Skip sep/NULL */
670 }
671 bpos++;
672 }
526 } 673 }
527 } 674 }
528/*failure*/ 675/*failure*/
529 bpos = buf; 676 bpos = buf;
530 index = 0; 677 index = 0;
531success: 678success:
532 *bpos = '\0'; 679 *bpos = '\0';
533 return &buf[index]; 680 return &buf[index];
534} 681}
diff --git a/apps/plugins/lib/printcell_helper.h b/apps/plugins/lib/printcell_helper.h
index adc98e5a5f..f58e73c0a5 100644
--- a/apps/plugins/lib/printcell_helper.h
+++ b/apps/plugins/lib/printcell_helper.h
@@ -21,25 +21,67 @@
21 21
22#ifndef _PRINTCELL_LIST_H_ 22#ifndef _PRINTCELL_LIST_H_
23#define _PRINTCELL_LIST_H_ 23#define _PRINTCELL_LIST_H_
24#ifndef PRINTCELL_MAX_COLUMNS
25#define PRINTCELL_MAX_COLUMNS 16 /* Max 32 (hidecol_flags)*/
26#endif
27
24#define PRINTCELL_MAXLINELEN MAX_PATH 28#define PRINTCELL_MAXLINELEN MAX_PATH
29#define PC_COL_FLAG(col) ((uint32_t)(col >= 0 \
30 && col < PRINTCELL_MAX_COLUMNS) ? 1u<<col : -1u)
31
32#define PRINTCELL_COLUMN_IS_VISIBLE(flag, col) ((flag & PC_COL_FLAG(col)) == 0)
33#define PRINTCELL_COLUMN_FLAG(col) (PC_COL_FLAG(col))
25 34
26/* sets the printcell function enabled */ 35struct printcell_settings
27void printcell_enable(struct gui_synclist *gui_list, bool enable, bool separator); 36{
37 bool cell_separator;
38 char title_delimeter;
39 char text_delimeter;
40 uint32_t hidecol_flags;
41};
28 42
29/* sets title and calculates cell widths each column is identified by '$' character 43/* Printcell initialization - Sets title and calculates cell widths
30 ex 3 columns title = "Col1$Col2$Col3" also accepts $*WIDTH$ 44* by default each column is identified by '$' character
31 ex 3 columns varying width title = "$*64$Col1$*128$Col2$Col3 45* ex 3 columns title = "Col1$Col2$Col3" also accepts $*WIDTH$
32 returns number of columns 46* ex 3 columns varying width title = "$*64$Col1$*128$Col2$Col3
47* supplying struct printcell_settings pcs allows changing default settings
48* supply NULL to use defaults
49*
50* Returns number of columns
33*/ 51*/
34int printcell_set_columns(struct gui_synclist *gui_list, 52int printcell_set_columns(struct gui_synclist *gui_list,
35 char * title, enum themable_icons icon); 53 struct printcell_settings * pcs,
54 char * title, enum themable_icons icon);
55
56/* Sets the printcell function enabled (use after initializing with set_column)
57 * Note you should call printcell_enable(false) if the list might be reused */
58void printcell_enable(bool enable);
36 59
37/* increments the current selected column negative increment is allowed 60/* Increments the current selected column negative increment is allowed
38 returns the selected column 61 returns the selected column
39 range: -1(no selection) to ncols - 1 */ 62 range: -1(no selection) to ncols - 1 */
40int printcell_increment_column(struct gui_synclist *gui_list, int increment, bool wrap); 63int printcell_increment_column(int increment, bool wrap);
64
65/* Return index of the currently selected column (-1 to ncols - 1) */
66int printcell_get_column_selected(void);
67
68/* Return the text of currently selected column buffer should be sized
69 * for max item len, buf[PRINTCELL_MAXLINELEN] is a safe bet */
70char *printcell_get_column_text(int selcol, char *buf, size_t bufsz);
41 71
42/* return the text of currently selected column buffer should be sized 72/* Return the text of currently selected column title should be sized
43 * for max item len, buf[PRINTCELL_MAXLINELEN] is a safe bet */ 73 * 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); 74char *printcell_get_title_text(int selcol, char *buf, size_t bufsz);
75
76
77/* Hide or show a specified column - supply col = -1 to affect all columns */
78void printcell_set_column_visible(int col, bool visible);
79
80/* Return visibility of a specified column
81* returns (1 visible or 0 hidden)
82* if supply col == -1 a flag with visibility of all columns will be returned
83* NOTE: flag denotes a hidden column by a 1 in the column bit (1 << col#)
84* PRINTCELL_COLUMN_IS_VISIBLE(flag,col) macro will convert to bool
85*/
86uint32_t printcell_get_column_visibility(int col);
45#endif /*_PRINTCELL_LIST_H_*/ 87#endif /*_PRINTCELL_LIST_H_*/
diff --git a/apps/plugins/rb_info.c b/apps/plugins/rb_info.c
index f123a623d2..a89cc658cc 100644
--- a/apps/plugins/rb_info.c
+++ b/apps/plugins/rb_info.c
@@ -335,6 +335,17 @@ static int list_voice_cb(int list_index, void* data)
335 rb->talk_spell(name, true); 335 rb->talk_spell(name, true);
336 } 336 }
337 } 337 }
338 else if (data == MENU_ID(M_TESTPUT))
339 {
340 char buf[64];
341 const char* name = printcell_get_column_text(printcell_get_column_selected(),
342 buf, sizeof(buf));
343 long id = P2ID((const unsigned char *)name);
344 if(id>=0)
345 rb->talk_id(id, true);
346 else
347 rb->talk_spell(name, true);
348 }
338 else 349 else
339 { 350 {
340 char buf[64]; 351 char buf[64];
@@ -354,12 +365,12 @@ int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_syncli
354 { 365 {
355 if (*action == ACTION_STD_OK) 366 if (*action == ACTION_STD_OK)
356 { 367 {
357 printcell_increment_column(lists, 1, true); 368 printcell_increment_column(1, true);
358 *action = ACTION_NONE; 369 *action = ACTION_NONE;
359 } 370 }
360 else if (*action == ACTION_STD_CANCEL) 371 else if (*action == ACTION_STD_CANCEL)
361 { 372 {
362 if (printcell_increment_column(lists, -1, true) != testput_cols - 1) 373 if (printcell_increment_column(-1, true) != testput_cols - 1)
363 { 374 {
364 *action = ACTION_NONE; 375 *action = ACTION_NONE;
365 } 376 }
@@ -368,7 +379,8 @@ int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_syncli
368 { 379 {
369 char buf[PRINTCELL_MAXLINELEN]; 380 char buf[PRINTCELL_MAXLINELEN];
370 char* bufp = buf; 381 char* bufp = buf;
371 bufp = printcell_get_selected_column_text(lists, bufp, PRINTCELL_MAXLINELEN); 382 int selcol = printcell_get_column_selected();
383 bufp = printcell_get_column_text(selcol, bufp, PRINTCELL_MAXLINELEN);
372 rb->splashf(HZ * 2, "Item: %s", bufp); 384 rb->splashf(HZ * 2, "Item: %s", bufp);
373 } 385 }
374 } 386 }
@@ -429,18 +441,12 @@ int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_syncli
429 if (cur->menuid == MENU_ID(M_TESTPUT)) 441 if (cur->menuid == MENU_ID(M_TESTPUT))
430 { 442 {
431 synclist_set(cur->menuid, 0, cur->items, 1); 443 synclist_set(cur->menuid, 0, cur->items, 1);
432#if LCD_DEPTH > 1 444 printcell_enable(true);
433 /* If line sep is set to automatic then outline cells */
434 bool showlinesep = (rb->global_settings->list_separator_height < 0);
435#else
436 bool showlinesep = (rb->global_settings->cursor_style == 0);
437#endif
438 printcell_enable(lists, true, showlinesep);
439 //lists->callback_draw_item = test_listdraw_fn; 445 //lists->callback_draw_item = test_listdraw_fn;
440 } 446 }
441 else 447 else
442 { 448 {
443 printcell_enable(lists, false, false); 449 printcell_enable(false);
444 synclist_set(cur->menuid, 1, cur->items, 1); 450 synclist_set(cur->menuid, 1, cur->items, 1);
445 } 451 }
446 rb->gui_synclist_draw(lists); 452 rb->gui_synclist_draw(lists);
@@ -473,7 +479,7 @@ int menu_action_cb(int *action, int selected_item, bool* exit, struct gui_syncli
473 if (lists->data == MENU_ID(M_TESTPUT)) 479 if (lists->data == MENU_ID(M_TESTPUT))
474 { 480 {
475 //lists->callback_draw_item = NULL; 481 //lists->callback_draw_item = NULL;
476 printcell_enable(lists, false, false); 482 printcell_enable(false);
477 } 483 }
478 if (lists->data != MENU_ID(M_ROOT)) 484 if (lists->data != MENU_ID(M_ROOT))
479 { 485 {
@@ -505,7 +511,8 @@ static void synclist_set(char* menu_id, int selected_item, int items, int sel_si
505 menu_id, false, sel_size, NULL); 511 menu_id, false, sel_size, NULL);
506 if (menu_id == MENU_ID(M_TESTPUT)) 512 if (menu_id == MENU_ID(M_TESTPUT))
507 { 513 {
508 testput_cols = printcell_set_columns(&lists, TESTPUT_HEADER, Icon_Rockbox); 514 testput_cols = printcell_set_columns(&lists, NULL,
515 TESTPUT_HEADER, Icon_Rockbox);
509 } 516 }
510 else 517 else
511 { 518 {
@@ -562,6 +569,6 @@ enum plugin_status plugin_start(const void* parameter)
562 selected_item = rb->gui_synclist_get_sel_pos(&lists); 569 selected_item = rb->gui_synclist_get_sel_pos(&lists);
563 } 570 }
564 } 571 }
565 572 printcell_enable(false);
566 return ret; 573 return ret;
567} 574}
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config
index 8d266966d0..c0b76d45d5 100644
--- a/apps/plugins/viewers.config
+++ b/apps/plugins/viewers.config
@@ -105,4 +105,5 @@ shopper,viewers/shopper,1
105lnk,viewers/windows_lnk,- 105lnk,viewers/windows_lnk,-
106#ifdef HAVE_TAGCACHE 106#ifdef HAVE_TAGCACHE
107*,demos/pictureflow,- 107*,demos/pictureflow,-
108log,viewers/lastfm_scrobbler_viewer,4
108#endif 109#endif