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) 2002 by Robert Hak <rhak at ramapo.edu>
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#include "plugin.h"
22#include "lib/helper.h"
23
24#ifdef HAVE_REMOTE_LCD
25#define REMOTE_WIDTH LCD_REMOTE_WIDTH
26#define REMOTE_HEIGHT LCD_REMOTE_HEIGHT
27#include "pluginbitmaps/remote_creditslogo.h"
28#define REMOTE_LOGO_WIDTH BMPWIDTH_remote_creditslogo
29#define REMOTE_LOGO_HEIGHT BMPHEIGHT_remote_creditslogo
30#define REMOTE_LOGO (const fb_remote_data*)remote_creditslogo
31#endif /* HAVE_REMOTE_LCD */
32
33#define LOGO (const fb_data*)creditslogo
34#include "pluginbitmaps/creditslogo.h"
35#define LOGO_WIDTH BMPWIDTH_creditslogo
36#define LOGO_HEIGHT BMPHEIGHT_creditslogo
37
38static const char* const credits[] = {
39#include "credits.raw" /* generated list of names from docs/CREDITS */
40};
41
42static bool stop_autoscroll(int action)
43{
44 switch (action)
45 {
46 case ACTION_STD_CANCEL:
47 case ACTION_STD_OK:
48 case ACTION_STD_NEXT:
49 case ACTION_STD_NEXTREPEAT:
50 case ACTION_STD_PREV:
51 case ACTION_STD_PREVREPEAT:
52 return true;
53 default:
54 return false;
55 }
56 return false;
57}
58
59static int update_rowpos(int action, int cur_pos, int rows_per_screen, int tot_rows)
60{
61 switch(action)
62 {
63 case ACTION_STD_PREV:
64 case ACTION_STD_PREVREPEAT:
65 cur_pos--;
66 break;
67 case ACTION_STD_NEXT:
68 case ACTION_STD_NEXTREPEAT:
69 cur_pos++;
70 break;
71 }
72
73 if(cur_pos > tot_rows - rows_per_screen)
74 cur_pos = 0;
75 if(cur_pos < 0)
76 cur_pos = tot_rows - rows_per_screen;
77
78 return cur_pos;
79}
80
81static void roll_credits(void)
82{
83 /* to do: use target defines iso keypads to set animation timings */
84#if (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
85 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
86 #define PAUSE_TIME 0
87 #define ANIM_SPEED 100
88#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
89 #define PAUSE_TIME 0
90 #define ANIM_SPEED 35
91#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
92 #define PAUSE_TIME 0
93 #define ANIM_SPEED 100
94#else
95 #define PAUSE_TIME 1
96 #define ANIM_SPEED 40
97#endif
98
99 #define NUM_VISIBLE_LINES (LCD_HEIGHT/font_h - 1)
100 #define CREDITS_TARGETPOS ((LCD_WIDTH/2)-(credits_w/2))
101
102 int i=0, j=0, namepos=0, offset_dummy;
103 int name_w, name_h, name_targetpos=1, font_h;
104 int credits_w, credits_pos;
105 int numnames = (sizeof(credits)/sizeof(char*));
106 char name[40], elapsednames[32];
107 int action = ACTION_NONE;
108
109 /* control if scrolling is automatic (with animation) or manual */
110 bool manual_scroll = false;
111
112 rb->lcd_setfont(FONT_UI);
113 rb->lcd_clear_display();
114 rb->lcd_update();
115
116 rb->lcd_getstringsize("A", NULL, &font_h);
117
118 /* snprintf "credits" text, and save the width and height */
119 rb->snprintf(elapsednames, sizeof(elapsednames), "[Credits] %d/%d",
120 j+1, numnames);
121 rb->lcd_getstringsize(elapsednames, &credits_w, NULL);
122
123 /* fly in "credits" text from the left */
124 for(credits_pos = 0 - credits_w; credits_pos <= CREDITS_TARGETPOS;
125 credits_pos += (CREDITS_TARGETPOS-credits_pos + 14) / 7)
126 {
127 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
128 rb->lcd_fillrect(0, 0, LCD_WIDTH, font_h);
129 rb->lcd_set_drawmode(DRMODE_SOLID);
130 rb->lcd_putsxy(credits_pos, 0, elapsednames);
131 rb->lcd_update_rect(0, 0, LCD_WIDTH, font_h);
132 rb->sleep(HZ/ANIM_SPEED);
133 }
134
135 /* first screen's worth of lines fly in */
136 for(i=0; i<NUM_VISIBLE_LINES; i++)
137 {
138 rb->snprintf(name, sizeof(name), "%s", credits[i]);
139 rb->lcd_getstringsize(name, &name_w, &name_h);
140
141 rb->snprintf(elapsednames, sizeof(elapsednames), "[Credits] %d/%d",
142 i+1, numnames);
143 rb->lcd_getstringsize(elapsednames, &credits_w, NULL);
144 rb->lcd_putsxy(CREDITS_TARGETPOS, 0, elapsednames);
145 rb->lcd_update_rect(CREDITS_TARGETPOS, 0, credits_w, font_h);
146
147 for(namepos = 0-name_w; namepos <= name_targetpos;
148 namepos += (name_targetpos - namepos + 14) / 7)
149 {
150 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
151 /* clear any trails left behind */
152 rb->lcd_fillrect(0, font_h*(i+1), LCD_WIDTH, font_h);
153 rb->lcd_set_drawmode(DRMODE_SOLID);
154 rb->lcd_putsxy(namepos, font_h*(i+1), name);
155 rb->lcd_update_rect(0, font_h*(i+1), LCD_WIDTH, font_h);
156
157 /* exit on abort, switch to manual on up/down */
158 action = rb->get_action(CONTEXT_LIST, HZ/ANIM_SPEED);
159 if(stop_autoscroll(action))
160 break;
161 }
162 if(stop_autoscroll(action))
163 break;
164 }
165
166 /* process user actions (if any) */
167 if(ACTION_STD_CANCEL == action)
168 return;
169 if(stop_autoscroll(action))
170 manual_scroll = true; /* up/down - abort was catched above */
171
172 if(!manual_scroll)
173 {
174 j+= i;
175
176 /* pause for a bit if needed */
177 action = rb->get_action(CONTEXT_LIST, HZ*PAUSE_TIME);
178 if(ACTION_STD_CANCEL == action)
179 return;
180 if(stop_autoscroll(action))
181 manual_scroll = true;
182 }
183
184 if(!manual_scroll)
185 {
186 while(j < numnames)
187 {
188 /* just a screen's worth at a time */
189 for(i=0; i<NUM_VISIBLE_LINES; i++)
190 {
191 if(j+i >= numnames)
192 break;
193 offset_dummy=1;
194
195 rb->snprintf(name, sizeof(name), "%s",
196 credits[j+i-NUM_VISIBLE_LINES]);
197 rb->lcd_getstringsize(name, &name_w, &name_h);
198
199 /* fly out an existing line.. */
200 while(namepos<LCD_WIDTH+offset_dummy)
201 {
202 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
203 /* clear trails */
204 rb->lcd_fillrect(0, font_h*(i+1), LCD_WIDTH, font_h);
205 rb->lcd_set_drawmode(DRMODE_SOLID);
206 rb->lcd_putsxy(namepos, font_h*(i+1), name);
207 rb->lcd_update_rect(0, font_h*(i+1), LCD_WIDTH, font_h);
208
209 /* exit on keypress, react to scrolling */
210 action = rb->get_action(CONTEXT_LIST, HZ/ANIM_SPEED);
211 if(stop_autoscroll(action))
212 break;
213
214 namepos += offset_dummy;
215 offset_dummy++;
216 } /* while(namepos<LCD_WIDTH+offset_dummy) */
217 if(stop_autoscroll(action))
218 break;
219
220 rb->snprintf(name, sizeof(name), "%s", credits[j+i]);
221 rb->lcd_getstringsize(name, &name_w, &name_h);
222
223 rb->snprintf(elapsednames, sizeof(elapsednames),
224 "[Credits] %d/%d", j+i+1, numnames);
225 rb->lcd_getstringsize(elapsednames, &credits_w, NULL);
226 rb->lcd_putsxy(CREDITS_TARGETPOS, 0, elapsednames);
227 if (j+i < NUM_VISIBLE_LINES) /* takes care of trail on loop */
228 rb->lcd_update_rect(0, 0, LCD_WIDTH, font_h);
229
230 for(namepos = 0-name_w; namepos <= name_targetpos;
231 namepos += (name_targetpos - namepos + 14) / 7)
232 {
233 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
234 rb->lcd_fillrect(0, font_h*(i+1), LCD_WIDTH, font_h);
235 rb->lcd_set_drawmode(DRMODE_SOLID);
236 rb->lcd_putsxy(namepos, font_h*(i+1), name);
237 rb->lcd_update_rect(0, font_h*(i+1), LCD_WIDTH, font_h);
238 rb->lcd_update_rect(CREDITS_TARGETPOS, 0, credits_w,font_h);
239
240 /* stop on keypress */
241 action = rb->get_action(CONTEXT_LIST, HZ/ANIM_SPEED);
242 if(stop_autoscroll(action))
243 break;
244 }
245 if(stop_autoscroll(action))
246 break;
247 namepos = name_targetpos;
248 } /* for(i=0; i<NUM_VISIBLE_LINES; i++) */
249 if(stop_autoscroll(action))
250 break;
251
252 action = rb->get_action(CONTEXT_LIST, HZ*PAUSE_TIME);
253 if(stop_autoscroll(action))
254 break;
255
256 j+=i; /* no user intervention, draw the next screen-full */
257 } /* while(j < numnames) */
258
259 /* handle the keypress that we intercepted during autoscroll */
260 if(ACTION_STD_CANCEL == action)
261 return;
262 if(stop_autoscroll(action))
263 manual_scroll = true;
264 } /* if(!manual_scroll) */
265
266 if(manual_scroll)
267 {
268 /* user went into manual scrolling, handle it here */
269 rb->lcd_set_drawmode(DRMODE_SOLID);
270 while(ACTION_STD_CANCEL != action)
271 {
272 rb->lcd_clear_display();
273 rb->snprintf(elapsednames, sizeof(elapsednames),
274 "[Credits] %d-%d/%d", j+1,
275 j+NUM_VISIBLE_LINES, numnames);
276 rb->lcd_getstringsize(elapsednames, &credits_w, NULL);
277 rb->lcd_putsxy(CREDITS_TARGETPOS, 0, elapsednames);
278
279 for(i=0; i<NUM_VISIBLE_LINES; i++)
280 rb->lcd_putsxyf(0, font_h*(i+1), "%s", credits[j+i]);
281
282 rb->lcd_update();
283
284 rb->yield();
285
286 /* wait for user action */
287 action = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK);
288 if(ACTION_STD_CANCEL == action)
289 return;
290 j = update_rowpos(action, j, NUM_VISIBLE_LINES, numnames);
291 }
292 return; /* exit without animation */
293 }
294
295 action = rb->get_action(CONTEXT_LIST, HZ*3);
296 if(ACTION_STD_CANCEL == action)
297 return;
298
299 offset_dummy = 1;
300
301 /* now make the text exit to the right */
302 for(credits_pos = (LCD_WIDTH/2)-(credits_w/2);
303 credits_pos <= LCD_WIDTH+offset_dummy;
304 credits_pos += offset_dummy, offset_dummy++)
305 {
306 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
307 rb->lcd_fillrect(0, 0, LCD_WIDTH, font_h);
308 rb->lcd_set_drawmode(DRMODE_SOLID);
309 rb->lcd_putsxy(credits_pos, 0, elapsednames);
310 rb->lcd_update();
311 }
312}
313
314int show_logo(void)
315{
316 unsigned char version[32];
317 int font_h, ver_w;
318 rb->snprintf(version, sizeof(version), "Ver. %s", rb->rbversion);
319 ver_w = rb->font_getstringsize(version, NULL, &font_h, FONT_SYSFIXED);
320 rb->lcd_clear_display();
321 rb->lcd_setfont(FONT_SYSFIXED);
322#if defined(SANSA_CLIP) || defined(SANSA_CLIPV2) || defined(SANSA_CLIPPLUS)
323 /* display the logo in the blue area of the screen (bottom 48 pixels) */
324 if (ver_w > LCD_WIDTH)
325 rb->lcd_puts_scroll(0, 0, version);
326 else
327 rb->lcd_putsxy((LCD_WIDTH/2) - (ver_w/2), 0, version);
328 rb->lcd_bitmap(LOGO, (LCD_WIDTH - LOGO_WIDTH) / 2, 16,
329 LOGO_WIDTH, LOGO_HEIGHT);
330#else
331 rb->lcd_bitmap(LOGO, (LCD_WIDTH - LOGO_WIDTH) / 2, 10,
332 LOGO_WIDTH, LOGO_HEIGHT);
333 if (ver_w > LCD_WIDTH)
334 rb->lcd_puts_scroll(0, (LCD_HEIGHT-font_h) / font_h, version);
335 else
336 rb->lcd_putsxy((LCD_WIDTH/2) - (ver_w/2), LCD_HEIGHT-font_h, version);
337#endif
338 rb->lcd_setfont(FONT_UI);
339 rb->lcd_update();
340#ifdef HAVE_REMOTE_LCD
341 rb->lcd_remote_clear_display();
342 rb->lcd_remote_bitmap(REMOTE_LOGO, 0, 10,
343 REMOTE_LOGO_WIDTH, REMOTE_LOGO_HEIGHT);
344 rb->lcd_remote_setfont(FONT_SYSFIXED);
345 if (ver_w > LCD_REMOTE_WIDTH)
346 rb->lcd_remote_puts_scroll(0, (LCD_REMOTE_HEIGHT-font_h) / font_h, version);
347 else
348 rb->lcd_remote_putsxy((LCD_REMOTE_WIDTH/2) - (ver_w/2),
349 LCD_REMOTE_HEIGHT-font_h, version);
350 rb->lcd_remote_setfont(FONT_UI);
351 rb->lcd_remote_update();
352#endif
353
354 return 0;
355}
356
357enum plugin_status plugin_start(const void* parameter)
358{
359 (void)parameter;
360
361
362 /* Turn off backlight timeout */
363 backlight_ignore_timeout();
364
365#if LCD_DEPTH >= 16
366 rb->lcd_set_foreground (LCD_WHITE);
367 rb->lcd_set_background (LCD_BLACK);
368#endif
369
370 show_logo();
371
372 /* Show the logo for about 5 secs allowing the user to stop */
373 if(!rb->action_userabort(5*HZ))
374 {
375 rb->lcd_scroll_stop();
376 roll_credits();
377 }
378
379#ifdef HAVE_REMOTE_LCD
380 rb->lcd_remote_scroll_stop();
381#endif
382
383 /* Turn on backlight timeout (revert to settings) */
384 backlight_use_settings();
385
386
387 return PLUGIN_OK;
388}