1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Robert E. Hak
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
25 #include "backlight.h"
37 #ifdef HAVE_LCD_BITMAP
45 struct menu_item
* items
;
47 int (*callback
)(int, int);
48 #ifdef HAVE_LCD_BITMAP
49 bool use_buttonbar
; /* true if a buttonbar is defined */
56 #ifdef HAVE_LCD_BITMAP
59 #define MARGIN_X (global_settings.scrollbar && \
60 menu_lines < menus[m].itemcount ? SCROLLBAR_WIDTH : 0) +\
62 #define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0)
64 /* position the entry-list starts at */
66 #define LINE_Y (global_settings.statusbar ? 1 : 0)
68 #define CURSOR_X (global_settings.scrollbar && \
69 menu_lines < menus[m].itemcount ? 1 : 0)
70 #define CURSOR_Y 0 /* the cursor is not positioned in regard to
71 the margins, so this is the amount of lines
72 we add to the cursor Y position to position
74 #define CURSOR_WIDTH (global_settings.invert_cursor ? 0 : 4)
77 #define SCROLLBAR_Y lcd_getymargin()
78 #define SCROLLBAR_WIDTH 6
80 #else /* HAVE_LCD_BITMAP */
82 #define LINE_X 1 /* X position the entry-list starts at */
87 #define CURSOR_Y 0 /* not really used for players */
89 #endif /* HAVE_LCD_BITMAP */
91 #define CURSOR_CHAR 0x92
93 static struct menu menus
[MAX_MENUS
];
94 static bool inuse
[MAX_MENUS
] = { false };
96 /* count in letter positions, NOT pixels */
97 void put_cursorxy(int x
, int y
, bool on
)
99 #ifdef HAVE_LCD_BITMAP
103 /* check here instead of at every call (ugly, but cheap) */
104 if (global_settings
.invert_cursor
)
107 lcd_getstringsize("A", &fw
, &fh
);
109 ypos
= y
*fh
+ lcd_getymargin();
111 ypos
+= (fh
- 8) / 2;
114 /* place the cursor */
116 #ifdef HAVE_LCD_BITMAP
117 lcd_bitmap ( bitmap_icons_6x8
[Cursor
],
118 xpos
, ypos
, 4, 8, true);
120 lcd_putc(x
, y
, CURSOR_CHAR
);
124 #if defined(HAVE_LCD_BITMAP)
125 /* I use xy here since it needs to disregard the margins */
126 lcd_clearrect (xpos
, ypos
, 4, 8);
133 void menu_draw(int m
)
136 #ifdef HAVE_LCD_BITMAP
139 int height
= LCD_HEIGHT
;
141 lcd_setfont(FONT_UI
);
142 lcd_getstringsize("A", &fw
, &fh
);
143 if (global_settings
.statusbar
)
144 height
-= STATUSBAR_HEIGHT
;
146 if(global_settings
.buttonbar
&& menus
[m
].use_buttonbar
) {
147 buttonbar_set(menus
[m
].buttonbar
[0],
148 menus
[m
].buttonbar
[1],
149 menus
[m
].buttonbar
[2]);
150 height
-= BUTTONBAR_HEIGHT
;
153 menu_lines
= height
/ fh
;
156 int menu_lines
= MENU_LINES
;
160 #ifdef HAVE_LCD_BITMAP
161 lcd_setmargins(MARGIN_X
,MARGIN_Y
); /* leave room for cursor and icon */
163 /* Adjust cursor pos if it's below the screen */
164 if (menus
[m
].cursor
- menus
[m
].top
>= menu_lines
)
167 /* Adjust cursor pos if it's above the screen */
168 if(menus
[m
].cursor
< menus
[m
].top
)
169 menus
[m
].top
= menus
[m
].cursor
;
171 for (i
= menus
[m
].top
;
172 (i
< menus
[m
].itemcount
) && (i
<menus
[m
].top
+menu_lines
);
175 /* We want to scroll the line where the cursor is */
176 if((menus
[m
].cursor
- menus
[m
].top
)==(i
-menus
[m
].top
))
177 #ifdef HAVE_LCD_BITMAP
178 if (global_settings
.invert_cursor
)
179 lcd_puts_scroll_style(LINE_X
, i
-menus
[m
].top
,
180 menus
[m
].items
[i
].desc
, STYLE_INVERT
);
183 lcd_puts_scroll(LINE_X
, i
-menus
[m
].top
, menus
[m
].items
[i
].desc
);
185 lcd_puts(LINE_X
, i
-menus
[m
].top
, menus
[m
].items
[i
].desc
);
188 /* place the cursor */
189 put_cursorxy(CURSOR_X
, menus
[m
].cursor
- menus
[m
].top
, true);
191 #ifdef HAVE_LCD_BITMAP
192 if (global_settings
.scrollbar
&& menus
[m
].itemcount
> menu_lines
)
193 scrollbar(SCROLLBAR_X
, SCROLLBAR_Y
, SCROLLBAR_WIDTH
- 1,
194 height
, menus
[m
].itemcount
, menus
[m
].top
,
195 menus
[m
].top
+ menu_lines
, VERTICAL
);
197 if(global_settings
.buttonbar
&& menus
[m
].use_buttonbar
)
206 * Move the cursor to a particular id,
207 * target: where you want it to be
209 static void put_cursor(int m
, int target
)
213 menus
[m
].cursor
= target
;
216 /* "say" the entry under the cursor */
217 if(global_settings
.talk_menu
)
219 voice_id
= menus
[m
].items
[menus
[m
].cursor
].voice_id
;
220 if (voice_id
>= 0) /* valid ID given? */
221 talk_id(voice_id
, false); /* say it */
225 int menu_init(struct menu_item
* mitems
, int count
, int (*callback
)(int, int),
226 char *button1
, char *button2
, char *button3
)
230 for ( i
=0; i
<MAX_MENUS
; i
++ ) {
236 if ( i
== MAX_MENUS
) {
237 DEBUGF("Out of menus!\n");
240 menus
[i
].items
= mitems
;
241 menus
[i
].itemcount
= count
;
244 menus
[i
].callback
= callback
;
245 #ifdef HAVE_LCD_BITMAP
246 menus
[i
].buttonbar
[0] = button1
;
247 menus
[i
].buttonbar
[1] = button2
;
248 menus
[i
].buttonbar
[2] = button3
;
250 if(button1
|| button2
|| button3
)
251 menus
[i
].use_buttonbar
= true;
253 menus
[i
].use_buttonbar
= false;
262 void menu_exit(int m
)
271 #ifdef HAVE_LCD_BITMAP
274 int height
= LCD_HEIGHT
;
276 lcd_setfont(FONT_UI
);
277 lcd_getstringsize("A", &fw
, &fh
);
278 if (global_settings
.statusbar
)
279 height
-= STATUSBAR_HEIGHT
;
281 if(global_settings
.buttonbar
&& menus
[m
].use_buttonbar
) {
282 buttonbar_set(menus
[m
].buttonbar
[0],
283 menus
[m
].buttonbar
[1],
284 menus
[m
].buttonbar
[2]);
285 height
-= BUTTONBAR_HEIGHT
;
288 menu_lines
= height
/ fh
;
291 /* Put the cursor on the first line and draw the menu */
292 put_cursor(m
, menus
[m
].cursor
);
295 key
= button_get_w_tmo(HZ
/2);
298 * "short-circuit" the default keypresses by running the
300 * The callback may return a new key value, often this will be
301 * BUTTON_NONE or the same key value, but it's perfectly legal
302 * to "simulate" key presses by returning another value.
305 if( menus
[m
].callback
!= NULL
)
306 key
= menus
[m
].callback(key
, m
);
310 #ifdef HAVE_RECORDER_KEYPAD
312 case BUTTON_UP
| BUTTON_REPEAT
:
315 case BUTTON_LEFT
| BUTTON_REPEAT
:
317 if (menus
[m
].cursor
) {
319 put_cursor(m
, menus
[m
].cursor
-1);
323 #ifdef HAVE_RECORDER_KEYPAD
324 menus
[m
].top
= menus
[m
].itemcount
-(menu_lines
+1);
326 menus
[m
].top
= menus
[m
].itemcount
-3;
328 if (menus
[m
].top
< 0)
330 menus
[m
].cursor
= menus
[m
].itemcount
-1;
331 put_cursor(m
, menus
[m
].itemcount
-1);
335 #ifdef HAVE_RECORDER_KEYPAD
337 case BUTTON_DOWN
| BUTTON_REPEAT
:
340 case BUTTON_RIGHT
| BUTTON_REPEAT
:
342 if (menus
[m
].cursor
< menus
[m
].itemcount
-1) {
344 put_cursor(m
, menus
[m
].cursor
+1);
354 #ifdef HAVE_RECORDER_KEYPAD
358 /* Erase current display state */
360 return menus
[m
].cursor
;
362 #ifdef HAVE_RECORDER_KEYPAD
365 case BUTTON_OFF
| BUTTON_REPEAT
:
369 case BUTTON_STOP
| BUTTON_REPEAT
:
375 case SYS_USB_CONNECTED
:
377 #ifdef HAVE_LCD_CHARCELLS
378 status_set_param(false);
380 return MENU_ATTACHED_USB
;
385 return MENU_SELECTED_EXIT
;
393 int result
=menu_show(m
);
394 if (result
== MENU_SELECTED_EXIT
)
396 else if (result
== MENU_ATTACHED_USB
)
398 if (menus
[m
].items
[menus
[m
].cursor
].function()) {
406 * Property function - return the current cursor for "menu"
409 int menu_cursor(int menu
)
411 return menus
[menu
].cursor
;
415 * Property function - return the "menu" description at "position"
418 char* menu_description(int menu
, int position
)
420 return menus
[menu
].items
[position
].desc
;
424 * Delete the element "position" from the menu items in "menu"
427 void menu_delete(int menu
, int position
)
431 /* copy the menu item from the one below */
432 for( i
= position
; i
< (menus
[menu
].itemcount
- 1); i
++)
433 menus
[menu
].items
[i
] = menus
[menu
].items
[i
+ 1];
435 /* reduce the count */
436 menus
[menu
].itemcount
--;
438 /* adjust if this was the last menu item and the cursor was on it */
439 if( menus
[menu
].itemcount
<= menus
[menu
].cursor
)
440 menus
[menu
].cursor
= menus
[menu
].itemcount
- 1;
444 * Property function - return the "count" of menu items in "menu"
447 int menu_count(int menu
)
449 return menus
[menu
].itemcount
;
453 * Allows a menu item at the current cursor position in "menu" to be moved up the list
456 bool menu_moveup(int menu
)
458 struct menu_item swap
;
460 /* can't be the first item ! */
461 if( menus
[menu
].cursor
== 0)
464 /* use a temporary variable to do the swap */
465 swap
= menus
[menu
].items
[menus
[menu
].cursor
- 1];
466 menus
[menu
].items
[menus
[menu
].cursor
- 1] = menus
[menu
].items
[menus
[menu
].cursor
];
467 menus
[menu
].items
[menus
[menu
].cursor
] = swap
;
468 menus
[menu
].cursor
--;
474 * Allows a menu item at the current cursor position in "menu" to be moved down the list
477 bool menu_movedown(int menu
)
479 struct menu_item swap
;
481 /* can't be the last item ! */
482 if( menus
[menu
].cursor
== menus
[menu
].itemcount
- 1)
485 /* use a temporary variable to do the swap */
486 swap
= menus
[menu
].items
[menus
[menu
].cursor
+ 1];
487 menus
[menu
].items
[menus
[menu
].cursor
+ 1] = menus
[menu
].items
[menus
[menu
].cursor
];
488 menus
[menu
].items
[menus
[menu
].cursor
] = swap
;
489 menus
[menu
].cursor
++;