A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Jonathan Gordon
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 "config.h"
23#include "system.h"
24#include "lcd.h"
25#include "font.h"
26#include "button.h"
27#include "string.h"
28#include "settings.h"
29#include "kernel.h"
30#include "file.h"
31
32#include "action.h"
33#include "screen_access.h"
34#include "list.h"
35#include "scrollbar.h"
36#include "lang.h"
37#include "sound.h"
38#include "misc.h"
39#include "viewport.h"
40#include "statusbar-skinned.h"
41#include "skin_engine/skin_engine.h"
42#include "skin_engine/skin_display.h"
43#include "appevents.h"
44
45static struct listitem_viewport_cfg *listcfg[NB_SCREENS] = {NULL};
46static struct gui_synclist *current_list;
47
48static int current_row;
49static int current_column;
50
51void skinlist_set_cfg(enum screen_type screen,
52 struct listitem_viewport_cfg *cfg)
53{
54 if (listcfg[screen] != cfg)
55 {
56 if (listcfg[screen])
57 screens[screen].scroll_stop_viewport(&listcfg[screen]->selected_item_vp.vp);
58 listcfg[screen] = cfg;
59 current_list = NULL;
60 current_column = -1;
61 current_row = -1;
62 }
63}
64
65static bool skinlist_is_configured(enum screen_type screen,
66 struct gui_synclist *list)
67{
68 return (listcfg[screen] != NULL) &&
69 (!list || (list && list->selected_size == 1));
70}
71static int current_drawing_line;
72static int offset_to_item(int offset, bool wrap)
73{
74 int item = current_drawing_line + offset;
75 if (!current_list || current_list->nb_items == 0)
76 return -1;
77 if (item < 0)
78 {
79 if (!wrap)
80 return -1;
81 else
82 item = (item + current_list->nb_items) % current_list->nb_items;
83 }
84 else if (item >= current_list->nb_items && !wrap)
85 return -1;
86 else
87 item = item % current_list->nb_items;
88 return item;
89}
90
91int skinlist_get_item_number()
92{
93 return current_drawing_line;
94}
95
96int skinlist_get_item_row()
97{
98 return current_row;
99}
100
101int skinlist_get_item_column()
102{
103 return current_column;
104}
105
106
107const char* skinlist_get_item_text(int offset, bool wrap, char* buf, size_t buf_size)
108{
109 int item = offset_to_item(offset, wrap);
110 if (item < 0 || !current_list)
111 return NULL;
112 const char* ret = current_list->callback_get_item_name(
113 item, current_list->data, buf, buf_size);
114 return P2STR((unsigned char*)ret);
115}
116
117enum themable_icons skinlist_get_item_icon(int offset, bool wrap)
118{
119 int item = offset_to_item(offset, wrap);
120 if (item < 0 || !current_list || current_list->callback_get_item_icon == NULL)
121 return Icon_NOICON;
122 return current_list->callback_get_item_icon(item, current_list->data);
123}
124
125static bool is_selected = false;
126bool skinlist_is_selected_item(void)
127{
128 return is_selected;
129}
130
131int skinlist_get_line_count(enum screen_type screen, struct gui_synclist *list)
132{
133 struct viewport *parent = (list->parent[screen]);
134 if (!skinlist_is_configured(screen, list))
135 return -1;
136 if (listcfg[screen]->tile == true)
137 {
138 int rows = (parent->height / listcfg[screen]->height);
139 int cols = (parent->width / listcfg[screen]->width);
140 return rows*cols;
141 }
142 else
143 return (parent->height / listcfg[screen]->height);
144}
145
146static int current_item;
147static int current_nbitems;
148static bool needs_scrollbar[NB_SCREENS];
149bool skinlist_needs_scrollbar(enum screen_type screen)
150{
151 return needs_scrollbar[screen];
152}
153
154void skinlist_get_scrollbar(int* nb_item, int* first_shown, int* last_shown)
155{
156 if (!skinlist_is_configured(0, NULL))
157 {
158 *nb_item = 0;
159 *first_shown = 0;
160 *last_shown = 0;
161 }
162 else
163 {
164 *nb_item = current_item;
165 *first_shown = 0;
166 *last_shown = current_nbitems;
167 }
168}
169
170bool skinlist_get_item(struct screen *display, struct gui_synclist *list, int x, int y, int *item)
171{
172 const int screen = display->screen_type;
173 if (!skinlist_is_configured(screen, list))
174 return false;
175
176 int row = y / listcfg[screen]->height;
177 int column = x / listcfg[screen]->width;
178 struct viewport *parent = (list->parent[screen]);
179 int cols = (parent->width / listcfg[screen]->width);
180 *item = row * cols+ column;
181 return true;
182}
183
184bool skinlist_draw(struct screen *display, struct gui_synclist *list)
185{
186 int cur_line, display_lines;
187 const int screen = display->screen_type;
188 struct viewport *parent = (list->parent[screen]);
189 char* label = NULL;
190 const int list_start_item = list->start_item[screen];
191 struct gui_wps wps;
192 if (!skinlist_is_configured(screen, list))
193 return false;
194
195 current_list = list;
196 wps.display = display;
197 wps.data = listcfg[screen]->data;
198 display_lines = skinlist_get_line_count(screen, list);
199 label = (char *)SKINOFFSETTOPTR(get_skin_buffer(wps.data), listcfg[screen]->label);
200 if (!label)
201 return false;
202
203 display->set_viewport(parent);
204 display->clear_viewport();
205 current_item = list->selected_item;
206 current_nbitems = list->nb_items;
207 needs_scrollbar[screen] = list->nb_items > display_lines;
208
209 for (cur_line = 0; cur_line < display_lines; cur_line++)
210 {
211 struct skin_element* viewport;
212 struct skin_viewport* skin_viewport = NULL;
213 if (list_start_item+cur_line+1 > list->nb_items)
214 break;
215 current_drawing_line = list_start_item+cur_line;
216 is_selected = list_start_item+cur_line == list->selected_item;
217
218 for (viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), listcfg[screen]->data->tree);
219 viewport;
220 viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->next))
221 {
222 int original_x, original_y;
223 skin_viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->data);
224 char *viewport_label = NULL;
225 if (skin_viewport)
226 viewport_label = SKINOFFSETTOPTR(get_skin_buffer(wps.data), skin_viewport->label);
227 if (viewport->children == 0 || !viewport_label ||
228 (skin_viewport->label && strcmp(label, viewport_label))
229 )
230 continue;
231 if (is_selected)
232 {
233 memcpy(&listcfg[screen]->selected_item_vp, skin_viewport, sizeof(struct skin_viewport));
234 skin_viewport = &listcfg[screen]->selected_item_vp;
235 }
236 original_x = skin_viewport->vp.x;
237 original_y = skin_viewport->vp.y;
238 if (listcfg[screen]->tile)
239 {
240 int cols = (parent->width / listcfg[screen]->width);
241 current_column = (cur_line)%cols;
242 current_row = (cur_line)/cols;
243
244 skin_viewport->vp.x = parent->x + listcfg[screen]->width*current_column + original_x;
245 skin_viewport->vp.y = parent->y + listcfg[screen]->height*current_row + original_y;
246 }
247 else
248 {
249 current_column = 1;
250 current_row = cur_line;
251 skin_viewport->vp.x = parent->x + original_x;
252 skin_viewport->vp.y = parent->y + original_y +
253 (listcfg[screen]->height*cur_line);
254 }
255 display->set_viewport(&skin_viewport->vp);
256 /* Set images to not to be displayed */
257 struct skin_token_list *imglist = SKINOFFSETTOPTR(get_skin_buffer(wps.data), wps.data->images);
258 while (imglist)
259 {
260 struct wps_token *token = SKINOFFSETTOPTR(get_skin_buffer(wps.data), imglist->token);
261 struct gui_img *img = NULL;
262 if (token)
263 img = SKINOFFSETTOPTR(get_skin_buffer(wps.data), token->value.data);
264 if (img)
265 img->display = -1;
266 imglist = SKINOFFSETTOPTR(get_skin_buffer(wps.data), imglist->next);
267 }
268 struct skin_element** children = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->children);
269 if (children && *children)
270 skin_render_viewport(SKINOFFSETTOPTR(get_skin_buffer(wps.data), (intptr_t)children[0]),
271 &wps, skin_viewport, SKIN_REFRESH_ALL);
272 wps_display_images(&wps, &skin_viewport->vp);
273 /* force disableing scroll because it breaks later */
274 if (!is_selected)
275 {
276 display->scroll_stop_viewport(&skin_viewport->vp);
277 skin_viewport->vp.x = original_x;
278 skin_viewport->vp.y = original_y;
279 }
280 }
281 }
282 current_column = -1;
283 current_row = -1;
284 display->set_viewport(parent);
285 display->update_viewport();
286 current_drawing_line = list->selected_item;
287 return true;
288}