1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 by Jonathan Gordon
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 /* This file contains the code to draw the list widget on BITMAP LCDs. */
35 #include "screen_access.h"
37 #include "scrollbar.h"
42 #include "statusbar-skinned.h"
44 #define ICON_PADDING 1
46 /* these are static to make scrolling work */
47 static struct viewport list_text
[NB_SCREENS
], title_text
[NB_SCREENS
];
49 int gui_list_get_item_offset(struct gui_synclist
* gui_list
, int item_width
,
50 int text_pos
, struct screen
* display
,
52 bool list_display_title(struct gui_synclist
*list
, enum screen_type screen
);
54 void gui_synclist_scroll_stop(struct gui_synclist
*lists
)
59 screens
[i
].scroll_stop(&list_text
[i
]);
60 screens
[i
].scroll_stop(&title_text
[i
]);
61 screens
[i
].scroll_stop(lists
->parent
[i
]);
66 internal screen layout:
68 |TI| title | TI is title icon
72 | | | items | I - icons
76 Note: This image is flipped horizontally when the language is a
77 right-to-left one (Hebrew, Arabic)
79 static bool draw_title(struct screen
*display
, struct gui_synclist
*list
)
81 const int screen
= display
->screen_type
;
82 int style
= STYLE_DEFAULT
;
83 struct viewport
*title_text_vp
= &title_text
[screen
];
85 if (sb_set_title_text(list
->title
, list
->title_icon
, screen
))
86 return false; /* the sbs is handling the title */
87 display
->scroll_stop(title_text_vp
);
88 if (!list_display_title(list
, screen
))
90 *title_text_vp
= *(list
->parent
[screen
]);
91 title_text_vp
->height
= font_get(title_text_vp
->font
)->height
;
93 if (list
->title_icon
!= Icon_NOICON
&& global_settings
.show_icons
)
95 struct viewport title_icon
= *title_text_vp
;
97 title_icon
.width
= get_icon_width(screen
) + ICON_PADDING
* 2;
98 if (VP_IS_RTL(&title_icon
))
100 title_icon
.x
+= title_text_vp
->width
- title_icon
.width
;
104 title_text_vp
->x
+= title_icon
.width
;
106 title_text_vp
->width
-= title_icon
.width
;
108 display
->set_viewport(&title_icon
);
109 screen_put_icon(display
, 0, 0, list
->title_icon
);
111 #ifdef HAVE_LCD_COLOR
112 if (list
->title_color
>= 0)
114 style
|= (STYLE_COLORED
|list
->title_color
);
117 display
->set_viewport(title_text_vp
);
118 display
->puts_scroll_style(0, 0, list
->title
, style
);
122 void list_draw(struct screen
*display
, struct gui_synclist
*list
)
124 struct viewport list_icons
;
125 int start
, end
, line_height
, style
, i
;
126 const int screen
= display
->screen_type
;
127 const int list_start_item
= list
->start_item
[screen
];
128 const int icon_width
= get_icon_width(screen
) + ICON_PADDING
;
129 const bool scrollbar_in_left
= (global_settings
.scrollbar
== SCROLLBAR_LEFT
);
130 const bool show_cursor
= !global_settings
.cursor_style
&&
131 list
->show_selection_marker
;
132 struct viewport
*parent
= (list
->parent
[screen
]);
133 #ifdef HAVE_LCD_COLOR
134 unsigned char cur_line
= 0;
138 struct viewport
*list_text_vp
= &list_text
[screen
];
140 line_height
= font_get(parent
->font
)->height
;
141 display
->set_viewport(parent
);
142 display
->clear_viewport();
143 display
->scroll_stop(list_text_vp
);
144 *list_text_vp
= *parent
;
145 if ((show_title
= draw_title(display
, list
)))
147 list_text_vp
->y
+= line_height
;
148 list_text_vp
->height
-= line_height
;
151 start
= list_start_item
;
152 end
= start
+ viewport_get_nb_lines(list_text_vp
);
154 /* draw the scrollbar if its needed */
155 if (global_settings
.scrollbar
&&
156 viewport_get_nb_lines(list_text_vp
) < list
->nb_items
)
160 vp
.width
= SCROLLBAR_WIDTH
;
161 vp
.height
= line_height
* viewport_get_nb_lines(list_text_vp
);
163 list_text_vp
->width
-= SCROLLBAR_WIDTH
;
164 if (scrollbar_in_left
)
165 list_text_vp
->x
+= SCROLLBAR_WIDTH
;
167 vp
.x
+= list_text_vp
->width
;
168 display
->set_viewport(&vp
);
169 gui_scrollbar_draw(display
,
170 (scrollbar_in_left
? 0: 1), 0, SCROLLBAR_WIDTH
-1, vp
.height
,
171 list
->nb_items
, list_start_item
, list_start_item
+ end
-start
,
176 /* shift everything a bit in relation to the title... */
177 if (!VP_IS_RTL(list_text_vp
) && scrollbar_in_left
)
179 list_text_vp
->width
-= SCROLLBAR_WIDTH
;
180 list_text_vp
->x
+= SCROLLBAR_WIDTH
;
182 else if (VP_IS_RTL(list_text_vp
) && !scrollbar_in_left
)
184 list_text_vp
->width
-= SCROLLBAR_WIDTH
;
188 /* setup icon placement */
189 list_icons
= *list_text_vp
;
190 int icon_count
= (list
->callback_get_item_icon
!= NULL
) ? 1 : 0;
195 list_icons
.width
= icon_width
* icon_count
;
196 list_text_vp
->width
-= list_icons
.width
+ ICON_PADDING
;
197 if (VP_IS_RTL(&list_icons
))
198 list_icons
.x
+= list_text_vp
->width
+ ICON_PADDING
;
200 list_text_vp
->x
+= list_icons
.width
+ ICON_PADDING
;
203 for (i
=start
; i
<end
&& i
<list
->nb_items
; i
++)
206 unsigned const char *s
;
207 char entry_buffer
[MAX_PATH
];
208 unsigned char *entry_name
;
210 s
= list
->callback_get_item_name(i
, list
->data
, entry_buffer
,
211 sizeof(entry_buffer
));
212 entry_name
= P2STR(s
);
213 display
->set_viewport(list_text_vp
);
214 style
= STYLE_DEFAULT
;
215 /* position the string at the correct offset place */
217 display
->getstringsize(entry_name
, &item_width
, &h
);
218 item_offset
= gui_list_get_item_offset(list
, item_width
, text_pos
,
219 display
, list_text_vp
);
221 #ifdef HAVE_LCD_COLOR
222 /* if the list has a color callback */
223 if (list
->callback_get_item_color
)
225 int color
= list
->callback_get_item_color(i
, list
->data
);
226 /* if color selected */
229 style
|= STYLE_COLORED
|color
;
233 if(i
>= list
->selected_item
&& i
< list
->selected_item
234 + list
->selected_size
&& list
->show_selection_marker
)
235 {/* The selected item must be displayed scrolling */
236 if (global_settings
.cursor_style
== 1
237 #ifdef HAVE_REMOTE_LCD
238 /* the global_settings.cursor_style check is here to make
239 * sure if they want the cursor instead of bar it will work
241 || (display
->depth
< 16 && global_settings
.cursor_style
)
245 /* Display inverted-line-style */
246 style
= STYLE_INVERT
;
248 #ifdef HAVE_LCD_COLOR
249 else if (global_settings
.cursor_style
== 2)
251 /* Display colour line selector */
252 style
= STYLE_COLORBAR
;
254 else if (global_settings
.cursor_style
== 3)
256 /* Display gradient line selector */
257 style
= STYLE_GRADIENT
;
259 /* Make the lcd driver know how many lines the gradient should
260 cover and current line number */
261 /* number of selected lines */
262 style
|= NUMLN_PACK(list
->selected_size
);
263 /* current line number, zero based */
264 style
|= CURLN_PACK(cur_line
);
268 /* if the text is smaller than the viewport size */
269 if (item_offset
> item_width
- (list_text_vp
->width
- text_pos
))
272 display
->puts_style_offset(0, i
-start
, entry_name
,
277 display
->puts_scroll_style_offset(0, i
-start
, entry_name
,
283 if (list
->scroll_all
)
284 display
->puts_scroll_style_offset(0, i
-start
, entry_name
,
287 display
->puts_style_offset(0, i
-start
, entry_name
,
291 display
->set_viewport(&list_icons
);
292 if (list
->callback_get_item_icon
&& global_settings
.show_icons
)
294 screen_put_icon_with_offset(display
, show_cursor
?1:0,
295 (i
-start
),show_cursor
?ICON_PADDING
:0,0,
296 list
->callback_get_item_icon(i
, list
->data
));
298 if (show_cursor
&& i
>= list
->selected_item
&&
299 i
< list
->selected_item
+ list
->selected_size
)
301 screen_put_icon(display
, 0, i
-start
, Icon_Cursor
);
304 display
->set_viewport(parent
);
305 display
->update_viewport();
306 display
->set_viewport(NULL
);
309 #if defined(HAVE_TOUCHSCREEN)
310 /* This needs to be fixed if we ever get more than 1 touchscreen on a target. */
311 static bool scrolling
=false;
313 static int gui_synclist_touchscreen_scrollbar(struct gui_synclist
* gui_list
,
316 const int screen
= screens
[SCREEN_MAIN
].screen_type
;
317 const int nb_lines
= viewport_get_nb_lines(&list_text
[screen
]);
319 if (nb_lines
< gui_list
->nb_items
)
323 int scrollbar_size
= nb_lines
*
324 font_get(gui_list
->parent
[screen
]->font
)->height
;
325 int actual_y
= y
- list_text
[screen
].y
;
327 int new_selection
= (actual_y
* gui_list
->nb_items
)
330 int start_item
= new_selection
- nb_lines
/2;
333 else if(start_item
> gui_list
->nb_items
- nb_lines
)
334 start_item
= gui_list
->nb_items
- nb_lines
;
336 gui_list
->start_item
[screen
] = start_item
;
337 gui_synclist_select_item(gui_list
, new_selection
);
339 return ACTION_REDRAW
;
345 unsigned gui_synclist_do_touchscreen(struct gui_synclist
* gui_list
)
348 const int button
= action_get_touchscreen_press(&x
, &y
);
350 const int screen
= SCREEN_MAIN
;
351 const int list_start_item
= gui_list
->start_item
[screen
];
352 const struct viewport
*list_text_vp
= &list_text
[screen
];
353 int list_width
= list_text_vp
->width
;
355 if (global_settings
.scrollbar
== SCROLLBAR_RIGHT
)
356 list_width
+= SCROLLBAR_WIDTH
;
358 if (button
== BUTTON_NONE
)
361 if (x
> list_text_vp
->x
+ list_width
)
364 /* make sure it is inside the UI viewport */
365 if (list_display_title(gui_list
, screen
) &&
366 viewport_point_within_vp(&title_text
[screen
], x
, y
) &&
367 button
== BUTTON_REL
)
368 return ACTION_STD_CANCEL
;
370 if (x
< list_text_vp
->x
)
372 /* Top left corner is GO_TO_ROOT */
373 if (y
<list_text
[SCREEN_MAIN
].y
)
375 if (button
== BUTTON_REL
)
376 return ACTION_STD_MENU
;
377 else if (button
== (BUTTON_REPEAT
|BUTTON_REL
))
378 return ACTION_STD_CONTEXT
;
383 else if(global_settings
.scrollbar
== SCROLLBAR_LEFT
)
384 return gui_synclist_touchscreen_scrollbar(gui_list
, y
);
388 if (x
> list_text_vp
->x
+ list_text_vp
->width
&&
389 global_settings
.scrollbar
== SCROLLBAR_RIGHT
)
390 return gui_synclist_touchscreen_scrollbar(gui_list
, y
);
392 /* |--------------------------------------------------------|
393 * | Description of the touchscreen list interface: |
394 * |--------------------------------------------------------|
395 * | Pressing an item will select it and "enter" it. |
397 * | Pressing and holding your pen down will scroll through |
398 * | the list of items. |
400 * | Pressing and holding your pen down on a single item |
401 * | will bring up the context menu of it. |
402 * |--------------------------------------------------------|
404 if (y
> list_text_vp
->y
|| button
& BUTTON_REPEAT
)
406 int line_height
, actual_y
;
408 actual_y
= y
- list_text_vp
->y
;
409 line_height
= font_get(gui_list
->parent
[screen
]->font
)->height
;
410 line
= actual_y
/ line_height
;
412 /* Pressed below the list*/
413 if (list_start_item
+ line
>= gui_list
->nb_items
)
416 /* Pressed a border */
417 if(UNLIKELY(actual_y
% line_height
== 0))
420 if (line
!= (gui_list
->selected_item
- list_start_item
)
421 && button
^ BUTTON_REL
)
423 if(button
& BUTTON_REPEAT
)
426 gui_synclist_select_item(gui_list
, list_start_item
+ line
);
428 return ACTION_REDRAW
;
431 /* This has the same effect as the icons do when the scrollbar
432 is on the left (ie eliminate the chances an user enters/starts
433 an item when he wanted to use the scrollbar, due to touchscreen
436 if(global_settings
.scrollbar
== SCROLLBAR_RIGHT
&&
437 x
> list_text_vp
->x
+ list_text_vp
->width
-
438 get_icon_width(SCREEN_MAIN
))
441 if (button
== (BUTTON_REPEAT
|BUTTON_REL
))
445 /* Pen was hold on the same line as the
446 * previously selected one
447 * => simulate long button press
449 return ACTION_STD_CONTEXT
;
453 /* Pen was moved across several lines and then released on
461 else if(button
== BUTTON_REL
&&
462 line
== gui_list
->selected_item
- list_start_item
)
464 /* Pen was released on either the same line as the previously
465 * selected one or an other one
466 * => simulate short press
468 return ACTION_STD_OK
;