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"
43 #define ICON_PADDING 1
45 /* these are static to make scrolling work */
46 static struct viewport list_text
[NB_SCREENS
], title_text
[NB_SCREENS
];
48 int gui_list_get_item_offset(struct gui_synclist
* gui_list
, int item_width
,
49 int text_pos
, struct screen
* display
,
51 bool list_display_title(struct gui_synclist
*list
, enum screen_type screen
);
54 internal screen layout:
56 |TI| title | TI is title icon
60 | | | items | I - icons
64 static bool draw_title(struct screen
*display
, struct gui_synclist
*list
)
66 const int screen
= display
->screen_type
;
67 int style
= STYLE_DEFAULT
;
68 if (!list_display_title(list
, screen
))
70 title_text
[screen
] = *(list
->parent
[screen
]);
71 title_text
[screen
].height
= font_get(title_text
[screen
].font
)->height
;
73 if (list
->title_icon
!= Icon_NOICON
&& global_settings
.show_icons
)
75 struct viewport title_icon
= title_text
[screen
];
76 title_icon
.width
= get_icon_width(screen
)
78 title_icon
.x
+= ICON_PADDING
;
80 title_text
[screen
].width
-= title_icon
.width
;
81 title_text
[screen
].x
+= title_icon
.width
;
83 display
->set_viewport(&title_icon
);
84 screen_put_icon(display
, 0, 0, list
->title_icon
);
87 if (list
->title_color
>= 0)
89 style
|= (STYLE_COLORED
|list
->title_color
);
92 display
->set_viewport(&title_text
[screen
]);
93 display
->puts_scroll_style(0, 0, list
->title
, style
);
97 void list_draw(struct screen
*display
, struct gui_synclist
*list
)
99 struct viewport list_icons
;
100 int start
, end
, line_height
, style
, i
;
101 const int screen
= display
->screen_type
;
102 const int icon_width
= get_icon_width(screen
) + ICON_PADDING
;
103 const bool show_cursor
= !global_settings
.cursor_style
&&
104 list
->show_selection_marker
;
105 struct viewport
*parent
= (list
->parent
[screen
]);
106 #ifdef HAVE_LCD_COLOR
107 unsigned char cur_line
= 0;
111 line_height
= font_get(parent
->font
)->height
;
112 display
->set_viewport(parent
);
113 display
->clear_viewport();
114 display
->stop_scroll();
115 list_text
[screen
] = *parent
;
116 if ((show_title
= draw_title(display
, list
)))
118 list_text
[screen
].y
+= line_height
;
119 list_text
[screen
].height
-= line_height
;
122 start
= list
->start_item
[screen
];
123 end
= start
+ viewport_get_nb_lines(&list_text
[screen
]);
125 /* draw the scrollbar if its needed */
126 if (global_settings
.scrollbar
&&
127 viewport_get_nb_lines(&list_text
[screen
]) < list
->nb_items
)
130 vp
= list_text
[screen
];
131 vp
.width
= SCROLLBAR_WIDTH
;
132 list_text
[screen
].width
-= SCROLLBAR_WIDTH
;
133 if(global_settings
.scrollbar
== SCROLLBAR_LEFT
)
134 list_text
[screen
].x
+= SCROLLBAR_WIDTH
;
135 vp
.height
= line_height
*
136 viewport_get_nb_lines(&list_text
[screen
]);
138 if(global_settings
.scrollbar
== SCROLLBAR_RIGHT
) /* right */
139 vp
.x
+= list_text
[screen
].width
;
140 display
->set_viewport(&vp
);
141 gui_scrollbar_draw(display
, 0, 0, SCROLLBAR_WIDTH
-1,
142 vp
.height
, list
->nb_items
,
143 list
->start_item
[screen
],
144 list
->start_item
[screen
] + end
-start
,
149 /* shift everything right a bit... */
150 if(global_settings
.scrollbar
== SCROLLBAR_LEFT
)
152 list_text
[screen
].width
-= SCROLLBAR_WIDTH
;
153 list_text
[screen
].x
+= SCROLLBAR_WIDTH
;
157 /* setup icon placement */
158 list_icons
= list_text
[screen
];
159 int icon_count
= global_settings
.show_icons
&&
160 (list
->callback_get_item_icon
!= NULL
) ? 1 : 0;
165 list_icons
.width
= icon_width
* icon_count
;
166 list_text
[screen
].width
-=
167 list_icons
.width
+ ICON_PADDING
;
168 list_text
[screen
].x
+=
169 list_icons
.width
+ ICON_PADDING
;
172 for (i
=start
; i
<end
&& i
<list
->nb_items
; i
++)
176 char entry_buffer
[MAX_PATH
];
177 unsigned char *entry_name
;
179 s
= list
->callback_get_item_name(i
, list
->data
, entry_buffer
,
180 sizeof(entry_buffer
));
181 entry_name
= P2STR(s
);
182 display
->set_viewport(&list_text
[screen
]);
183 style
= STYLE_DEFAULT
;
184 /* position the string at the correct offset place */
186 display
->getstringsize(entry_name
, &item_width
, &h
);
187 item_offset
= gui_list_get_item_offset(list
, item_width
,
191 #ifdef HAVE_LCD_COLOR
192 /* if the list has a color callback */
193 if (list
->callback_get_item_color
)
195 int color
= list
->callback_get_item_color(i
, list
->data
);
196 /* if color selected */
199 style
|= STYLE_COLORED
|color
;
203 if(i
>= list
->selected_item
&& i
< list
->selected_item
204 + list
->selected_size
&& list
->show_selection_marker
)
205 {/* The selected item must be displayed scrolling */
206 if (global_settings
.cursor_style
== 1
207 #ifdef HAVE_REMOTE_LCD
208 /* the global_settings.cursor_style check is here to make
209 * sure if they want the cursor instead of bar it will work
211 || (display
->depth
< 16 && global_settings
.cursor_style
)
215 /* Display inverted-line-style */
216 style
= STYLE_INVERT
;
218 #ifdef HAVE_LCD_COLOR
219 else if (global_settings
.cursor_style
== 2)
221 /* Display colour line selector */
222 style
= STYLE_COLORBAR
;
224 else if (global_settings
.cursor_style
== 3)
226 /* Display gradient line selector */
227 style
= STYLE_GRADIENT
;
229 /* Make the lcd driver know how many lines the gradient should
230 cover and current line number */
231 /* number of selected lines */
232 style
|= NUMLN_PACK(list
->selected_size
);
233 /* current line number, zero based */
234 style
|= CURLN_PACK(cur_line
);
238 /* if the text is smaller than the viewport size */
239 if (item_offset
> item_width
240 - (list_text
[screen
].width
- text_pos
))
243 display
->puts_style_offset(0, i
-start
, entry_name
,
248 display
->puts_scroll_style_offset(0, i
-start
, entry_name
,
254 if (list
->scroll_all
)
255 display
->puts_scroll_style_offset(0, i
-start
, entry_name
,
258 display
->puts_style_offset(0, i
-start
, entry_name
,
262 if (list
->callback_get_item_icon
&& global_settings
.show_icons
)
264 display
->set_viewport(&list_icons
);
265 screen_put_icon_with_offset(display
, show_cursor
?1:0,
266 (i
-start
),show_cursor
?ICON_PADDING
:0,0,
267 list
->callback_get_item_icon(i
, list
->data
));
268 if (show_cursor
&& i
>= list
->selected_item
&&
269 i
< list
->selected_item
+ list
->selected_size
)
271 screen_put_icon(display
, 0, i
-start
, Icon_Cursor
);
274 else if (show_cursor
&& i
>= list
->selected_item
&&
275 i
< list
->selected_item
+ list
->selected_size
)
277 display
->set_viewport(&list_icons
);
278 screen_put_icon(display
, 0, (i
-start
), Icon_Cursor
);
281 display
->set_viewport(parent
);
282 display
->update_viewport();
283 display
->set_viewport(NULL
);
286 #if defined(HAVE_TOUCHSCREEN)
287 /* This needs to be fixed if we ever get more than 1 touchscreen on a target.
288 * This also assumes the whole screen is used, which is a bad assumption but
289 * fine until customizable lists comes in...
291 static bool scrolling
=false;
293 static int gui_synclist_touchscreen_scrollbar(struct gui_synclist
* gui_list
,
296 int screen
= screens
[SCREEN_MAIN
].screen_type
;
297 int nb_lines
= viewport_get_nb_lines(&list_text
[screen
]);
298 if (nb_lines
< gui_list
->nb_items
)
300 int scrollbar_size
= nb_lines
*
301 font_get(gui_list
->parent
[screen
]->font
)->height
;
302 int actual_y
= y
- list_text
[screen
].y
;
304 int new_selection
= (actual_y
* gui_list
->nb_items
)
307 int start_item
= new_selection
- nb_lines
/2;
310 else if(start_item
> gui_list
->nb_items
- nb_lines
)
311 start_item
= gui_list
->nb_items
- nb_lines
;
313 gui_list
->start_item
[screen
] = start_item
;
314 gui_synclist_select_item(gui_list
, new_selection
);
316 return ACTION_REDRAW
;
322 unsigned gui_synclist_do_touchscreen(struct gui_synclist
* gui_list
)
325 int button
= action_get_touchscreen_press(&x
, &y
);
327 struct screen
*display
= &screens
[SCREEN_MAIN
];
328 int screen
= display
->screen_type
;
329 if (button
== BUTTON_NONE
)
331 if (x
<list_text
[screen
].x
)
333 /* Top left corner is GO_TO_ROOT */
334 if (y
<list_text
[SCREEN_MAIN
].y
)
336 if (button
== BUTTON_REL
)
337 return ACTION_STD_MENU
;
338 else if (button
== (BUTTON_REPEAT
|BUTTON_REL
))
339 return ACTION_STD_CONTEXT
;
344 else if(global_settings
.scrollbar
== SCROLLBAR_LEFT
)
345 return gui_synclist_touchscreen_scrollbar(gui_list
, y
);
349 if(x
>list_text
[screen
].x
+list_text
[screen
].width
&&
350 global_settings
.scrollbar
== SCROLLBAR_RIGHT
)
351 return gui_synclist_touchscreen_scrollbar(gui_list
, y
);
353 /* |--------------------------------------------------------|
354 * | Description of the touchscreen list interface: |
355 * |--------------------------------------------------------|
356 * | Pressing an item will select it and "enter" it. |
358 * | Pressing and holding your pen down will scroll through |
359 * | the list of items. |
361 * | Pressing and holding your pen down on a single item |
362 * | will bring up the context menu of it. |
363 * |--------------------------------------------------------|
365 if (y
> list_text
[screen
].y
|| button
& BUTTON_REPEAT
)
367 int line_height
, actual_y
;
369 actual_y
= y
- list_text
[screen
].y
;
370 line_height
= font_get(gui_list
->parent
[screen
]->font
)->height
;
371 line
= actual_y
/ line_height
;
373 /* Pressed below the list*/
374 if (gui_list
->start_item
[screen
]+line
>= gui_list
->nb_items
)
377 /* Pressed a border */
378 if(UNLIKELY(actual_y
% line_height
== 0))
381 if (line
!= (gui_list
->selected_item
- gui_list
->start_item
[screen
])
382 && button
^ BUTTON_REL
)
384 if(button
& BUTTON_REPEAT
)
387 gui_synclist_select_item(gui_list
, gui_list
->start_item
[screen
]
390 return ACTION_REDRAW
;
393 if (button
== (BUTTON_REPEAT
|BUTTON_REL
))
397 /* Pen was hold on the same line as the
398 * previously selected one
399 * => simulate long button press
401 return ACTION_STD_CONTEXT
;
405 /* Pen was moved across several lines and then released on
413 else if(button
== BUTTON_REL
&&
414 line
== gui_list
->selected_item
- gui_list
->start_item
[screen
])
416 /* Pen was released on either the same line as the previously
417 * selected one or an other one
418 * => simulate short press
420 return ACTION_STD_OK
;
425 /* Everything above the items is cancel */
426 else if (y
< list_text
[screen
].y
&& button
== BUTTON_REL
)
427 return ACTION_STD_CANCEL
;