First step towards context sensitive and configurable menus, by Brent Coutts


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4370 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/action.h b/apps/action.h
new file mode 100644
index 0000000..ef17185
--- /dev/null
+++ b/apps/action.h
@@ -0,0 +1,28 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (C) 2004 Brent Coutts
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __ACTION_H__
+#define __ACTION_H__
+
+#include "stdbool.h"
+
+#define CONTEXT_WPS                                     1
+#define CONTEXT_TREE                                    2
+#define CONTEXT_RECORD                                  3
+#define CONTEXT_MAINMENU                                4
+
+#endif
diff --git a/apps/bookmark.c b/apps/bookmark.c
index 5ecd10e..51b720b 100644
--- a/apps/bookmark.c
+++ b/apps/bookmark.c
@@ -98,7 +98,7 @@
         { str(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS), bookmark_mrb_load},
     };
 
-    m=menu_init( items, sizeof items / sizeof(struct menu_items) );
+    m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
 
 #ifdef HAVE_LCD_CHARCELLS
     status_set_param(true);
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index a2535d7..b77014a 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1509,7 +1509,7 @@
 #endif
     };
 
-    m=menu_init( items, sizeof items / sizeof(struct menu_items) );
+    m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
     result = menu_run(m);
     menu_exit(m);
     
diff --git a/apps/main_menu.c b/apps/main_menu.c
index 23af8d7..f42655b 100644
--- a/apps/main_menu.c
+++ b/apps/main_menu.c
@@ -254,6 +254,7 @@
 #endif
 
 #ifdef HAVE_MAS3587F
+
 bool rec_menu(void)
 {
     int m;
@@ -265,7 +266,7 @@
         { str(LANG_RECORDING_SETTINGS), recording_settings},
     };
 
-    m=menu_init( items, sizeof items / sizeof(struct menu_items) );
+    m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
     result = menu_run(m);
     menu_exit(m);
 
@@ -290,7 +291,7 @@
 #endif
     };
 
-    m=menu_init( items, sizeof items / sizeof(struct menu_items) );
+    m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
     result = menu_run(m);
     menu_exit(m);
 
@@ -336,7 +337,7 @@
     items[i].desc = str(LANG_INFO);
     items[i++].function = info_menu;
 
-    m=menu_init( items, i );
+    m=menu_init( items, i, NULL );
 #ifdef HAVE_LCD_CHARCELLS
     status_set_param(true);
 #endif
diff --git a/apps/menu.c b/apps/menu.c
index 0bd21b9..f187b5d 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -17,6 +17,7 @@
  *
  ****************************************************************************/
 #include <stdbool.h>
+#include <stdlib.h>
 
 #include "hwcompat.h"
 #include "lcd.h"
@@ -42,6 +43,7 @@
     int cursor;
     struct menu_items* items;
     int itemcount;
+    int (*callback)(int, int);
 };
 
 #define MAX_MENUS 5
@@ -123,7 +125,7 @@
     }
 }
 
-static void menu_draw(int m)
+void menu_draw(int m)
 {
     int i = 0;
 #ifdef HAVE_LCD_BITMAP
@@ -216,7 +218,7 @@
 
 }
 
-int menu_init(struct menu_items* mitems, int count)
+int menu_init(struct menu_items* mitems, int count, int (*callback)(int, int))
 {
     int i;
 
@@ -234,6 +236,7 @@
     menus[i].itemcount = count;
     menus[i].top = 0;
     menus[i].cursor = 0;
+    menus[i].callback = callback;
 
     return i;
 }
@@ -246,6 +249,7 @@
 int menu_show(int m)
 {
     bool exit = false;
+    int key;
 #ifdef HAVE_LCD_BITMAP
     int fw, fh;
     int menu_lines;
@@ -260,7 +264,16 @@
     menu_draw(m);
 
     while (!exit) {
-        switch( button_get_w_tmo(HZ/2) ) {
+        key = button_get_w_tmo(HZ/2);
+        
+        /*  
+         *   "short-circuit" the default keypresses by running the callback function
+         */
+
+        if( menus[m].callback != NULL )
+            key = menus[m].callback(key, m);            /* make sure there's no match in the switch */
+
+        switch( key ) {
 #ifdef HAVE_RECORDER_KEYPAD
             case BUTTON_UP:
             case BUTTON_UP | BUTTON_REPEAT:
@@ -326,20 +339,6 @@
                 exit = true;
                 break;
 
-#ifdef HAVE_RECORDER_KEYPAD
-            case BUTTON_F2:
-                if (f2_screen())
-                    return MENU_ATTACHED_USB;
-                menu_draw(m);
-                break;
-
-            case BUTTON_F3:
-                if (f3_screen())
-                    return MENU_ATTACHED_USB;
-                menu_draw(m);
-                break;
-#endif
-
             case SYS_USB_CONNECTED:
                 usb_screen();
 #ifdef HAVE_LCD_CHARCELLS
@@ -369,3 +368,92 @@
   }
   return false;
 }
+
+/*  
+ *  Property function - return the current cursor for "menu"
+ */
+
+int menu_cursor(int menu)
+{
+    return menus[menu].cursor;
+}
+
+/*  
+ *  Property function - return the "menu" description at "position"
+ */
+
+char* menu_description(int menu, int position)
+{
+    return menus[menu].items[position].desc;
+}
+
+/*  
+ *  Delete the element "position" from the menu items in "menu"
+ */
+
+void menu_delete(int menu, int position)
+{
+    int i;
+    
+    /* copy the menu item from the one below */
+    for( i = position; i < (menus[menu].itemcount - 1); i++)
+        menus[menu].items[i] = menus[menu].items[i + 1];
+ 
+    /* reduce the count */       
+    menus[menu].itemcount--;
+    
+    /* adjust if this was the last menu item and the cursor was on it */
+    if( menus[menu].itemcount <= menus[menu].cursor)
+        menus[menu].cursor = menus[menu].itemcount - 1;
+}
+
+/*  
+ *  Property function - return the "count" of menu items in "menu" 
+ */
+
+int menu_count(int menu)
+{
+    return menus[menu].itemcount;
+}
+
+/*  
+ *  Allows a menu item at the current cursor position in "menu" to be moved up the list
+ */
+
+bool menu_moveup(int menu)
+{
+    struct menu_items swap;
+    
+    /* can't be the first item ! */
+    if( menus[menu].cursor == 0)
+        return false;
+    
+    /* use a temporary variable to do the swap */    
+    swap = menus[menu].items[menus[menu].cursor - 1];
+    menus[menu].items[menus[menu].cursor - 1] = menus[menu].items[menus[menu].cursor];
+    menus[menu].items[menus[menu].cursor] = swap;
+    menus[menu].cursor--;
+    
+    return true;
+}
+
+/*  
+ *  Allows a menu item at the current cursor position in "menu" to be moved down the list
+ */
+
+bool menu_movedown(int menu)
+{
+    struct menu_items swap;
+    
+    /* can't be the last item ! */
+    if( menus[menu].cursor == menus[menu].itemcount - 1)
+        return false;
+    
+    /* use a temporary variable to do the swap */    
+    swap = menus[menu].items[menus[menu].cursor + 1];
+    menus[menu].items[menus[menu].cursor + 1] = menus[menu].items[menus[menu].cursor];
+    menus[menu].items[menus[menu].cursor] = swap;
+    menus[menu].cursor++;
+    
+    return true;
+}
diff --git a/apps/menu.h b/apps/menu.h
index 632db87..827de1d 100644
--- a/apps/menu.h
+++ b/apps/menu.h
@@ -27,7 +27,7 @@
     bool (*function) (void); /* return true if USB was connected */
 };
 
-int menu_init(struct menu_items* items, int count);
+int menu_init(struct menu_items* items, int count, int (*callback) (int keycode, int menu));
 void menu_exit(int menu);
 
 void put_cursorxy(int x, int y, bool on);
@@ -38,6 +38,13 @@
 #define MENU_SELECTED_EXIT -2
 
 bool menu_run(int menu);
+int menu_cursor(int menu);
+char* menu_description(int menu, int position);
+void menu_delete(int menu, int position);
+int menu_count(int menu);
+bool menu_moveup(int menu);
+bool menu_movedown(int menu);
+void menu_draw(int menu);
 
 #endif /* End __MENU_H__ */
 
diff --git a/apps/onplay.c b/apps/onplay.c
index 52d5d20..e4733fb 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -193,7 +193,7 @@
         i++;
     }
 
-    m = menu_init( menu, i );
+    m = menu_init( menu, i, NULL );
     result = menu_show(m);
     if (result >= 0 && result < pstart)
         ret = menu[result].function();
@@ -580,7 +580,7 @@
     i++;
 
     /* DIY menu handling, since we want to exit after selection */
-    m = menu_init( menu, i );
+    m = menu_init( menu, i, NULL );
     result = menu_show(m);
     if (result >= 0)
         menu[result].function();
diff --git a/apps/playlist_menu.c b/apps/playlist_menu.c
index b274278..87862ab 100644
--- a/apps/playlist_menu.c
+++ b/apps/playlist_menu.c
@@ -71,7 +71,7 @@
         { str(LANG_RECURSE_DIRECTORY),     recurse_directory },
     };
     
-    m = menu_init( items, sizeof items / sizeof(struct menu_items) );
+    m = menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c
index f469cc3..58052af 100644
--- a/apps/playlist_viewer.c
+++ b/apps/playlist_viewer.c
@@ -693,7 +693,7 @@
     menu[i].desc = str(LANG_FILE_OPTIONS);
     i++;
 
-    m = menu_init(menu, i);
+    m = menu_init(menu, i, NULL);
     result = menu_show(m);
     if (result == MENU_ATTACHED_USB)
         ret = -1;
@@ -763,7 +763,7 @@
         { str(LANG_SAVE_DYNAMIC_PLAYLIST),  save_playlist },
     };
     
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
 
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index fdb1f1b..a9937a3 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -604,7 +604,7 @@
         if(num_presets)
         {
             /* DIY menu handling, since we want to exit after selection */
-            m = menu_init( menu, num_presets );
+            m = menu_init( menu, num_presets, NULL );
             result = menu_show(m);
             menu_exit(m);
             if (result == MENU_SELECTED_EXIT)
@@ -676,7 +676,7 @@
         }
         
         /* DIY menu handling, since we want to exit after selection */
-        m = menu_init( menu, num_presets );
+        m = menu_init( menu, num_presets, NULL );
         result = menu_show(m);
         menu_exit(m);
         if (result == MENU_SELECTED_EXIT)
@@ -724,7 +724,7 @@
     bool result;
 
     m = menu_init( radio_menu_items,
-                   sizeof radio_menu_items / sizeof(struct menu_items) );
+                   sizeof radio_menu_items / sizeof(struct menu_items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
diff --git a/apps/screens.c b/apps/screens.c
index 6987fc9..c2320a0 100644
--- a/apps/screens.c
+++ b/apps/screens.c
@@ -37,6 +37,7 @@
 #include "system.h"
 #include "powermgmt.h"
 #include "adc.h"
+#include "action.h"
 
 #ifdef HAVE_LCD_BITMAP
 #define BMPHEIGHT_usb_logo 32
@@ -427,85 +428,128 @@
         return 0;
 }
 
-bool f2_screen(void)
+bool quick_screen(int context, int button)
 {
     bool exit = false;
     bool used = false;
-    int w, h;
+    int w, h, key;
     char buf[32];
     int oldrepeat = global_settings.repeat_mode;
-
+    
+    /* just to stop compiler warning */
+    context = context;
     lcd_setfont(FONT_SYSFIXED);
-    lcd_getstringsize("A",&w,&h);
+
+    if(button==BUTTON_F2)
+        lcd_getstringsize("A",&w,&h);
 
     while (!exit) {
         char* ptr=NULL;
 
         lcd_clear_display();
 
-        /* Shuffle mode */
-        lcd_putsxy(0, LCD_HEIGHT/2 - h*2, str(LANG_SHUFFLE));
-        lcd_putsxy(0, LCD_HEIGHT/2 - h, str(LANG_F2_MODE));
-        lcd_putsxy(0, LCD_HEIGHT/2, 
-                   global_settings.playlist_shuffle ? 
-                   str(LANG_ON) : str(LANG_OFF));
+        switch(button)
+        {
+            case BUTTON_F2:
+                /* Shuffle mode */
+                lcd_putsxy(0, LCD_HEIGHT/2 - h*2, str(LANG_SHUFFLE));
+                lcd_putsxy(0, LCD_HEIGHT/2 - h, str(LANG_F2_MODE));
+                lcd_putsxy(0, LCD_HEIGHT/2, 
+                           global_settings.playlist_shuffle ? 
+                           str(LANG_ON) : str(LANG_OFF));
+
+                /* Directory Filter */
+                switch ( global_settings.dirfilter ) {
+                    case SHOW_ALL:
+                        ptr = str(LANG_FILTER_ALL);
+                        break;
+        
+                    case SHOW_SUPPORTED:
+                        ptr = str(LANG_FILTER_SUPPORTED);
+                        break;
+        
+                    case SHOW_MUSIC:
+                        ptr = str(LANG_FILTER_MUSIC);
+                        break;
+                        
+                    case SHOW_PLAYLIST:
+                        ptr = str(LANG_FILTER_PLAYLIST);
+                        break;
+                }
+        
+                snprintf(buf, sizeof buf, "%s:", str(LANG_FILTER));
+                lcd_getstringsize(buf,&w,&h);
+                lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, buf);
+                lcd_getstringsize(ptr,&w,&h);
+                lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr);
+
+                /* Repeat Mode */
+                switch ( global_settings.repeat_mode ) {
+                    case REPEAT_OFF:
+                        ptr = str(LANG_OFF);
+                        break;
+        
+                    case REPEAT_ALL:
+                        ptr = str(LANG_REPEAT_ALL);
+                        break;
+        
+                    case REPEAT_ONE:
+                        ptr = str(LANG_REPEAT_ONE);
+                        break;
+                }
+        
+                lcd_getstringsize(str(LANG_REPEAT),&w,&h);
+                lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h*2, str(LANG_REPEAT));
+                lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h, str(LANG_F2_MODE));
+                lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2, ptr);
+                break;
+            case BUTTON_F3:
+                /* Scrollbar */
+                lcd_putsxy(0, LCD_HEIGHT/2 - h*2, str(LANG_F3_SCROLL));
+                lcd_putsxy(0, LCD_HEIGHT/2 - h, str(LANG_F3_BAR));
+                lcd_putsxy(0, LCD_HEIGHT/2, 
+                           global_settings.scrollbar ? str(LANG_ON) : str(LANG_OFF));
+    
+                /* Status bar */
+                ptr = str(LANG_F3_STATUS);
+                lcd_getstringsize(ptr,&w,&h);
+                lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h*2, ptr);
+                lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h, str(LANG_F3_BAR));
+                lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2, 
+                           global_settings.statusbar ? str(LANG_ON) : str(LANG_OFF));
+    
+                /* Flip */
+                ptr = str(LANG_FLIP_DISPLAY);
+                lcd_getstringsize(ptr,&w,&h);
+                lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, str(LANG_FLIP_DISPLAY));
+                ptr = global_settings.flip_display ?
+                           str(LANG_SET_BOOL_YES) : str(LANG_SET_BOOL_NO);
+                lcd_getstringsize(ptr,&w,&h);
+                lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr);
+                break;
+        }
+
         lcd_bitmap(bitmap_icons_7x8[Icon_FastBackward], 
                    LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8, true);
-
-        /* Directory Filter */
-        switch ( global_settings.dirfilter ) {
-            case SHOW_ALL:
-                ptr = str(LANG_FILTER_ALL);
-                break;
-
-            case SHOW_SUPPORTED:
-                ptr = str(LANG_FILTER_SUPPORTED);
-                break;
-
-            case SHOW_MUSIC:
-                ptr = str(LANG_FILTER_MUSIC);
-                break;
-                
-            case SHOW_PLAYLIST:
-                ptr = str(LANG_FILTER_PLAYLIST);
-                break;
-        }
-
-        snprintf(buf, sizeof buf, "%s:", str(LANG_FILTER));
-        lcd_getstringsize(buf,&w,&h);
-        lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, buf);
-        lcd_getstringsize(ptr,&w,&h);
-        lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr);
         lcd_bitmap(bitmap_icons_7x8[Icon_DownArrow],
                    LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8, true);
-
-        /* Repeat Mode */
-        switch ( global_settings.repeat_mode ) {
-            case REPEAT_OFF:
-                ptr = str(LANG_OFF);
-                break;
-
-            case REPEAT_ALL:
-                ptr = str(LANG_REPEAT_ALL);
-                break;
-
-            case REPEAT_ONE:
-                ptr = str(LANG_REPEAT_ONE);
-                break;
-        }
-
-        lcd_getstringsize(str(LANG_REPEAT),&w,&h);
-        lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h*2, str(LANG_REPEAT));
-        lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h, str(LANG_F2_MODE));
-        lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2, ptr);
         lcd_bitmap(bitmap_icons_7x8[Icon_FastForward], 
                    LCD_WIDTH/2 + 8, LCD_HEIGHT/2 - 4, 7, 8, true);
 
         lcd_update();
-
-        switch (button_get(true)) {
-            case BUTTON_LEFT:
+        key = button_get(true);
+        
+        /*  
+         *  This is a temporary kludge so that the F2 & F3 menus operate in exactly
+         *  the same manner up until the full F2/F3 configurable menus are complete
+         */  
+          
+        if( key == BUTTON_LEFT || key == BUTTON_RIGHT || key == BUTTON_DOWN || key == ( BUTTON_LEFT | BUTTON_REPEAT ) || key == ( BUTTON_RIGHT  | BUTTON_REPEAT ) || key == ( BUTTON_DOWN  | BUTTON_REPEAT ) )
+            key = button | key;
+            
+        switch (key) {
             case BUTTON_F2 | BUTTON_LEFT:
+            case BUTTON_F2 | BUTTON_LEFT | BUTTON_REPEAT:
                 global_settings.playlist_shuffle =
                     !global_settings.playlist_shuffle;
 
@@ -519,110 +563,38 @@
                 used = true;
                 break;
 
-            case BUTTON_DOWN:
             case BUTTON_F2 | BUTTON_DOWN:
+            case BUTTON_F2 | BUTTON_DOWN | BUTTON_REPEAT:
                 global_settings.dirfilter++;
                 if ( global_settings.dirfilter >= NUM_FILTER_MODES )
                     global_settings.dirfilter = 0;
                 used = true;
                 break;
 
-            case BUTTON_RIGHT:
             case BUTTON_F2 | BUTTON_RIGHT:
+            case BUTTON_F2 | BUTTON_RIGHT | BUTTON_REPEAT:
                 global_settings.repeat_mode++;
                 if ( global_settings.repeat_mode >= NUM_REPEAT_MODES )
                     global_settings.repeat_mode = 0;
                 used = true;
                 break;
 
-            case BUTTON_F2 | BUTTON_REL:
-                if ( used )
-                    exit = true;
-                used = true;
-                break;
-
-            case BUTTON_F2 | BUTTON_REPEAT:
-                used = true;
-                break;
-
-            case BUTTON_OFF | BUTTON_REPEAT:
-                return false;
-                
-            case SYS_USB_CONNECTED:
-                usb_screen();
-                return true;
-        }
-    }
-
-    settings_save();
-    lcd_setfont(FONT_UI);
-    if ( oldrepeat != global_settings.repeat_mode )
-        mpeg_flush_and_reload_tracks();
-
-    return false;
-}
-
-bool f3_screen(void)
-{
-    bool exit = false;
-    bool used = false;
-
-    lcd_setfont(FONT_SYSFIXED);
-
-    while (!exit) {
-        int w,h;
-        char* ptr;
-
-        lcd_clear_display();
-
-        /* Scrollbar */
-        lcd_putsxy(0, LCD_HEIGHT/2 - h*2, str(LANG_F3_SCROLL));
-        lcd_putsxy(0, LCD_HEIGHT/2 - h, str(LANG_F3_BAR));
-        lcd_putsxy(0, LCD_HEIGHT/2, 
-                   global_settings.scrollbar ? str(LANG_ON) : str(LANG_OFF));
-        lcd_bitmap(bitmap_icons_7x8[Icon_FastBackward], 
-                   LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8, true);
-
-        /* Status bar */
-        ptr = str(LANG_F3_STATUS);
-        lcd_getstringsize(ptr,&w,&h);
-        lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h*2, ptr);
-        lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h, str(LANG_F3_BAR));
-        lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2, 
-                   global_settings.statusbar ? str(LANG_ON) : str(LANG_OFF));
-        lcd_bitmap(bitmap_icons_7x8[Icon_FastForward], 
-                   LCD_WIDTH/2 + 8, LCD_HEIGHT/2 - 4, 7, 8, true);
-
-        /* Flip */
-        ptr = str(LANG_FLIP_DISPLAY);
-        lcd_getstringsize(ptr,&w,&h);
-        lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, str(LANG_FLIP_DISPLAY));
-        ptr = global_settings.flip_display ?
-                   str(LANG_SET_BOOL_YES) : str(LANG_SET_BOOL_NO);
-        lcd_getstringsize(ptr,&w,&h);
-        lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr);
-        lcd_bitmap(bitmap_icons_7x8[Icon_DownArrow],
-                   LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8, true);
-
-        lcd_update();
-
-        switch (button_get(true)) {
-            case BUTTON_LEFT:
             case BUTTON_F3 | BUTTON_LEFT:
+            case BUTTON_F3 | BUTTON_LEFT | BUTTON_REPEAT:
                 global_settings.scrollbar = !global_settings.scrollbar;
                 used = true;
                 break;
 
-            case BUTTON_RIGHT:
             case BUTTON_F3 | BUTTON_RIGHT:
+            case BUTTON_F3 | BUTTON_RIGHT | BUTTON_REPEAT:
                 global_settings.statusbar = !global_settings.statusbar;
                 used = true;
                 break;
 
-            case BUTTON_DOWN:
             case BUTTON_F3 | BUTTON_DOWN:
-            case BUTTON_UP: /* allow "up" as well, more tolerant if tilted */
+            case BUTTON_F3 | BUTTON_DOWN | BUTTON_REPEAT:
             case BUTTON_F3 | BUTTON_UP:
+            case BUTTON_F3 | BUTTON_UP | BUTTON_REPEAT:
                 global_settings.flip_display = !global_settings.flip_display;
                 button_set_flip(global_settings.flip_display);
                 lcd_set_flip(global_settings.flip_display);
@@ -630,13 +602,13 @@
                 break;
 
             case BUTTON_F3 | BUTTON_REL:
-                if ( used )
+            case BUTTON_F2 | BUTTON_REL:
+            
+                if( used )
                     exit = true;
-                used = true;
-                break;
 
-            case BUTTON_F3 | BUTTON_REPEAT:
                 used = true;
+                    
                 break;
 
             case BUTTON_OFF | BUTTON_REPEAT:
@@ -649,10 +621,25 @@
     }
 
     settings_save();
-    if (global_settings.statusbar)
-        lcd_setmargins(0, STATUSBAR_HEIGHT);
-    else
-        lcd_setmargins(0, 0);
+    
+    switch( button )
+    {
+        case BUTTON_F2:
+
+            if ( oldrepeat != global_settings.repeat_mode )
+                mpeg_flush_and_reload_tracks();
+
+            break;
+        case BUTTON_F3:
+
+            if (global_settings.statusbar)
+                lcd_setmargins(0, STATUSBAR_HEIGHT);
+            else
+                lcd_setmargins(0, 0);
+                
+            break;
+    }
+    
     lcd_setfont(FONT_UI);
 
     return false;
diff --git a/apps/screens.h b/apps/screens.h
index fdd5df1..2fa081a 100644
--- a/apps/screens.h
+++ b/apps/screens.h
@@ -26,8 +26,7 @@
 
 #ifdef HAVE_RECORDER_KEYPAD
 int on_screen(void);
-bool f2_screen(void);
-bool f3_screen(void);
+bool quick_screen(const int, const int);
 #endif
 
 void splash(int ticks,  /* how long */
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 24a67ad..7c060c4 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -380,7 +380,7 @@
         { str(LANG_PM_MAX)      , peak_meter_max       },
     };
     
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -795,7 +795,7 @@
         { str(LANG_FFRW_ACCEL), ff_rewind_accel },
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
 
@@ -819,7 +819,7 @@
 
     bool old_shuffle = global_settings.playlist_shuffle;
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
 
@@ -848,7 +848,7 @@
         { str(LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS), useMRB},
     };
 
-    m=menu_init( items, sizeof items / sizeof(struct menu_items) );
+    m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
     result = menu_run(m);
     menu_exit(m);
 
@@ -916,7 +916,7 @@
         { str(LANG_SHOW_ICONS),   show_icons          },
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -941,7 +941,7 @@
 #endif
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -964,7 +964,7 @@
 #endif
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -983,7 +983,7 @@
         { str(LANG_BATTERY_DISPLAY), battery_type },
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -1009,7 +1009,7 @@
 #endif
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -1036,7 +1036,7 @@
 #endif
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -1054,7 +1054,7 @@
 #endif
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -1071,7 +1071,7 @@
         { str(LANG_TIMEFORMAT),  timeformat_set  },
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -1090,7 +1090,7 @@
         { str(LANG_SAVE_SETTINGS),   settings_save_config },
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -1106,7 +1106,7 @@
         { str(LANG_MAX_FILES_IN_PLAYLIST),    max_files_in_playlist        },
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -1137,7 +1137,7 @@
         { str(LANG_MANAGE_MENU),      manage_settings_menu   },
     };
 
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
@@ -1157,7 +1157,7 @@
         { str(LANG_LANGUAGE),         language_browse        },
     };
     
-    m=menu_init( items, sizeof(items) / sizeof(*items) );
+    m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
     result = menu_run(m);
     menu_exit(m);
     return result;
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index 01bbe09..256da0b 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -307,7 +307,7 @@
 #endif
     };
     
-    m=menu_init( items, sizeof items / sizeof(struct menu_items) );
+    m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
     result = menu_run(m);
     menu_exit(m);
 
@@ -341,7 +341,7 @@
     menu[i].desc = str(LANG_RECORD_DIRECTORY);
     menu[i++].function = recdirectory;
         
-    m=menu_init( menu, i );
+    m=menu_init( menu, i, NULL );
     result = menu_run(m);
     menu_exit(m);
 
diff --git a/apps/tree.c b/apps/tree.c
index 88fb2f3..7a7ba3a 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -54,6 +54,7 @@
 #include "buffer.h"
 #include "plugin.h"
 #include "power.h"
+#include "action.h"
 
 #ifdef HAVE_LCD_BITMAP
 #include "widgets.h"
@@ -1277,7 +1278,7 @@
             case BUTTON_F2:
                 if (*dirfilter < NUM_FILTER_MODES)
                 {
-                    if (f2_screen())
+                    if (quick_screen(CONTEXT_TREE, BUTTON_F2))
                         reload_root = true;
                     restore = true;
                     break;
@@ -1286,7 +1287,7 @@
             case BUTTON_F3:
                 if (*dirfilter < NUM_FILTER_MODES)
                 {
-                    if (f3_screen())
+                    if (quick_screen(CONTEXT_TREE, BUTTON_F3))
                         reload_root = true;
 
 #ifdef HAVE_LCD_BITMAP
diff --git a/apps/wps.c b/apps/wps.c
index f1c1adc..e1a2bab 100644
--- a/apps/wps.c
+++ b/apps/wps.c
@@ -43,6 +43,7 @@
 #ifdef HAVE_LCD_BITMAP
 #include "icons.h"
 #include "peakmeter.h"
+#include "action.h"
 #endif
 #include "lang.h"
 #include "bookmark.h"
@@ -926,14 +927,14 @@
 #ifdef HAVE_RECORDER_KEYPAD
                 /* play settings */
             case BUTTON_F2:
-                if (f2_screen())
+                if (quick_screen(CONTEXT_WPS, BUTTON_F2))
                     return SYS_USB_CONNECTED;
                 restore = true;
                 break;
 
                 /* screen settings */
             case BUTTON_F3:
-                if (f3_screen())
+                if (quick_screen(CONTEXT_WPS, BUTTON_F2))
                     return SYS_USB_CONNECTED;
                 restore = true;
                 break;
diff --git a/docs/CREDITS b/docs/CREDITS
index b05f6c9..8affb93 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -83,3 +83,4 @@
 Zakk Roberts
 Francois Boucher
 Matthias Wientapper
+Brent Coutts