summaryrefslogtreecommitdiff
path: root/apps/gui/list.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/gui/list.c')
-rw-r--r--apps/gui/list.c413
1 files changed, 72 insertions, 341 deletions
diff --git a/apps/gui/list.c b/apps/gui/list.c
index bc21976449..fbc417edee 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -37,6 +37,7 @@
37#include "sound.h" 37#include "sound.h"
38#include "misc.h" 38#include "misc.h"
39#include "talk.h" 39#include "talk.h"
40#include "viewport.h"
40 41
41#ifdef HAVE_LCD_CHARCELLS 42#ifdef HAVE_LCD_CHARCELLS
42#define SCROLL_LIMIT 1 43#define SCROLL_LIMIT 1
@@ -56,11 +57,46 @@ static bool offset_out_of_view = false;
56#endif 57#endif
57static struct gui_synclist* last_list_displayed; 58static struct gui_synclist* last_list_displayed;
58 59
59#define SHOW_LIST_TITLE ((gui_list->title != NULL) && \
60 (display->nb_lines > 2))
61
62static void gui_list_select_at_offset(struct gui_synclist * gui_list, 60static void gui_list_select_at_offset(struct gui_synclist * gui_list,
63 int offset); 61 int offset);
62void list_draw(struct screen *display, struct viewport *parent, struct gui_synclist *list);
63
64#ifdef HAVE_LCD_BITMAP
65static struct viewport parent[NB_SCREENS];
66void list_init_viewports(void)
67{
68 int i;
69 struct viewport *vp;
70 FOR_NB_SCREENS(i)
71 {
72 vp = &parent[i];
73 viewport_set_defaults(vp, i);
74 }
75}
76#else
77static struct viewport parent[NB_SCREENS] =
78{
79 [SCREEN_MAIN] =
80 {
81 .x = 0,
82 .y = 0,
83 .width = LCD_WIDTH,
84 .height = LCD_HEIGHT
85 },
86};
87void list_init_viewports(void)
88{
89}
90#endif
91
92#ifdef HAVE_LCD_BITMAP
93bool list_display_title(struct gui_synclist *list, struct viewport *vp)
94{
95 return list->title != NULL && viewport_get_nb_lines(vp)>2;
96}
97#else
98#define list_display_title(l,v) false
99#endif
64 100
65/* 101/*
66 * Initializes a scrolling list 102 * Initializes a scrolling list
@@ -82,7 +118,7 @@ void gui_synclist_init(struct gui_synclist * gui_list,
82 gui_list->callback_get_item_icon = NULL; 118 gui_list->callback_get_item_icon = NULL;
83 gui_list->callback_get_item_name = callback_get_item_name; 119 gui_list->callback_get_item_name = callback_get_item_name;
84 gui_list->callback_speak_item = NULL; 120 gui_list->callback_speak_item = NULL;
85 gui_list_set_nb_items(gui_list, 0); 121 gui_list->nb_items = 0;
86 gui_list->selected_item = 0; 122 gui_list->selected_item = 0;
87 FOR_NB_SCREENS(i) 123 FOR_NB_SCREENS(i)
88 { 124 {
@@ -91,6 +127,7 @@ void gui_synclist_init(struct gui_synclist * gui_list,
91#ifdef HAVE_LCD_BITMAP 127#ifdef HAVE_LCD_BITMAP
92 gui_list->offset_position[i] = 0; 128 gui_list->offset_position[i] = 0;
93#endif 129#endif
130 gui_list->parent[i] = &parent[i];
94 } 131 }
95 gui_list->limit_scroll = false; 132 gui_list->limit_scroll = false;
96 gui_list->data=data; 133 gui_list->data=data;
@@ -118,8 +155,10 @@ void gui_synclist_hide_selection_marker(struct gui_synclist * lists, bool hide)
118 155
119 156
120#ifdef HAVE_LCD_BITMAP 157#ifdef HAVE_LCD_BITMAP
121static int gui_list_get_item_offset(struct gui_synclist * gui_list, int item_width, 158int list_title_height(struct gui_synclist *list, struct viewport *vp);
122 int text_pos, struct screen * display) 159
160int gui_list_get_item_offset(struct gui_synclist * gui_list, int item_width,
161 int text_pos, struct screen * display, struct viewport *vp)
123{ 162{
124 int item_offset; 163 int item_offset;
125 164
@@ -130,7 +169,7 @@ static int gui_list_get_item_offset(struct gui_synclist * gui_list, int item_wid
130 else 169 else
131 { 170 {
132 /* if text is smaller then view */ 171 /* if text is smaller then view */
133 if (item_width <= display->width - text_pos) 172 if (item_width <= vp->width - text_pos)
134 { 173 {
135 item_offset = 0; 174 item_offset = 0;
136 } 175 }
@@ -138,8 +177,8 @@ static int gui_list_get_item_offset(struct gui_synclist * gui_list, int item_wid
138 { 177 {
139 /* if text got out of view */ 178 /* if text got out of view */
140 if (gui_list->offset_position[display->screen_type] > 179 if (gui_list->offset_position[display->screen_type] >
141 item_width - (display->width - text_pos)) 180 item_width - (vp->width - text_pos))
142 item_offset = item_width - (display->width - text_pos); 181 item_offset = item_width - (vp->width - text_pos);
143 else 182 else
144 item_offset = gui_list->offset_position[display->screen_type]; 183 item_offset = gui_list->offset_position[display->screen_type];
145 } 184 }
@@ -148,341 +187,32 @@ static int gui_list_get_item_offset(struct gui_synclist * gui_list, int item_wid
148 return item_offset; 187 return item_offset;
149} 188}
150#endif 189#endif
151
152/*
153 * Draws the list on the attached screen
154 * - gui_list : the list structure
155 */
156static void gui_list_draw_smart(struct gui_synclist *gui_list, struct screen * display)
157{
158 int text_pos;
159 bool draw_icons = (gui_list->callback_get_item_icon != NULL && global_settings.show_icons);
160 bool draw_cursor;
161 int i;
162 int lines;
163 static int last_lines[NB_SCREENS] = {0};
164#ifdef HAVE_LCD_BITMAP
165 int item_offset;
166 int old_margin = display->getxmargin();
167#endif
168 int start, end;
169 bool partial_draw = false;
170
171#ifdef HAVE_LCD_BITMAP
172 display->setfont(FONT_UI);
173 gui_textarea_update_nblines(display);
174#endif
175 /* Speed up UI by drawing the changed contents only. */
176 if (gui_list == last_list_displayed
177 && gui_list->last_displayed_start_item[display->screen_type] == gui_list->start_item[display->screen_type]
178 && gui_list->selected_size == 1)
179 {
180 partial_draw = true;
181 }
182
183 lines = display->nb_lines - SHOW_LIST_TITLE;
184 if (last_lines[display->screen_type] != lines)
185 {
186 gui_list_select_at_offset(gui_list, 0);
187 last_lines[display->screen_type] = lines;
188 }
189
190 if (partial_draw)
191 {
192 end = gui_list->last_displayed_selected_item - gui_list->start_item[display->screen_type];
193 i = gui_list->selected_item - gui_list->start_item[display->screen_type];
194 if (i < end )
195 {
196 start = i;
197 end++;
198 }
199 else
200 {
201 start = end;
202 end = i + 1;
203 }
204 }
205 else
206 {
207 gui_textarea_clear(display);
208 start = 0;
209 end = display->nb_lines;
210 gui_list->last_displayed_start_item[display->screen_type] = gui_list->start_item[display->screen_type];
211 last_list_displayed = gui_list;
212 }
213
214 gui_list->last_displayed_selected_item = gui_list->selected_item;
215
216 /* position and draw the list title & icon */
217 if (SHOW_LIST_TITLE && !partial_draw)
218 {
219 if (gui_list->title_icon != NOICON && draw_icons)
220 {
221 screen_put_icon(display, 0, 0, gui_list->title_icon);
222#ifdef HAVE_LCD_BITMAP
223 text_pos = get_icon_width(display->screen_type)+2; /* pixels */
224#else
225 text_pos = 1; /* chars */
226#endif
227 }
228 else
229 {
230 text_pos = 0;
231 }
232
233#ifdef HAVE_LCD_BITMAP
234 int title_style = STYLE_DEFAULT;
235#ifdef HAVE_LCD_COLOR
236 if (gui_list->title_color >= 0)
237 {
238 title_style |= STYLE_COLORED;
239 title_style |= gui_list->title_color;
240 }
241#endif
242 screen_set_xmargin(display, text_pos); /* margin for title */
243 item_offset = gui_list_get_item_offset(gui_list, gui_list->title_width,
244 text_pos, display);
245 if (item_offset > gui_list->title_width - (display->width - text_pos))
246 display->puts_style_offset(0, 0, gui_list->title,
247 title_style, item_offset);
248 else
249 display->puts_scroll_style_offset(0, 0, gui_list->title,
250 title_style, item_offset);
251#else
252 display->puts_scroll(text_pos, 0, gui_list->title);
253#endif
254 }
255
256 /* Adjust the position of icon, cursor, text for the list */
257#ifdef HAVE_LCD_BITMAP
258 gui_textarea_update_nblines(display);
259 bool draw_scrollbar;
260
261 draw_scrollbar = (global_settings.scrollbar &&
262 lines < gui_list->nb_items);
263
264 draw_cursor = !global_settings.cursor_style &&
265 gui_list->show_selection_marker;
266 text_pos = 0; /* here it's in pixels */
267 if(draw_scrollbar || SHOW_LIST_TITLE) /* indent if there's
268 a title */
269 {
270 text_pos += SCROLLBAR_WIDTH;
271 }
272 if(draw_cursor)
273 text_pos += get_icon_width(display->screen_type) + 2;
274
275 if(draw_icons)
276 text_pos += get_icon_width(display->screen_type) + 2;
277#else
278 draw_cursor = true;
279 if(draw_icons)
280 text_pos = 2; /* here it's in chars */
281 else
282 text_pos = 1;
283#endif
284
285#ifdef HAVE_LCD_BITMAP
286 screen_set_xmargin(display, text_pos); /* margin for list */
287#endif
288
289 if (SHOW_LIST_TITLE)
290 {
291 start++;
292 if (end < display->nb_lines)
293 end++;
294 }
295
296#ifdef HAVE_LCD_COLOR
297 unsigned char cur_line = 0;
298#endif
299 for (i = start; i < end; i++)
300 {
301 unsigned char *s;
302 char entry_buffer[MAX_PATH];
303 unsigned char *entry_name;
304 int current_item = gui_list->start_item[display->screen_type] +
305 (SHOW_LIST_TITLE ? i-1 : i);
306
307 /* When there are less items to display than the
308 * current available space on the screen, we stop*/
309 if(current_item >= gui_list->nb_items)
310 break;
311 s = gui_list->callback_get_item_name(current_item,
312 gui_list->data,
313 entry_buffer);
314 entry_name = P2STR(s);
315
316#ifdef HAVE_LCD_BITMAP
317 int style = STYLE_DEFAULT;
318 /* position the string at the correct offset place */
319 int item_width,h;
320 display->getstringsize(entry_name, &item_width, &h);
321 item_offset = gui_list_get_item_offset(gui_list, item_width,
322 text_pos, display);
323#endif
324
325#ifdef HAVE_LCD_COLOR
326 /* if the list has a color callback */
327 if (gui_list->callback_get_item_color)
328 {
329 int color = gui_list->callback_get_item_color(current_item,
330 gui_list->data);
331 /* if color selected */
332 if (color >= 0)
333 {
334 style |= STYLE_COLORED;
335 style |= color;
336 }
337 }
338#endif
339
340 if(gui_list->show_selection_marker &&
341 current_item >= gui_list->selected_item &&
342 current_item < gui_list->selected_item + gui_list->selected_size)
343 {/* The selected item must be displayed scrolling */
344#ifdef HAVE_LCD_BITMAP
345 if (global_settings.cursor_style == 1
346#ifdef HAVE_REMOTE_LCD
347 || display->screen_type == SCREEN_REMOTE
348#endif
349 )
350 {
351 /* Display inverted-line-style */
352 style |= STYLE_INVERT;
353 }
354#ifdef HAVE_LCD_COLOR
355 else if (global_settings.cursor_style == 2)
356 {
357 /* Display colour line selector */
358 style |= STYLE_COLORBAR;
359 }
360 else if (global_settings.cursor_style == 3)
361 {
362 /* Display gradient line selector */
363 style = STYLE_GRADIENT;
364
365 /* Make the lcd driver know how many lines the gradient should
366 cover and current line number */
367 /* number of selected lines */
368 style |= NUMLN_PACK(gui_list->selected_size);
369 /* current line number, zero based */
370 style |= CURLN_PACK(cur_line);
371 cur_line++;
372 }
373#endif
374 else /* if (!global_settings.cursor_style) */
375 {
376 if (current_item % gui_list->selected_size != 0)
377 draw_cursor = false;
378 }
379 /* if the text is smaller than the viewport size */
380 if (item_offset > item_width - (display->width - text_pos))
381 {
382 /* don't scroll */
383 display->puts_style_offset(0, i, entry_name,
384 style, item_offset);
385 }
386 else
387 {
388 display->puts_scroll_style_offset(0, i, entry_name,
389 style, item_offset);
390 }
391#else
392 display->puts_scroll(text_pos, i, entry_name);
393#endif
394
395 if (draw_cursor)
396 {
397 screen_put_icon_with_offset(display, 0, i,
398 (draw_scrollbar || SHOW_LIST_TITLE)?
399 SCROLLBAR_WIDTH: 0,
400 0, Icon_Cursor);
401 }
402 }
403 else
404 {/* normal item */
405 if(gui_list->scroll_all)
406 {
407#ifdef HAVE_LCD_BITMAP
408 display->puts_scroll_style_offset(0, i, entry_name,
409 style, item_offset);
410#else
411 display->puts_scroll(text_pos, i, entry_name);
412#endif
413 }
414 else
415 {
416#ifdef HAVE_LCD_BITMAP
417 display->puts_style_offset(0, i, entry_name,
418 style, item_offset);
419#else
420 display->puts(text_pos, i, entry_name);
421#endif
422 }
423 }
424 /* Icons display */
425 if(draw_icons)
426 {
427 enum themable_icons icon;
428 icon = gui_list->callback_get_item_icon(current_item, gui_list->data);
429 if(icon > Icon_NOICON)
430 {
431#ifdef HAVE_LCD_BITMAP
432 int x = draw_cursor?1:0;
433 int x_off = (draw_scrollbar || SHOW_LIST_TITLE) ? SCROLLBAR_WIDTH: 0;
434 screen_put_icon_with_offset(display, x, i,
435 x_off, 0, icon);
436#else
437 screen_put_icon(display, 1, i, icon);
438#endif
439 }
440 }
441 }
442
443#ifdef HAVE_LCD_BITMAP
444 /* Draw the scrollbar if needed*/
445 if(draw_scrollbar)
446 {
447 int y_start = gui_textarea_get_ystart(display);
448 if (SHOW_LIST_TITLE)
449 y_start += display->char_height;
450 int scrollbar_y_end = display->char_height *
451 lines + y_start;
452 gui_scrollbar_draw(display, 0, y_start, SCROLLBAR_WIDTH-1,
453 scrollbar_y_end - y_start, gui_list->nb_items,
454 gui_list->start_item[display->screen_type],
455 gui_list->start_item[display->screen_type] + lines, VERTICAL);
456 }
457
458 screen_set_xmargin(display, old_margin);
459#endif
460
461 gui_textarea_update(display);
462}
463
464/* 190/*
465 * Force a full screen update. 191 * Force a full screen update.
466 */ 192 */
193
467void gui_synclist_draw(struct gui_synclist *gui_list) 194void gui_synclist_draw(struct gui_synclist *gui_list)
468{ 195{
469 int i; 196 int i;
470 FOR_NB_SCREENS(i) 197 FOR_NB_SCREENS(i)
471 { 198 {
472 last_list_displayed = NULL; 199 last_list_displayed = NULL;
473 gui_list_draw_smart(gui_list, &screens[i]); 200 list_draw(&screens[i], gui_list->parent[i], gui_list);
474 } 201 }
475} 202}
476 203
477
478
479/* sets up the list so the selection is shown correctly on the screen */ 204/* sets up the list so the selection is shown correctly on the screen */
480static void gui_list_put_selection_on_screen(struct gui_synclist * gui_list, 205static void gui_list_put_selection_on_screen(struct gui_synclist * gui_list,
481 enum screen_type screen) 206 enum screen_type screen)
482{ 207{
483 struct screen *display = &screens[screen]; 208 int nb_lines;
484 int nb_lines = display->nb_lines - SHOW_LIST_TITLE;
485 int difference = gui_list->selected_item - gui_list->start_item[screen]; 209 int difference = gui_list->selected_item - gui_list->start_item[screen];
210 struct viewport vp = *gui_list->parent[screen];
211#ifdef HAVE_LCD_BITMAP
212 if (list_display_title(gui_list, gui_list->parent[screen]))
213 vp.height -= list_title_height(gui_list,gui_list->parent[screen]);
214#endif
215 nb_lines = viewport_get_nb_lines(&vp);
486 216
487 /* edge case,, selected last item */ 217 /* edge case,, selected last item */
488 if (gui_list->selected_item == gui_list->nb_items -1) 218 if (gui_list->selected_item == gui_list->nb_items -1)
@@ -576,8 +306,12 @@ static void gui_list_select_at_offset(struct gui_synclist * gui_list,
576 int i, nb_lines, screen_top; 306 int i, nb_lines, screen_top;
577 FOR_NB_SCREENS(i) 307 FOR_NB_SCREENS(i)
578 { 308 {
579 struct screen *display = &screens[i]; 309 struct viewport vp = *gui_list->parent[i];
580 nb_lines = display->nb_lines - SHOW_LIST_TITLE; 310#ifdef HAVE_LCD_BITMAP
311 if (list_display_title(gui_list, gui_list->parent[i]))
312 vp.height -= list_title_height(gui_list,gui_list->parent[i]);
313#endif
314 nb_lines = viewport_get_nb_lines(&vp);
581 if (offset > 0) 315 if (offset > 0)
582 { 316 {
583 screen_top = gui_list->nb_items-nb_lines; 317 screen_top = gui_list->nb_items-nb_lines;
@@ -616,23 +350,12 @@ void gui_synclist_add_item(struct gui_synclist * gui_list)
616 */ 350 */
617void gui_synclist_del_item(struct gui_synclist * gui_list) 351void gui_synclist_del_item(struct gui_synclist * gui_list)
618{ 352{
619 int i;
620 if(gui_list->nb_items > 0) 353 if(gui_list->nb_items > 0)
621 { 354 {
622 if (gui_list->selected_item == gui_list->nb_items-1) 355 if (gui_list->selected_item == gui_list->nb_items-1)
623 gui_list->selected_item--; 356 gui_list->selected_item--;
624 FOR_NB_SCREENS(i)
625 {
626 gui_textarea_update_nblines(&screens[i]);
627 int nb_lines = screens[i].nb_lines;
628 int dist_start_from_end = gui_list->nb_items
629 - gui_list->start_item[i] - 1;
630
631 /* scroll the list if needed */
632 if( (dist_start_from_end < nb_lines) && (gui_list->start_item[i] != 0) )
633 gui_list->start_item[i]--;
634 }
635 gui_list->nb_items--; 357 gui_list->nb_items--;
358 gui_synclist_select_item(gui_list, gui_list->selected_item);
636 } 359 }
637} 360}
638 361
@@ -707,6 +430,14 @@ void gui_synclist_set_voice_callback(struct gui_synclist * lists,
707 lists->callback_speak_item = voice_callback; 430 lists->callback_speak_item = voice_callback;
708} 431}
709 432
433#ifdef HAVE_LCD_COLOR
434void gui_synclist_set_color_callback(struct gui_synclist * lists,
435 list_get_color color_callback)
436{
437 lists->callback_get_item_color = color_callback;
438}
439#endif
440
710static void gui_synclist_select_next_page(struct gui_synclist * lists, 441static void gui_synclist_select_next_page(struct gui_synclist * lists,
711 enum screen_type screen) 442 enum screen_type screen)
712{ 443{