Explicitely say 'minutes' when speaking the battery time, fixes FS#11932.
[kugel-rb.git] / apps / plugins / matrix.c
blob02a64dba81a86d608812fdab2c538990409c57b6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 1999 Chris Allegretta
11 * Copyright (C) 2005 Alastair S - ported to podzilla
12 * Copyright (C) 2005 Jonas Häggqvist - ported to rockbox
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
26 * TODO:
27 * - The font is a bit large, create smaller one
28 * - For colour/greyscale displays, the font from the xscreensaver xmatrix
29 * should be converted and used
30 * BUGS:
31 * - The animation "dies" after a few seconds, not sure why. Works in sim.
32 * Symtom Fixed Oct 2007 GRaTT (Gerritt Gonzales)
36 #include "plugin.h"
39 /* Images */
40 #include "pluginbitmaps/matrix_bold.h"
41 #include "pluginbitmaps/matrix_normal.h"
42 #define MAXCHARS 27 - 1
43 #define COL_W 14
44 #define COL_H 15
46 #define COLS LCD_WIDTH/COL_W
47 #define ROWS LCD_HEIGHT/COL_H
49 #define LEFTMARGIN (LCD_WIDTH-(COLS*COL_W))/2
50 #define TOPMARGIN (LCD_HEIGHT-(ROWS*COL_H))/2
52 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
53 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
54 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
55 #define MATRIX_EXIT BUTTON_MENU
56 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
57 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
58 #define MATRIX_PAUSE BUTTON_PLAY
60 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
61 (CONFIG_KEYPAD == IRIVER_H300_PAD)
62 #define MATRIX_EXIT BUTTON_OFF
63 #define MATRIX_SLEEP_MORE BUTTON_UP
64 #define MATRIX_SLEEP_LESS BUTTON_DOWN
65 #define MATRIX_PAUSE BUTTON_SELECT
67 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
68 #define MATRIX_EXIT BUTTON_POWER
69 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_UP|BUTTON_REPEAT
70 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_DOWN|BUTTON_REPEAT
71 #define MATRIX_PAUSE BUTTON_PLAY
73 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
74 #define MATRIX_EXIT BUTTON_POWER
75 #define MATRIX_SLEEP_MORE BUTTON_UP
76 #define MATRIX_SLEEP_LESS BUTTON_DOWN
77 #define MATRIX_PAUSE BUTTON_PLAY
79 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
80 #define MATRIX_EXIT BUTTON_POWER
81 #define MATRIX_SLEEP_MORE BUTTON_UP
82 #define MATRIX_SLEEP_LESS BUTTON_DOWN
83 #define MATRIX_PAUSE BUTTON_SELECT
85 #elif CONFIG_KEYPAD == SANSA_E200_PAD
86 #define MATRIX_EXIT BUTTON_POWER
87 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
88 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
89 #define MATRIX_PAUSE BUTTON_SELECT
91 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
92 #define MATRIX_EXIT (BUTTON_HOME|BUTTON_REPEAT)
93 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
94 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
95 #define MATRIX_PAUSE BUTTON_SELECT
97 #elif CONFIG_KEYPAD == SANSA_C200_PAD
98 #define MATRIX_EXIT BUTTON_POWER
99 #define MATRIX_SLEEP_MORE BUTTON_UP
100 #define MATRIX_SLEEP_LESS BUTTON_DOWN
101 #define MATRIX_PAUSE BUTTON_SELECT
103 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
104 #define MATRIX_EXIT BUTTON_BACK
105 #define MATRIX_SLEEP_MORE BUTTON_UP
106 #define MATRIX_SLEEP_LESS BUTTON_DOWN
107 #define MATRIX_PAUSE BUTTON_SELECT
109 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
110 #define MATRIX_EXIT BUTTON_RC_REC
111 #define MATRIX_SLEEP_MORE BUTTON_RC_VOL_UP
112 #define MATRIX_SLEEP_LESS BUTTON_RC_VOL_DOWN
113 #define MATRIX_PAUSE BUTTON_RC_PLAY
115 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
116 #define MATRIX_EXIT BUTTON_POWER
118 #elif CONFIG_KEYPAD == IAUDIO67_PAD
119 #define MATRIX_EXIT BUTTON_POWER
120 #define MATRIX_SLEEP_MORE BUTTON_VOLUP
121 #define MATRIX_SLEEP_LESS BUTTON_VOLDOWN
122 #define MATRIX_PAUSE BUTTON_PLAY
124 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
125 #define MATRIX_EXIT BUTTON_BACK
126 #define MATRIX_SLEEP_MORE BUTTON_UP
127 #define MATRIX_SLEEP_LESS BUTTON_DOWN
128 #define MATRIX_PAUSE BUTTON_PLAY
130 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
131 #define MATRIX_EXIT BUTTON_POWER
132 #define MATRIX_SLEEP_MORE BUTTON_UP
133 #define MATRIX_SLEEP_LESS BUTTON_DOWN
134 #define MATRIX_PAUSE BUTTON_SELECT
136 #elif (CONFIG_KEYPAD == PHILIPS_HDD6330_PAD) || \
137 (CONFIG_KEYPAD == PHILIPS_SA9200_PAD)
138 #define MATRIX_EXIT BUTTON_POWER
139 #define MATRIX_SLEEP_MORE BUTTON_UP
140 #define MATRIX_SLEEP_LESS BUTTON_DOWN
141 #define MATRIX_PAUSE BUTTON_PLAY
143 #elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
144 CONFIG_KEYPAD == ONDAVX777_PAD || \
145 CONFIG_KEYPAD == MROBE500_PAD
146 #define MATRIX_EXIT BUTTON_POWER
148 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
149 #define MATRIX_EXIT BUTTON_REC
150 #define MATRIX_SLEEP_MORE BUTTON_UP
151 #define MATRIX_SLEEP_LESS BUTTON_DOWN
152 #define MATRIX_PAUSE BUTTON_PLAY
154 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
155 #define MATRIX_EXIT BUTTON_REC
156 #define MATRIX_SLEEP_MORE BUTTON_PREV
157 #define MATRIX_SLEEP_LESS BUTTON_NEXT
158 #define MATRIX_PAUSE BUTTON_PLAY
160 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
161 #define MATRIX_EXIT (BUTTON_REC|BUTTON_PLAY)
162 #define MATRIX_SLEEP_MORE BUTTON_VOL_UP
163 #define MATRIX_SLEEP_LESS BUTTON_VOL_DOWN
164 #define MATRIX_PAUSE BUTTON_PLAY
166 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
167 #define MATRIX_EXIT (BUTTON_REC|BUTTON_REPEAT)
168 #define MATRIX_SLEEP_MORE BUTTON_UP
169 #define MATRIX_SLEEP_LESS BUTTON_DOWN
170 #define MATRIX_PAUSE BUTTON_PLAY
172 #else
173 #error Unsupported keypad
174 #endif
176 #ifdef HAVE_TOUCHSCREEN
177 #ifndef MATRIX_EXIT
178 #define MATRIX_EXIT BUTTON_TOPLEFT
179 #endif
180 #ifndef MATRIX_SLEEP_MORE
181 #define MATRIX_SLEEP_MORE BUTTON_MIDRIGHT
182 #endif
183 #ifndef MATRIX_SLEEP_LESS
184 #define MATRIX_SLEEP_LESS BUTTON_MIDLEFT
185 #endif
186 #ifndef MATRIX_PAUSE
187 #define MATRIX_PAUSE BUTTON_CENTER
188 #endif
189 #endif
191 #define SLEEP HZ/50
193 /* Each position is of this type */
194 typedef struct cmatrix {
195 int val;
196 int bold;
197 } cmatrix;
199 /* The matrix - who'd have guessed it was just a few hundred bytes? */
200 static cmatrix matrix[ROWS][COLS];
201 static int length[COLS];
202 static int spaces[COLS];
203 static int updates[COLS];
205 static void matrix_init(void) {
206 int i,j;
208 /* Seed rand */
209 rb->srand(*rb->current_tick);
211 /* Make the matrix */
212 for (i = 0; i <= ROWS; i++) {
213 for (j = 0; j <= COLS - 1; j++ ) {
214 matrix[i][j].val = -1;
215 matrix[i][j].bold = 0;
219 for (j = 0; j <= COLS - 1; j++) {
220 /* Set up spaces[] array of how many spaces to skip */
221 spaces[j] = rb->rand() % ROWS + 1;
223 /* And length of the stream */
224 length[j] = rb->rand() % (ROWS - 3) + 3;
226 /* Sentinel value for creation of new objects */
227 matrix[1][j].val = 129;
229 /* And set updates[] array for update speed. */
230 updates[j] = rb->rand() % 3 + 1;
234 static void matrix_blit_char(const int row, const int col, int cha)
236 if (cha == 129 || cha == 2 || cha > MAXCHARS)
237 cha = 0;
239 if (matrix[row][col].bold == 1) {
240 rb->lcd_bitmap_part(matrix_bold, cha*COL_W, 0,
241 STRIDE( SCREEN_MAIN,
242 BMPWIDTH_matrix_bold, BMPHEIGHT_matrix_bold),
243 col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
245 else {
246 rb->lcd_bitmap_part(matrix_normal, cha*COL_W, 0,
247 STRIDE( SCREEN_MAIN,
248 BMPWIDTH_matrix_normal, BMPHEIGHT_matrix_normal),
249 col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
253 static void matrix_loop(void)
255 int i, j = 0, y, z, firstcoldone = 0;
256 static int count = 0;
257 int randomness = 6;
259 count++;
260 if (count > 4)
261 count = 1;
263 for (j = 0; j <= COLS - 1; j++) {
264 if (count > updates[j]) {
265 /* New style scrolling */
266 if (matrix[0][j].val == -1 && matrix[1][j].val == 129
267 && spaces[j] > 0) {
268 matrix[0][j].val = -1;
269 spaces[j]--;
270 } else if (matrix[0][j].val == -1 && matrix[1][j].val == 129){
271 length[j] = rb->rand() % (ROWS - 3) + 3;
272 matrix[0][j].val = rb->rand() % (MAXCHARS-1) + 1;
273 if (rb->rand() % 2 == 1)
274 matrix[0][j].bold = 2;
275 spaces[j] = rb->rand() % ROWS + 1;
277 i = 0;
278 y = 0;
279 firstcoldone = 0;
280 while (i <= ROWS) {
281 /* Skip over spaces */
282 /* this is whear the characters were disappearing */
284 while (i <= ROWS && (matrix[i][j].val == 129 ||
285 matrix[i][j].val == -1))
286 i++;
288 /* A little more random now for spaces */
289 if (rb->rand() % randomness == 1){
290 while (i <= ROWS && (matrix[i][j].val == 129 ||
291 matrix[i][j].val == -1)){
292 i++;
293 randomness--;
294 if(randomness <=1)
295 randomness = 6;}
296 }else{
297 randomness++;
298 if(randomness >6)
299 randomness = 6;
303 if (i > ROWS)
304 break;
306 /* Go to the head of this collumn */
307 z = i;
308 y = 0;
309 while (i <= ROWS && (matrix[i][j].val != 129 &&
310 matrix[i][j].val != -1)) {
311 i++;
312 y++;
315 if (i > ROWS) {
316 matrix[z][j].val = 129;
317 matrix[ROWS - 1][j].bold = 1;
318 matrix_blit_char(z - 1, j, matrix[z][j].val);
319 continue;
322 matrix[i][j].val = rb->rand() % (MAXCHARS-1) + 1;
324 if (matrix[i - 1][j].bold == 2) {
325 matrix[i - 1][j].bold = 1;
326 matrix[i][j].bold = 2;
329 /* If we're at the top of the collumn and it's reached its
330 * full length (about to start moving down), we do this
331 * to get it moving. This is also how we keep segments
332 * not already growing from growing accidentally =>
334 if (y > length[j] || firstcoldone) {
335 matrix[z][j].val = 129;
336 matrix[0][j].val = -1;
338 firstcoldone = 1;
339 i++;
341 for (i = 1; i <= ROWS; i++) {
342 if (matrix[i][j].val == 0 || matrix[i][j].bold == 2) {
343 if (matrix[i][j].val == 0)
344 matrix_blit_char(i - 1, j, 20);
345 else
346 matrix_blit_char(i - 1, j, matrix[i][j].val);
347 } else {
348 if (matrix[i][j].val == 1)
349 matrix_blit_char(i - 1, j, 2);
350 else if (matrix[i][j].val == -1)
351 matrix_blit_char(i - 1, j, 129);
352 else
353 matrix_blit_char(i - 1, j, matrix[i][j].val);
360 enum plugin_status plugin_start(const void* parameter) {
361 int button;
362 int sleep = SLEEP;
363 bool frozen = false;
365 (void)parameter;
367 rb->lcd_set_background(LCD_BLACK);
368 rb->lcd_set_backdrop(NULL);
369 rb->lcd_clear_display();
370 matrix_init();
372 while (1) {
373 if (!frozen) {
374 matrix_loop();
375 rb->lcd_update();
376 rb->sleep(sleep);
378 button = rb->button_get(frozen);
379 switch(button) {
380 case MATRIX_PAUSE:
381 frozen = !frozen;
382 break;
383 case MATRIX_EXIT:
384 return PLUGIN_OK;
385 break;
386 case MATRIX_SLEEP_MORE:
387 /* Sleep longer */
388 sleep += SLEEP;
389 break;
390 case MATRIX_SLEEP_LESS:
391 /* Sleep less */
392 sleep -= SLEEP;
393 if (sleep < 0) sleep = 0;
394 break;
395 default:
396 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
397 return PLUGIN_USB_CONNECTED;
399 break;
402 return PLUGIN_OK;