summaryrefslogtreecommitdiff
path: root/apps/gui/list.c
diff options
context:
space:
mode:
authorJonathan Gordon <rockbox@jdgordon.info>2008-03-05 09:58:30 +0000
committerJonathan Gordon <rockbox@jdgordon.info>2008-03-05 09:58:30 +0000
commit0e5cec2d187dbded9b3c36dbcfd1469d00fe47af (patch)
treeab02e321e04ebfb4fb2e0a5327b5443a10761176 /apps/gui/list.c
parent8232e1a7c8d7cfaa16e3c8283fdb6d5a46aaf577 (diff)
downloadrockbox-0e5cec2d187dbded9b3c36dbcfd1469d00fe47af.tar.gz
rockbox-0e5cec2d187dbded9b3c36dbcfd1469d00fe47af.zip
FS#8457 - convert the list drawing code to use viewports. This does not include any of the customizability which was in the patch, so unless any bugs show up users should not notice any difference.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16527 a1c6a512-1295-4272-9138-f99709370657
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{