Пример #1
0
unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
{
    short x, y;
    const enum screen_type screen = SCREEN_MAIN;
    struct viewport *info_vp = sb_skin_get_info_vp(screen);
    const int button = action_get_touchscreen_press_in_vp(&x, &y, info_vp);
    const int list_start_item = gui_list->start_item[screen];
    const int line_height = font_get(gui_list->parent[screen]->font)->height;
    const struct viewport *list_text_vp = &list_text[screen];
    const bool old_released = released;
    const bool show_title = list_display_title(gui_list, screen);
    const bool show_cursor = !global_settings.cursor_style &&
                        gui_list->show_selection_marker;
    const bool on_title_clicked = show_title && y < line_height && (button&BUTTON_REL);
    const bool cancelled_kinetic = (scroll_mode == SCROLL_KINETIC
                        && button != ACTION_NONE && button != ACTION_UNKNOWN
                        && !is_kinetic_over());
    int icon_width = 0;
    int line, list_width = list_text_vp->width;

    released = (button&BUTTON_REL) != 0;

    if (button == ACTION_NONE || button == ACTION_UNKNOWN)
    {
        /* this happens when we hit edges of the list while kinetic scrolling,
         * but not when manually cancelling */
        if (scroll_mode == SCROLL_KINETIC)
            return ACTION_REDRAW;
        return ACTION_NONE;
    }

    /* x and y are relative to info_vp */
    if (gui_list->callback_get_item_icon != NULL)
        icon_width += get_icon_width(screen);
    if (show_cursor)
        icon_width += get_icon_width(screen);

    if (on_title_clicked)
    {
        if (scroll_mode == SCROLL_NONE || is_kinetic_over())
        {
            if (x < icon_width)
            {
                /* Top left corner is GO_TO_ROOT */
                if (button == BUTTON_REL)
                    return ACTION_STD_MENU;
                else if (button == (BUTTON_REPEAT|BUTTON_REL))
                    return ACTION_STD_CONTEXT;
                return ACTION_NONE;
            }
            else /* click on title text is cancel */
                if (button == BUTTON_REL)
                    return ACTION_STD_CANCEL;
        }
        /* do this after the above so the scrolling stops without
         * going back in the list with the same touch */
        if (scroll_mode == SCROLL_KINETIC)
        {
            kinetic_force_stop();
            scroll_mode = SCROLL_NONE;
        }
    }
    else /* list area clicked (or not released) */
    {
        const int actual_y = y - (show_title ? line_height : 0);
        bool on_scrollbar_clicked;
        switch (global_settings.scrollbar)
        {
            case SCROLLBAR_LEFT:
                on_scrollbar_clicked = x <= SCROLLBAR_WIDTH; break;
            case SCROLLBAR_RIGHT:
                on_scrollbar_clicked = x > (icon_width + list_width); break;
            default:
                on_scrollbar_clicked = false; break;
        }
        /* conditions for scrollbar scrolling:
         *    * pen is on the scrollbar
         *      AND scrollbar is on the right (left case is handled above)
         * OR * pen is in the somewhere else but we did scrollbar scrolling before
         *
         * scrollbar scrolling must end if the pen is released
         * scrollbar scrolling must not happen if we're currently scrolling
         * via swiping the screen
         **/

        if (!released && scroll_mode != SCROLL_SWIPE &&
            (on_scrollbar_clicked || scroll_mode == SCROLL_BAR))
        {
            if (scroll_mode == SCROLL_KINETIC)
                kinetic_force_stop();
            scroll_mode = SCROLL_BAR;
            return scrollbar_scroll(gui_list, y);
        }

        /* |--------------------------------------------------------|
         * | Description of the touchscreen list interface:         |
         * |--------------------------------------------------------|
         * | Pressing an item will select it and "enter" it.        |
         * |                                                        |
         * | Pressing and holding your pen down will scroll through |
         * | the list of items.                                     |
         * |                                                        |
         * | Pressing and holding your pen down on a single item    |
         * | will bring up the context menu of it.                  |
         * |--------------------------------------------------------|
         */
        if (actual_y > 0 || button & BUTTON_REPEAT)
        {
            /* selection needs to be corrected if an items are only
             * partially visible */
            line = (actual_y - y_offset) / line_height;

            if (cancelled_kinetic)
            {
                kinetic_force_stop();
                scroll_mode = SCROLL_SWIPE;
            }

            /* Pressed below the list*/
            if (list_start_item + line >= gui_list->nb_items)
            {
                /* don't collect last_position outside of the list area
                 * it'd break selecting after such a situation */
                last_position = 0;
                return ACTION_NONE;
            }

            if (button & BUTTON_REPEAT && scroll_mode == SCROLL_NONE)
            {
                /* held a single line for a while, bring up the context menu */
                gui_synclist_select_item(gui_list, list_start_item + line);
                /* don't sent context repeatedly */
                action_wait_for_release();
                last_position = 0;
                return ACTION_STD_CONTEXT;
            }
            if (released && !cancelled_kinetic)
            {
                /* Pen was released anywhere on the screen */
                last_position = 0;
                if (scroll_mode == SCROLL_NONE)
                {
                    /* select current line */
                    gui_synclist_select_item(gui_list, list_start_item + line);
                    return ACTION_STD_OK;
                }
                else
                {
                    /* we were scrolling
                     *  -> reset scrolling but do nothing else */
                    if (scroll_mode == SCROLL_SWIPE)
                    {
                        if (kinetic_setup_scroll(gui_list))
                            scroll_mode = SCROLL_KINETIC;
                    }
                    if (scroll_mode != SCROLL_KINETIC)
                        scroll_mode = SCROLL_NONE;
                    return ACTION_NONE;
                }
            }
            else
            {   /* pen is on the screen */
                bool redraw = false, result = false;
                /* beginning of list interaction denoted by release in
                 * the previous call */
                if (old_released || is_kinetic_over())
                {
                    scroll_mode = SCROLL_NONE;
                    redraw = true;
                }
                
                /* select current item; gui_synclist_select_item()
                 * is not called because it has side effects that
                 * disturb kinetic scrolling */
                gui_list->selected_item = list_start_item+line;
                gui_synclist_speak_item(gui_list);
                if (last_position == 0)
                {
                    redraw = true;
                    last_position = actual_y;
                }
                else
                {
                    /* record speed data in case we do kinetic scrolling */
                    int diff = actual_y - last_position;
                    kinetic_stats_collect(diff);
                    result = swipe_scroll(gui_list, line_height, diff);
                }

                /* Start scrolling once the pen is moved without
                 * releasing it inbetween */
                if (result)
                {
                    redraw = true;
                    scroll_mode = SCROLL_SWIPE;
                }
                last_position = actual_y;

                return redraw ? ACTION_REDRAW:ACTION_NONE;
            }
        }
    }
    return ACTION_REDRAW;
}
Пример #2
0
/* ------------------------------------------------------------------------*/
static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume, char** selected_bookmark)
{
    struct bookmark_list* bookmarks;
    struct gui_synclist list;
    int item = 0;
    int action;
    size_t size;
    bool exit = false;
    bool refresh = true;
    int ret = BOOKMARK_FAIL;

    bookmarks = plugin_get_buffer(&size);
    bookmarks->buffer_size = size;
    bookmarks->show_dont_resume = show_dont_resume;
    bookmarks->filename = bookmark_file_name;
    bookmarks->start = 0;
    bookmarks->show_playlist_name
        = strcmp(bookmark_file_name, RECENT_BOOKMARK_FILE) == 0;
    gui_synclist_init(&list, &get_bookmark_info, (void*) bookmarks, false, 2, NULL);
    if(global_settings.talk_menu)
        gui_synclist_set_voice_callback(&list, bookmark_list_voice_cb);
    gui_synclist_set_title(&list, str(LANG_BOOKMARK_SELECT_BOOKMARK), 
        Icon_Bookmark);

    while (!exit)
    {
        
        if (refresh)
        {
            int count = get_bookmark_count(bookmark_file_name);
            bookmarks->total_count = count;

            if (bookmarks->total_count < 1)
            {
                /* No more bookmarks, delete file and exit */
                splash(HZ, ID2P(LANG_BOOKMARK_LOAD_EMPTY));
                remove(bookmark_file_name);
                *selected_bookmark = NULL;
                return BOOKMARK_FAIL;
            }

            if (bookmarks->show_dont_resume)
            {
                count++;
                item++;
            }

            gui_synclist_set_nb_items(&list, count * 2);

            if (item >= count)
            {
                /* Selected item has been deleted */
                item = count - 1;
                gui_synclist_select_item(&list, item * 2);
            }

            buffer_bookmarks(bookmarks, bookmarks->start);
            gui_synclist_draw(&list);
            cond_talk_ids_fq(VOICE_EXT_BMARK);
            gui_synclist_speak_item(&list);
            refresh = false;
        }

        list_do_action(CONTEXT_BOOKMARKSCREEN, HZ / 2,
                       &list, &action, LIST_WRAP_UNLESS_HELD);
        item = gui_synclist_get_sel_pos(&list) / 2;

        if (bookmarks->show_dont_resume)
        {
            item--;
        }

        if (action == ACTION_STD_CONTEXT)
        {
            MENUITEM_STRINGLIST(menu_items, ID2P(LANG_BOOKMARK_CONTEXT_MENU),
                NULL, ID2P(LANG_BOOKMARK_CONTEXT_RESUME), 
                ID2P(LANG_BOOKMARK_CONTEXT_DELETE));
            static const int menu_actions[] = 
            {
                ACTION_STD_OK, ACTION_BMS_DELETE
            };
            int selection = do_menu(&menu_items, NULL, NULL, false);
            
            refresh = true;

            if (selection >= 0 && selection <= 
                (int) (sizeof(menu_actions) / sizeof(menu_actions[0])))
            {
                action = menu_actions[selection];
            }
        }

        switch (action)
        {
        case ACTION_STD_OK:
            if (item >= 0)
            {
                talk_shutup();
                *selected_bookmark = bookmarks->items[item - bookmarks->start];
                return BOOKMARK_SUCCESS;
            }
            exit = true;
            ret = BOOKMARK_SUCCESS;
            break;

        case ACTION_TREE_WPS:
        case ACTION_STD_CANCEL:
            exit = true;
            break;

        case ACTION_BMS_DELETE:
            if (item >= 0)
            {                
                const char *lines[]={
                    ID2P(LANG_REALLY_DELETE)
                };
                const char *yes_lines[]={
                    ID2P(LANG_DELETING)
                };

                const struct text_message message={lines, 1};
                const struct text_message yes_message={yes_lines, 1};

                if(gui_syncyesno_run(&message, &yes_message, NULL)==YESNO_YES)
                {                    
                    delete_bookmark(bookmark_file_name, item);
                    bookmarks->reload = true;
                }
                refresh = true;
            }
            break;

        default:
            if (default_event_handler(action) == SYS_USB_CONNECTED)
            {
                ret = BOOKMARK_USB_CONNECTED;
                exit = true;
            }

            break;
        }
    }

    talk_shutup();
    *selected_bookmark = NULL;
    return ret;
}
Пример #3
0
bool option_screen(const struct settings_list *setting,
                   struct viewport parent[NB_SCREENS],
                   bool use_temp_var, unsigned char* option_title)
{
    int action;
    bool done = false;
    struct gui_synclist lists;
    int oldvalue, nb_items = 0, selected = 0, temp_var;
    int *variable;
    bool allow_wrap = setting->flags & F_NO_WRAP ? false : true;
    int var_type = setting->flags&F_T_MASK;
    void (*function)(int) = NULL;
    char *title;
    if (var_type == F_T_INT || var_type == F_T_UINT)
    {
        variable = use_temp_var ? &temp_var: (int*)setting->setting;
        temp_var = oldvalue = *(int*)setting->setting;
    }
    else if (var_type == F_T_BOOL)
    {
        /* bools always use the temp variable...
        if use_temp_var is false it will be copied to setting->setting every change */
        variable = &temp_var;
        temp_var = oldvalue = *(bool*)setting->setting?1:0;
    }
    else return false; /* only int/bools can go here */
    gui_synclist_init(&lists, value_setting_get_name_cb,
                      (void*)setting, false, 1, parent);
    if (setting->lang_id == -1)
        title = (char*)setting->cfg_vals;
    else
        title = P2STR(option_title);
    
    gui_synclist_set_title(&lists, title, Icon_Questionmark);
    gui_synclist_set_icon_callback(&lists, NULL);
    if(global_settings.talk_menu)
        gui_synclist_set_voice_callback(&lists, option_talk);
    
    val_to_selection(setting, oldvalue, &nb_items, &selected, &function);
    gui_synclist_set_nb_items(&lists, nb_items);
    gui_synclist_select_item(&lists, selected);
    
    gui_synclist_limit_scroll(&lists, true);
    gui_synclist_draw(&lists);
    /* talk the item */
    gui_synclist_speak_item(&lists);
    while (!done)
    {
        if (list_do_action(CONTEXT_LIST, HZ, /* HZ so the status bar redraws */
                           &lists, &action,
            allow_wrap? LIST_WRAP_UNLESS_HELD: LIST_WRAP_OFF))
        {
            /* setting changed */
            selected = gui_synclist_get_sel_pos(&lists);
            *variable = selection_to_val(setting, selected);
            if (var_type == F_T_BOOL && !use_temp_var)
                *(bool*)setting->setting = (*variable==1);
        }
        else if (action == ACTION_NONE)
            continue;
        else if (action == ACTION_STD_CANCEL)
        {
            /* setting canceled, restore old value if changed */
            if (*variable != oldvalue)
            {
                *variable = oldvalue;
                if (var_type == F_T_BOOL && !use_temp_var)
                    *(bool*)setting->setting = (oldvalue==1);
                splash(HZ/2, ID2P(LANG_CANCEL));
            }
            done = true;
        }
        else if (action == ACTION_STD_CONTEXT)
        {
            /* reset setting to default */
            reset_setting(setting, variable);
            if (var_type == F_T_BOOL && !use_temp_var)
                *(bool*)setting->setting = (*variable==1);
            val_to_selection(setting, *variable, &nb_items,
                                &selected, &function);
            gui_synclist_select_item(&lists, selected);
            gui_synclist_draw(&lists);
            gui_synclist_speak_item(&lists);
        }
        else if (action == ACTION_STD_OK)
        {
            /* setting accepted, store now if it used a temp var */
            if (use_temp_var)
            {
                if (var_type == F_T_INT || var_type == F_T_UINT)
                    *(int*)setting->setting = *variable;
                else 
                    *(bool*)setting->setting = (*variable==1);
            }
            settings_save();
            done = true;
        }
        else if(default_event_handler(action) == SYS_USB_CONNECTED)
            return true;
        /* callback */
        if ( function )
            function(*variable);
        /* if the volume is changing we need to let the skins know */
        if (function == sound_get_fn(SOUND_VOLUME))
            global_status.last_volume_change = current_tick;
    }
    return false;
}
Пример #4
0
/*
 * Called when a new dir is loaded (for example when returning from other apps ...)
 * also completely redraws the tree
 */
static int update_dir(void)
{
    bool changed = false;
#ifdef HAVE_TAGCACHE
    bool id3db = *tc.dirfilter == SHOW_ID3DB;
    /* Checks for changes */
    if (id3db) {
        if (tc.currtable != lasttable ||
            tc.currextra != lastextra ||
            tc.firstpos  != lastfirstpos ||
            reload_dir)
        {
            if (tagtree_load(&tc) < 0)
                return -1;

            lasttable = tc.currtable;
            lastextra = tc.currextra;
            lastfirstpos = tc.firstpos;
            changed = true;
        }
    }
    else 
#endif
    {
        /* if the tc.currdir has been changed, reload it ...*/
        if (strncmp(tc.currdir, lastdir, sizeof(lastdir)) || reload_dir)
        {
            if (ft_load(&tc, NULL) < 0)
                return -1;
            strcpy(lastdir, tc.currdir);
            changed = true;
        }
    }
    /* if selected item is undefined */
    if (tc.selected_item == -1)
    {
        /* use lastfile to determine the selected item */
        tc.selected_item = tree_get_file_position(lastfile);

        /* If the file doesn't exists, select the first one (default) */
        if(tc.selected_item < 0)
            tc.selected_item = 0;
        changed = true;
    }
    if (changed)
    {
        if(
#ifdef HAVE_TAGCACHE
        !id3db && 
#endif
        tc.dirfull )
        {
            splash(HZ, ID2P(LANG_SHOWDIR_BUFFER_FULL));
        }
    }
#ifdef HAVE_TAGCACHE
    if (id3db) 
    {
#ifdef HAVE_LCD_BITMAP
        if (global_settings.show_path_in_browser == SHOW_PATH_FULL
            || global_settings.show_path_in_browser == SHOW_PATH_CURRENT)
        {
            gui_synclist_set_title(&tree_lists, tagtree_get_title(&tc),
                filetype_get_icon(ATTR_DIRECTORY));
        }
        else
        {
            /* Must clear the title as the list is reused */
            gui_synclist_set_title(&tree_lists, NULL, NOICON);
        } 
#endif
    }
    else
#endif
    {
#ifdef HAVE_LCD_BITMAP
        if (tc.browse && tc.browse->title)
        {
            int icon = tc.browse->icon;
            if (icon == NOICON)
                icon = filetype_get_icon(ATTR_DIRECTORY);
            gui_synclist_set_title(&tree_lists, tc.browse->title, icon);
        }
        else if (global_settings.show_path_in_browser == SHOW_PATH_FULL)
        {
            gui_synclist_set_title(&tree_lists, tc.currdir,
                filetype_get_icon(ATTR_DIRECTORY));
        }
        else if (global_settings.show_path_in_browser == SHOW_PATH_CURRENT)
        {
            char *title = strrchr(tc.currdir, '/') + 1;
            if (*title == '\0')
            {
                /* Display "Files" for the root dir */
                gui_synclist_set_title(&tree_lists, str(LANG_DIR_BROWSER),
                    filetype_get_icon(ATTR_DIRECTORY));
            }
            else
                gui_synclist_set_title(&tree_lists, title,
                    filetype_get_icon(ATTR_DIRECTORY));
        }
        else
        {
            /* Must clear the title as the list is reused */
            gui_synclist_set_title(&tree_lists, NULL, NOICON);
        } 
#endif
    }
    
    gui_synclist_set_nb_items(&tree_lists, tc.filesindir);
    gui_synclist_set_icon_callback(&tree_lists,
                                   global_settings.show_icons?tree_get_fileicon:NULL);
    if( tc.selected_item >= tc.filesindir)
        tc.selected_item=tc.filesindir-1;

    gui_synclist_select_item(&tree_lists, tc.selected_item);
#ifdef HAVE_BUTTONBAR
    if (global_settings.buttonbar) {
        if (*tc.dirfilter < NUM_FILTER_MODES)
            gui_buttonbar_set(&tree_buttonbar, str(LANG_SYSFONT_DIRBROWSE_F1),
                          str(LANG_SYSFONT_DIRBROWSE_F2),
                          str(LANG_SYSFONT_DIRBROWSE_F3));
        else
            gui_buttonbar_set(&tree_buttonbar, "<<<", "", "");
        gui_buttonbar_draw(&tree_buttonbar);
    }
#endif
    gui_synclist_draw(&tree_lists);
    gui_synclist_speak_item(&tree_lists);
    return tc.filesindir;
}
/* Main viewer function.  Filename identifies playlist to be viewed.  If NULL,
   view current playlist. */
enum playlist_viewer_result playlist_viewer_ex(const char* filename)
{
    enum playlist_viewer_result ret = PLAYLIST_VIEWER_OK;
    bool exit = false;        /* exit viewer */
    int button;
    bool dirty = false;
    struct gui_synclist playlist_lists;
    if (!playlist_viewer_init(&viewer, filename, false))
        goto exit;

    push_current_activity(ACTIVITY_PLAYLISTVIEWER);
    gui_synclist_init(&playlist_lists, playlist_callback_name,
                      &viewer, false, 1, NULL);
    gui_synclist_set_voice_callback(&playlist_lists, playlist_callback_voice);
    gui_synclist_set_icon_callback(&playlist_lists,
                  global_settings.playlist_viewer_icons?
                  &playlist_callback_icons:NULL);
    gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);
    gui_synclist_set_title(&playlist_lists, str(LANG_PLAYLIST), Icon_Playlist);
    gui_synclist_select_item(&playlist_lists, viewer.selected_track);
    gui_synclist_draw(&playlist_lists);
    gui_synclist_speak_item(&playlist_lists);
    while (!exit)
    {
        int track;

        if (global_status.resume_index != -1 && !viewer.playlist)
            playlist_get_resume_info(&track);
        else
            track = -1;

        if (track != viewer.current_playing_track ||
            playlist_amount_ex(viewer.playlist) != viewer.num_tracks)
        {
            /* Playlist has changed (new track started?) */
            if (!update_playlist(false))
                goto exit;
            /*Needed because update_playlist gives wrong value when
                                                            playing is stopped*/
            viewer.current_playing_track = track;
            gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);

            gui_synclist_draw(&playlist_lists);
        }

        /* Timeout so we can determine if play status has changed */
        bool res = list_do_action(CONTEXT_TREE, HZ/2,
                            &playlist_lists, &button, LIST_WRAP_UNLESS_HELD);
        /* during moving, another redraw is going to be needed,
         * since viewer.selected_track is updated too late (after the first draw)
         * drawing the moving item needs it */
        viewer.selected_track=gui_synclist_get_sel_pos(&playlist_lists);
        if (res)
        {
            bool reload = playlist_buffer_needs_reload(&viewer.buffer,
                    viewer.selected_track);
            if (reload)
                playlist_buffer_load_entries_screen(&viewer.buffer,
                    button == ACTION_STD_NEXT ? FORWARD : BACKWARD);
            if (reload || viewer.moving_track >= 0)
                gui_synclist_draw(&playlist_lists);
        }
        switch (button)
        {
            case ACTION_TREE_WPS:
            case ACTION_STD_CANCEL:
            {
                if (viewer.moving_track >= 0)
                {
                    viewer.selected_track = viewer.moving_track;
                    gui_synclist_select_item(&playlist_lists, viewer.moving_track);
                    viewer.moving_track = -1;
                    viewer.moving_playlist_index = -1;
                    gui_synclist_draw(&playlist_lists);
                }
                else
                {
                    exit = true;
                    ret = PLAYLIST_VIEWER_CANCEL;
                }
                break;
            }
            case ACTION_STD_OK:
            {
                struct playlist_entry * current_track =
                            playlist_buffer_get_track(&viewer.buffer,
                                                      viewer.selected_track);

                if (viewer.moving_track >= 0)
                {
                    /* Move track */
                    int ret_val;

                    ret_val = playlist_move(viewer.playlist,
                                            viewer.moving_playlist_index,
                                            current_track->index);
                    if (ret_val < 0)
                         splashf(HZ, (unsigned char *)"%s %s", str(LANG_MOVE),
                                                               str(LANG_FAILED));
                    update_playlist(true);
                    viewer.moving_track = -1;
                    viewer.moving_playlist_index = -1;
                    dirty = true;
                }
                else if (!viewer.playlist)
                {
                    /* play new track */
                    if (!global_settings.party_mode)
                    {
                        playlist_start(current_track->index, 0);
                        update_playlist(false);
                    }
                }
                else if (!global_settings.party_mode)
                {
                    int start_index = current_track->index;
                    if (!warn_on_pl_erase())
                    {
                        gui_synclist_draw(&playlist_lists);
                        break;
                    }
                    /* New playlist */
                    if (playlist_set_current(viewer.playlist) < 0)
                        goto exit;
                    if (global_settings.playlist_shuffle)
                        start_index = playlist_shuffle(current_tick, start_index);
                    playlist_start(start_index, 0);

                    /* Our playlist is now the current list */
                    if (!playlist_viewer_init(&viewer, NULL, true))
                        goto exit;
                    exit = true;
                }
                gui_synclist_draw(&playlist_lists);

                break;
            }
            case ACTION_STD_CONTEXT:
            {
                /* ON+PLAY menu */
                int ret_val;

                ret_val = onplay_menu(viewer.selected_track);

                if (ret_val < 0)
                {
                    ret = PLAYLIST_VIEWER_USB;
                    goto exit;
                }
                else if (ret_val > 0)
                {
                    /* Playlist changed */
                    gui_synclist_del_item(&playlist_lists);
                    update_playlist(true);
                    if (viewer.num_tracks <= 0)
                        exit = true;
                    if (viewer.selected_track >= viewer.num_tracks)
                        viewer.selected_track = viewer.num_tracks-1;
                    dirty = true;
                }
                gui_synclist_draw(&playlist_lists);
                break;
            }
            case ACTION_STD_MENU:
                ret = PLAYLIST_VIEWER_MAINMENU;
                goto exit;
            default:
                if(default_event_handler(button) == SYS_USB_CONNECTED)
                {
                    ret = PLAYLIST_VIEWER_USB;
                    goto exit;
                }
                break;
        }
    }

exit:
    pop_current_activity();
    if (viewer.playlist)
    {
        if(dirty && yesno_pop(ID2P(LANG_SAVE_CHANGES)))
            save_playlist_screen(viewer.playlist);
        playlist_close(viewer.playlist);
    }
    return ret;
}