blob: 1940c379bcbe6d9eda5981cb5c512ccfc8d447cf [file] [log] [blame]
Daniel Stenberg1c0c8612002-05-17 12:22:24 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Robert E. Hak
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
Björn Stenberg2ac05722002-05-26 17:03:17 +000019#include <stdbool.h>
Justin Heinerb5025a82002-08-31 04:58:35 +000020
Daniel Stenberg1c0c8612002-05-17 12:22:24 +000021#include "lcd.h"
Justin Heinerb5025a82002-08-31 04:58:35 +000022#include "backlight.h"
Daniel Stenberg1c0c8612002-05-17 12:22:24 +000023#include "menu.h"
Björn Stenbergb21a3bd2002-05-21 14:25:45 +000024#include "button.h"
25#include "kernel.h"
26#include "debug.h"
Justin Heiner26302452002-08-23 02:17:00 +000027#include "usb.h"
Björn Stenbergcd225732002-08-11 09:17:47 +000028#include "panic.h"
Markus Braun5e4c1d22002-08-20 19:37:00 +000029#include "settings.h"
30#include "status.h"
Markus Braun000c2db2002-08-30 13:49:32 +000031
Daniel Stenbergbf603f92002-06-14 08:47:44 +000032#ifdef HAVE_LCD_BITMAP
33#include "icons.h"
Markus Braun000c2db2002-08-30 13:49:32 +000034#include "widgets.h"
Daniel Stenbergbf603f92002-06-14 08:47:44 +000035#endif
Markus Braun000c2db2002-08-30 13:49:32 +000036
Björn Stenbergcd225732002-08-11 09:17:47 +000037#ifdef LOADABLE_FONTS
38#include "ajf.h"
39#endif
Markus Braun5e4c1d22002-08-20 19:37:00 +000040
Björn Stenberg2ac05722002-05-26 17:03:17 +000041struct menu {
Björn Stenbergf76cee72002-05-28 15:35:33 +000042 int top;
Björn Stenberg2ac05722002-05-26 17:03:17 +000043 int cursor;
44 struct menu_items* items;
45 int itemcount;
46};
47
48#define MAX_MENUS 4
49
Björn Stenbergf76cee72002-05-28 15:35:33 +000050#ifdef HAVE_LCD_BITMAP
Markus Braun000c2db2002-08-30 13:49:32 +000051
52#define MARGIN_X (global_settings.scrollbar ? SCROLLBAR_WIDTH : 0) + CURSOR_WIDTH /* X pixel margin */
53#define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0) /* Y pixel margin */
54
55#define LINE_X 0 /* X position the entry-list starts at */
Markus Braun5e4c1d22002-08-20 19:37:00 +000056#define LINE_Y (global_settings.statusbar ? 1 : 0) /* Y position the entry-list starts at */
57#define LINE_HEIGTH 8 /* pixels for each text line */
Markus Braun000c2db2002-08-30 13:49:32 +000058
Markus Braun5e4c1d22002-08-20 19:37:00 +000059#define MENU_LINES (LCD_HEIGHT / LINE_HEIGTH - LINE_Y)
Markus Braun000c2db2002-08-30 13:49:32 +000060
61#define CURSOR_X (global_settings.scrollbar ? 1 : 0)
62#define CURSOR_Y 0 /* the cursor is not positioned in regard to
63 the margins, so this is the amount of lines
64 we add to the cursor Y position to position
65 it on a line */
66#define CURSOR_WIDTH 4
67
68#define SCROLLBAR_X 0
69#define SCROLLBAR_Y lcd_getymargin()
70#define SCROLLBAR_WIDTH 6
71
72#else /* HAVE_LCD_BITMAP */
73
Justin Heinerb5025a82002-08-31 04:58:35 +000074#define LINE_X 1 /* X position the entry-list starts at */
Markus Braun000c2db2002-08-30 13:49:32 +000075
Björn Stenbergf76cee72002-05-28 15:35:33 +000076#define MENU_LINES 2
Markus Braun000c2db2002-08-30 13:49:32 +000077
78#define CURSOR_X 0
79#define CURSOR_Y 0 /* not really used for players */
80
81#endif /* HAVE_LCD_BITMAP */
Björn Stenbergf76cee72002-05-28 15:35:33 +000082
Björn Stenberg9314a682002-05-31 09:04:51 +000083#ifdef HAVE_NEW_CHARCELL_LCD
84#define CURSOR_CHAR "\x7e"
85#else
86#define CURSOR_CHAR "\x89"
87#endif
Björn Stenberg9314a682002-05-31 09:04:51 +000088
Björn Stenberg2ac05722002-05-26 17:03:17 +000089static struct menu menus[MAX_MENUS];
90static bool inuse[MAX_MENUS] = { false };
Daniel Stenberg1c0c8612002-05-17 12:22:24 +000091
Daniel Stenbergbf603f92002-06-14 08:47:44 +000092/* count in letter posistions, NOT pixels */
93void put_cursorxy(int x, int y, bool on)
94{
Björn Stenberg71f71ef2002-08-11 09:20:53 +000095#ifdef HAVE_LCD_BITMAP
Björn Stenbergcd225732002-08-11 09:17:47 +000096#ifdef LOADABLE_FONTS
97 int fh;
98 unsigned char* font = lcd_getcurrentldfont();
99 fh = ajf_get_fontheight(font);
100#else
101 int fh = 8;
102#endif
Björn Stenberg71f71ef2002-08-11 09:20:53 +0000103#endif
Björn Stenbergcd225732002-08-11 09:17:47 +0000104
Daniel Stenbergbf603f92002-06-14 08:47:44 +0000105 /* place the cursor */
106 if(on) {
107#ifdef HAVE_LCD_BITMAP
108 lcd_bitmap ( bitmap_icons_6x8[Cursor],
Markus Braun5e4c1d22002-08-20 19:37:00 +0000109 x*6, y*fh + lcd_getymargin(), 4, 8, true);
Daniel Stenberge35f8eb2002-06-15 11:39:36 +0000110#elif defined(SIMULATOR)
Daniel Stenbergc4be1ee2002-06-19 13:00:14 +0000111 /* player simulator */
Daniel Stenberge35f8eb2002-06-15 11:39:36 +0000112 unsigned char cursor[] = { 0x7f, 0x3e, 0x1c, 0x08 };
Daniel Stenberg7cdf5c82002-08-09 09:13:00 +0000113 lcd_bitmap ( cursor, x*6, 12+y*16, 4, 8, true);
Daniel Stenbergbf603f92002-06-14 08:47:44 +0000114#else
115 lcd_puts(x, y, CURSOR_CHAR);
116#endif
117 }
118 else {
Daniel Stenbergc4be1ee2002-06-19 13:00:14 +0000119#if defined(HAVE_LCD_BITMAP)
Daniel Stenbergbf603f92002-06-14 08:47:44 +0000120 /* I use xy here since it needs to disregard the margins */
Markus Braun5e4c1d22002-08-20 19:37:00 +0000121 lcd_clearrect (x*6, y*fh + lcd_getymargin(), 4, 8);
Daniel Stenbergc4be1ee2002-06-19 13:00:14 +0000122#elif defined(SIMULATOR)
123 /* player simulator in action */
Daniel Stenberg7cdf5c82002-08-09 09:13:00 +0000124 lcd_clearrect (x*6, 12+y*16, 4, 8);
Daniel Stenbergbf603f92002-06-14 08:47:44 +0000125#else
126 lcd_puts(x, y, " ");
127#endif
128 }
129}
130
Björn Stenbergf76cee72002-05-28 15:35:33 +0000131static void menu_draw(int m)
132{
133 int i = 0;
Björn Stenbergcd225732002-08-11 09:17:47 +0000134#ifdef LOADABLE_FONTS
135 int menu_lines;
136 int fh;
137 unsigned char* font = lcd_getcurrentldfont();
138 fh = ajf_get_fontheight(font);
Markus Braun5e4c1d22002-08-20 19:37:00 +0000139 if (global_settings.statusbar)
140 menu_lines = (LCD_HEIGHT - STATUSBAR_HEIGHT) / fh;
141 else
142 menu_lines = LCD_HEIGHT/fh;
Björn Stenbergcd225732002-08-11 09:17:47 +0000143#else
144 int menu_lines = MENU_LINES;
145#endif
Björn Stenbergf76cee72002-05-28 15:35:33 +0000146
Daniel Stenberga8e89fd2002-08-22 21:45:22 +0000147 lcd_scroll_pause(); /* halt scroll first... */
148 lcd_clear_display(); /* ...then clean the screen */
Björn Stenbergf76cee72002-05-28 15:35:33 +0000149#ifdef HAVE_LCD_BITMAP
Markus Braun000c2db2002-08-30 13:49:32 +0000150 lcd_setmargins(MARGIN_X,MARGIN_Y); /* leave room for cursor and icon */
Björn Stenbergf76cee72002-05-28 15:35:33 +0000151 lcd_setfont(0);
152#endif
Markus Braun5e4c1d22002-08-20 19:37:00 +0000153 /* correct cursor pos if out of screen */
154 if (menus[m].cursor - menus[m].top >= menu_lines)
155 menus[m].top++;
156
Björn Stenbergf76cee72002-05-28 15:35:33 +0000157 for (i = menus[m].top;
Björn Stenbergcd225732002-08-11 09:17:47 +0000158 (i < menus[m].itemcount) && (i<menus[m].top+menu_lines);
Björn Stenbergf76cee72002-05-28 15:35:33 +0000159 i++) {
Linus Nielsen Feltzing8fa02172002-08-02 07:59:25 +0000160 if((menus[m].cursor - menus[m].top)==(i-menus[m].top))
Markus Braun000c2db2002-08-30 13:49:32 +0000161 lcd_puts_scroll(LINE_X, i-menus[m].top, menus[m].items[i].desc);
Linus Nielsen Feltzing8fa02172002-08-02 07:59:25 +0000162 else
Markus Braun000c2db2002-08-30 13:49:32 +0000163 lcd_puts(LINE_X, i-menus[m].top, menus[m].items[i].desc);
Björn Stenbergf76cee72002-05-28 15:35:33 +0000164 }
Robert Hakc501ac72002-05-30 08:06:42 +0000165
Daniel Stenbergbf603f92002-06-14 08:47:44 +0000166 /* place the cursor */
Markus Braun000c2db2002-08-30 13:49:32 +0000167 put_cursorxy(CURSOR_X, menus[m].cursor - menus[m].top, true);
Markus Braun5e4c1d22002-08-20 19:37:00 +0000168#ifdef HAVE_LCD_BITMAP
Markus Braun000c2db2002-08-30 13:49:32 +0000169 if (global_settings.scrollbar)
170 scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1,
171 LCD_HEIGHT - SCROLLBAR_Y, menus[m].itemcount, menus[m].top,
172 menus[m].top + menu_lines, VERTICAL);
Markus Braun5e4c1d22002-08-20 19:37:00 +0000173#endif
Markus Braun000c2db2002-08-30 13:49:32 +0000174 status_draw();
Björn Stenbergf76cee72002-05-28 15:35:33 +0000175 lcd_update();
176}
177
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000178/*
179 * Move the cursor to a particular id,
180 * target: where you want it to be
181 */
Björn Stenberg2ac05722002-05-26 17:03:17 +0000182static void put_cursor(int m, int target)
Daniel Stenberg1c0c8612002-05-17 12:22:24 +0000183{
Robert Hakc501ac72002-05-30 08:06:42 +0000184 bool do_update = true;
Björn Stenbergcd225732002-08-11 09:17:47 +0000185#ifdef LOADABLE_FONTS
186 int menu_lines;
187 int fh;
188 unsigned char* font = lcd_getcurrentldfont();
189 fh = ajf_get_fontheight(font);
Markus Braun5e4c1d22002-08-20 19:37:00 +0000190 if (global_settings.statusbar)
191 menu_lines = (LCD_HEIGHT-STATUSBAR_HEIGHT)/fh;
192 else
193 menu_lines = LCD_HEIGHT/fh;
Björn Stenbergcd225732002-08-11 09:17:47 +0000194#else
195 int menu_lines = MENU_LINES;
196#endif
Markus Braun000c2db2002-08-30 13:49:32 +0000197 put_cursorxy(CURSOR_X, menus[m].cursor - menus[m].top, false);
Robert Hakc501ac72002-05-30 08:06:42 +0000198 menus[m].cursor = target;
Linus Nielsen Feltzing8fa02172002-08-02 07:59:25 +0000199 menu_draw(m);
Björn Stenbergf76cee72002-05-28 15:35:33 +0000200
201 if ( target < menus[m].top ) {
202 menus[m].top--;
203 menu_draw(m);
Robert Hakc501ac72002-05-30 08:06:42 +0000204 do_update = false;
Björn Stenbergf76cee72002-05-28 15:35:33 +0000205 }
Björn Stenbergcd225732002-08-11 09:17:47 +0000206 else if ( target-menus[m].top > menu_lines-1 ) {
Björn Stenbergf76cee72002-05-28 15:35:33 +0000207 menus[m].top++;
208 menu_draw(m);
Robert Hakc501ac72002-05-30 08:06:42 +0000209 do_update = false;
Björn Stenbergf76cee72002-05-28 15:35:33 +0000210 }
Robert Hakc501ac72002-05-30 08:06:42 +0000211
212 if (do_update) {
Markus Braun000c2db2002-08-30 13:49:32 +0000213 put_cursorxy(CURSOR_X, menus[m].cursor - menus[m].top, true);
Robert Hakc501ac72002-05-30 08:06:42 +0000214 lcd_update();
215 }
216
Daniel Stenberg1c0c8612002-05-17 12:22:24 +0000217}
218
Björn Stenberg2ac05722002-05-26 17:03:17 +0000219int menu_init(struct menu_items* mitems, int count)
Daniel Stenberg1c0c8612002-05-17 12:22:24 +0000220{
Björn Stenberg2ac05722002-05-26 17:03:17 +0000221 int i;
222
223 for ( i=0; i<MAX_MENUS; i++ ) {
224 if ( !inuse[i] ) {
225 inuse[i] = true;
226 break;
227 }
228 }
229 if ( i == MAX_MENUS ) {
230 DEBUGF("Out of menus!\n");
231 return -1;
232 }
233 menus[i].items = mitems;
234 menus[i].itemcount = count;
Björn Stenbergf76cee72002-05-28 15:35:33 +0000235 menus[i].top = 0;
Björn Stenberg2ac05722002-05-26 17:03:17 +0000236 menus[i].cursor = 0;
237
238 return i;
Daniel Stenberg1c0c8612002-05-17 12:22:24 +0000239}
240
Björn Stenberg2ac05722002-05-26 17:03:17 +0000241void menu_exit(int m)
Daniel Stenberg1c0c8612002-05-17 12:22:24 +0000242{
Björn Stenberg2ac05722002-05-26 17:03:17 +0000243 inuse[m] = false;
Daniel Stenberg1c0c8612002-05-17 12:22:24 +0000244}
245
Daniel Stenbergb2850762002-08-23 12:32:52 +0000246Menu menu_run(int m)
Robert Hak7ec9aa32002-05-18 11:41:37 +0000247{
Justin Heiner0a3589d2002-08-23 02:45:39 +0000248#ifndef SIMULATOR
Justin Heineredf6b802002-08-23 02:26:22 +0000249#ifdef HAVE_LCD_BITMAP
Justin Heiner26302452002-08-23 02:17:00 +0000250 bool laststate;
Justin Heineredf6b802002-08-23 02:26:22 +0000251#endif
Justin Heiner0a3589d2002-08-23 02:45:39 +0000252#endif
Daniel Stenbergb2850762002-08-23 12:32:52 +0000253 Menu result = MENU_OK;
Justin Heiner26302452002-08-23 02:17:00 +0000254
Björn Stenberg2ac05722002-05-26 17:03:17 +0000255 menu_draw(m);
Justin Heiner26302452002-08-23 02:17:00 +0000256
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000257 while(1) {
Markus Braun5e4c1d22002-08-20 19:37:00 +0000258 switch( button_get_w_tmo(HZ/2) ) {
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000259#ifdef HAVE_RECORDER_KEYPAD
260 case BUTTON_UP:
Björn Stenbergcbc71792002-08-10 09:04:55 +0000261 case BUTTON_UP | BUTTON_REPEAT:
Robert Hak7ec9aa32002-05-18 11:41:37 +0000262#else
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000263 case BUTTON_LEFT:
Linus Nielsen Feltzing8fa02172002-08-02 07:59:25 +0000264 case BUTTON_LEFT | BUTTON_REPEAT:
Robert Hak7ec9aa32002-05-18 11:41:37 +0000265#endif
Björn Stenberg4caebab2002-05-29 14:25:06 +0000266 if (menus[m].cursor) {
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000267 /* move up */
Björn Stenberg2ac05722002-05-26 17:03:17 +0000268 put_cursor(m, menus[m].cursor-1);
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000269 }
270 break;
Robert Hakdfba2102002-05-21 08:47:34 +0000271
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000272#ifdef HAVE_RECORDER_KEYPAD
273 case BUTTON_DOWN:
Björn Stenbergcbc71792002-08-10 09:04:55 +0000274 case BUTTON_DOWN | BUTTON_REPEAT:
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000275#else
276 case BUTTON_RIGHT:
Linus Nielsen Feltzing8fa02172002-08-02 07:59:25 +0000277 case BUTTON_RIGHT | BUTTON_REPEAT:
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000278#endif
Björn Stenberg4caebab2002-05-29 14:25:06 +0000279 if (menus[m].cursor < menus[m].itemcount-1) {
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000280 /* move down */
Björn Stenberg2ac05722002-05-26 17:03:17 +0000281 put_cursor(m, menus[m].cursor+1);
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000282 }
283 break;
284
285#ifdef HAVE_RECORDER_KEYPAD
286 case BUTTON_RIGHT:
287#endif
288 case BUTTON_PLAY:
289 /* Erase current display state */
Daniel Stenberga8e89fd2002-08-22 21:45:22 +0000290 lcd_scroll_pause(); /* pause is better than stop when
291 are gonna clear the screen anyway */
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000292 lcd_clear_display();
293
Daniel Stenberg49984fa2002-08-23 12:57:00 +0000294 /* if a child returns that the contents is changed, we
295 must remember this, even if we perhaps invoke other
296 children too before returning back */
297 if(MENU_DISK_CHANGED ==
298 menus[m].items[menus[m].cursor].function())
299 result = MENU_DISK_CHANGED;
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000300
301 /* Return to previous display state */
Björn Stenberg2ac05722002-05-26 17:03:17 +0000302 menu_draw(m);
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000303 break;
304
305#ifdef HAVE_RECORDER_KEYPAD
306 case BUTTON_LEFT:
Linus Nielsen Feltzinga552f4c2002-07-27 19:53:26 +0000307 case BUTTON_F1:
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000308#else
309 case BUTTON_STOP:
Björn Stenberg60fad542002-05-29 12:28:08 +0000310 case BUTTON_MENU:
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000311#endif
Linus Nielsen Feltzing8fa02172002-08-02 07:59:25 +0000312 lcd_stop_scroll();
Daniel Stenbergb2850762002-08-23 12:32:52 +0000313 return result;
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000314
Markus Braun5e4c1d22002-08-20 19:37:00 +0000315#ifdef HAVE_RECORDER_KEYPAD
Markus Braun000c2db2002-08-30 13:49:32 +0000316 case BUTTON_F3: {
Markus Braun5e4c1d22002-08-20 19:37:00 +0000317#ifdef HAVE_LCD_BITMAP
Markus Braun000c2db2002-08-30 13:49:32 +0000318 unsigned char state;
319 state = global_settings.statusbar << 1 | global_settings.scrollbar;
320 state = (state + 1) % 4;
321 global_settings.statusbar = state >> 1;
322 global_settings.scrollbar = state & 0x1;
323 settings_save();
324
325 menu_draw(m);
Markus Braun5e4c1d22002-08-20 19:37:00 +0000326#endif
Markus Braun000c2db2002-08-30 13:49:32 +0000327 }
Markus Braun5e4c1d22002-08-20 19:37:00 +0000328 break;
329#endif
330
Justin Heiner26302452002-08-23 02:17:00 +0000331#ifndef SIMULATOR
332 case SYS_USB_CONNECTED:
333#ifdef HAVE_LCD_BITMAP
334 laststate = statusbar(false);
335#endif
Justin Heinerb5025a82002-08-31 04:58:35 +0000336 backlight_time(4);
Justin Heiner26302452002-08-23 02:17:00 +0000337 usb_acknowledge(SYS_USB_CONNECTED_ACK);
338 usb_wait_for_disconnect(&button_queue);
Justin Heinerb5025a82002-08-31 04:58:35 +0000339 backlight_time(global_settings.backlight);
Justin Heiner26302452002-08-23 02:17:00 +0000340#ifdef HAVE_LCD_BITMAP
341 statusbar(laststate);
342#else
343 lcd_icon(ICON_PARAM, true);
344#endif
Daniel Stenberg49984fa2002-08-23 12:57:00 +0000345 menu_draw(m);
Daniel Stenbergaa458aa2002-08-23 12:41:25 +0000346 result = MENU_DISK_CHANGED;
Justin Heiner26302452002-08-23 02:17:00 +0000347 break;
348#endif
349
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000350 default:
351 break;
352 }
353
Markus Braun5e4c1d22002-08-20 19:37:00 +0000354 status_draw();
Björn Stenbergb21a3bd2002-05-21 14:25:45 +0000355 lcd_update();
356 }
Daniel Stenbergb2850762002-08-23 12:32:52 +0000357
358 return result;
Robert Hak7ec9aa32002-05-18 11:41:37 +0000359}