when changing settings from the Talk and Voice window also update the main widgets...
[Rockbox.git] / apps / plugins / matrix.c
blob827b205e7d27a1d703654e53e1b161750776ed6b
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 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 * TODO:
25 * - The font is a bit large, create smaller one
26 * - For colour/greyscale displays, the font from the xscreensaver xmatrix
27 * should be converted and used
28 * BUGS:
29 * - The animation "dies" after a few seconds, not sure why. Works in sim.
30 * Symtom Fixed Oct 2007 GRaTT (Gerritt Gonzales)
34 #include "plugin.h"
35 PLUGIN_HEADER
37 /* Images */
38 #define MAXCHARS 27 - 1
39 extern const fb_data matrix_bold[];
40 extern const fb_data matrix_normal[];
41 #define COL_W 14
42 #define COL_H 15
44 #define COLS LCD_WIDTH/COL_W
45 #define ROWS LCD_HEIGHT/COL_H
47 #define LEFTMARGIN (LCD_WIDTH-(COLS*COL_W))/2
48 #define TOPMARGIN (LCD_HEIGHT-(ROWS*COL_H))/2
50 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
51 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
52 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
53 #define MATRIX_EXIT BUTTON_MENU
54 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
55 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
56 #define MATRIX_PAUSE BUTTON_PLAY
57 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
58 (CONFIG_KEYPAD == IRIVER_H300_PAD)
59 #define MATRIX_EXIT BUTTON_OFF
60 #define MATRIX_SLEEP_MORE BUTTON_UP
61 #define MATRIX_SLEEP_LESS BUTTON_DOWN
62 #define MATRIX_PAUSE BUTTON_SELECT
63 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
64 #define MATRIX_EXIT BUTTON_POWER
65 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_UP|BUTTON_REPEAT
66 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_DOWN|BUTTON_REPEAT
67 #define MATRIX_PAUSE BUTTON_PLAY
68 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
69 #define MATRIX_EXIT BUTTON_POWER
70 #define MATRIX_SLEEP_MORE BUTTON_UP
71 #define MATRIX_SLEEP_LESS BUTTON_DOWN
72 #define MATRIX_PAUSE BUTTON_PLAY
73 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
74 #define MATRIX_EXIT BUTTON_A
75 #define MATRIX_SLEEP_MORE BUTTON_UP
76 #define MATRIX_SLEEP_LESS BUTTON_DOWN
77 #define MATRIX_PAUSE BUTTON_SELECT
78 #elif CONFIG_KEYPAD == SANSA_E200_PAD
79 #define MATRIX_EXIT BUTTON_POWER
80 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
81 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
82 #define MATRIX_PAUSE BUTTON_SELECT
83 #elif CONFIG_KEYPAD == SANSA_C200_PAD
84 #define MATRIX_EXIT BUTTON_POWER
85 #define MATRIX_SLEEP_MORE BUTTON_UP
86 #define MATRIX_SLEEP_LESS BUTTON_DOWN
87 #define MATRIX_PAUSE BUTTON_SELECT
88 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
89 #define MATRIX_EXIT BUTTON_BACK
90 #define MATRIX_SLEEP_MORE BUTTON_UP
91 #define MATRIX_SLEEP_LESS BUTTON_DOWN
92 #define MATRIX_PAUSE BUTTON_SELECT
93 #else
94 #error Unsupported keypad
95 #endif
97 #define SLEEP HZ/50
99 /* Codec api pointer */
100 static struct plugin_api* rb;
102 /* Each position is of this type */
103 typedef struct cmatrix {
104 int val;
105 int bold;
106 } cmatrix;
108 /* The matrix - who'd have guessed it was just a few hundred bytes? */
109 static cmatrix matrix[ROWS][COLS];
110 static int length[COLS];
111 static int spaces[COLS];
112 static int updates[COLS];
114 static void matrix_init(void) {
115 int i,j;
117 /* Seed rand */
118 rb->srand(*rb->current_tick);
120 /* Make the matrix */
121 for (i = 0; i <= ROWS; i++) {
122 for (j = 0; j <= COLS - 1; j++ ) {
123 matrix[i][j].val = -1;
124 matrix[i][j].bold = 0;
128 for (j = 0; j <= COLS - 1; j++) {
129 /* Set up spaces[] array of how many spaces to skip */
130 spaces[j] = rb->rand() % ROWS + 1;
132 /* And length of the stream */
133 length[j] = rb->rand() % (ROWS - 3) + 3;
135 /* Sentinel value for creation of new objects */
136 matrix[1][j].val = 129;
138 /* And set updates[] array for update speed. */
139 updates[j] = rb->rand() % 3 + 1;
143 static void matrix_blit_char(const int row, const int col, int cha)
145 if (cha == 129 || cha == 2 || cha > MAXCHARS)
146 cha = 0;
148 if (matrix[row][col].bold == 1) {
149 rb->lcd_bitmap_part(matrix_bold, cha*COL_W, 0, 392,
150 col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
152 else {
153 rb->lcd_bitmap_part(matrix_normal, cha*COL_W, 0, 392,
154 col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
158 static void matrix_loop(void)
160 int i, j = 0, y, z, firstcoldone = 0;
161 static int count = 0;
162 int randomness = 6;
164 count++;
165 if (count > 4)
166 count = 1;
168 for (j = 0; j <= COLS - 1; j++) {
169 if (count > updates[j]) {
170 /* New style scrolling */
171 if (matrix[0][j].val == -1 && matrix[1][j].val == 129
172 && spaces[j] > 0) {
173 matrix[0][j].val = -1;
174 spaces[j]--;
175 } else if (matrix[0][j].val == -1 && matrix[1][j].val == 129){
176 length[j] = rb->rand() % (ROWS - 3) + 3;
177 matrix[0][j].val = rb->rand() % (MAXCHARS-1) + 1;
178 if (rb->rand() % 2 == 1)
179 matrix[0][j].bold = 2;
180 spaces[j] = rb->rand() % ROWS + 1;
182 i = 0;
183 y = 0;
184 firstcoldone = 0;
185 while (i <= ROWS) {
186 /* Skip over spaces */
187 /* this is whear the characters were disappearing */
189 while (i <= ROWS && (matrix[i][j].val == 129 ||
190 matrix[i][j].val == -1))
191 i++;
193 /* A little more random now for spaces */
194 if (rb->rand() % randomness == 1){
195 while (i <= ROWS && (matrix[i][j].val == 129 ||
196 matrix[i][j].val == -1)){
197 i++;
198 randomness--;
199 if(randomness <=1)
200 randomness = 6;}
201 }else{
202 randomness++;
203 if(randomness >6)
204 randomness = 6;
208 if (i > ROWS)
209 break;
211 /* Go to the head of this collumn */
212 z = i;
213 y = 0;
214 while (i <= ROWS && (matrix[i][j].val != 129 &&
215 matrix[i][j].val != -1)) {
216 i++;
217 y++;
220 if (i > ROWS) {
221 matrix[z][j].val = 129;
222 matrix[ROWS][j].bold = 1;
223 matrix_blit_char(z - 1, j, matrix[z][j].val);
224 continue;
227 matrix[i][j].val = rb->rand() % (MAXCHARS-1) + 1;
229 if (matrix[i - 1][j].bold == 2) {
230 matrix[i - 1][j].bold = 1;
231 matrix[i][j].bold = 2;
234 /* If we're at the top of the collumn and it's reached its
235 * full length (about to start moving down), we do this
236 * to get it moving. This is also how we keep segments
237 * not already growing from growing accidentally =>
239 if (y > length[j] || firstcoldone) {
240 matrix[z][j].val = 129;
241 matrix[0][j].val = -1;
243 firstcoldone = 1;
244 i++;
246 for (i = 1; i <= ROWS; i++) {
247 if (matrix[i][j].val == 0 || matrix[i][j].bold == 2) {
248 if (matrix[i][j].val == 0)
249 matrix_blit_char(i - 1, j, 20);
250 else
251 matrix_blit_char(i - 1, j, matrix[i][j].val);
252 } else {
253 if (matrix[i][j].val == 1)
254 matrix_blit_char(i - 1, j, 2);
255 else if (matrix[i][j].val == -1)
256 matrix_blit_char(i - 1, j, 129);
257 else
258 matrix_blit_char(i - 1, j, matrix[i][j].val);
265 enum plugin_status plugin_start(struct plugin_api* api, void* parameter) {
266 int button;
267 int sleep = SLEEP;
268 bool frozen = false;
270 (void)parameter;
271 rb = api;
273 rb->lcd_set_background(LCD_BLACK);
274 rb->lcd_set_backdrop(NULL);
275 rb->lcd_clear_display();
276 matrix_init();
278 while (1) {
279 if (!frozen) {
280 matrix_loop();
281 rb->lcd_update();
282 rb->sleep(sleep);
284 button = rb->button_get(false);
285 switch(button) {
286 case MATRIX_PAUSE:
287 frozen = !frozen;
288 break;
289 case MATRIX_EXIT:
290 return PLUGIN_OK;
291 break;
292 case MATRIX_SLEEP_MORE:
293 /* Sleep longer */
294 sleep += SLEEP;
295 break;
296 case MATRIX_SLEEP_LESS:
297 /* Sleep less */
298 sleep -= SLEEP;
299 if (sleep < 0) sleep = 0;
300 break;
301 default:
302 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
303 return PLUGIN_USB_CONNECTED;
305 break;
308 return PLUGIN_OK;