rockbox/apps/gui/bitmap/list-skinned.c
Aidan MacDonald 9ce5b2a2ed gui: Remove show/hide selection option in lists
The implementation of the "show_selection_marker" option in
lists isn't great. It's a cosmetic option used to hide the
selection, but it causes the list to do funny things to the
selected_item and doesn't play nice with voiced menus, since
these rely on the selection to determine what item is spoken.

There are only two user-facing lists that use the option, the
"Rockbox Info" screen and a menu in the superdom plugin. The
rest are debug screens, and cosmetics don't matter much there.

Given how little used the option is, and its issues, removing
it seems reasonable.

Change-Id: I2c70b3e4c74ff3cc6dbac46366a371d271dd2d58
2022-10-02 09:21:25 -04:00

288 lines
9.5 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2011 by Jonathan Gordon
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "system.h"
#include "lcd.h"
#include "font.h"
#include "button.h"
#include "string.h"
#include "settings.h"
#include "kernel.h"
#include "file.h"
#include "action.h"
#include "screen_access.h"
#include "list.h"
#include "scrollbar.h"
#include "lang.h"
#include "sound.h"
#include "misc.h"
#include "viewport.h"
#include "statusbar-skinned.h"
#include "skin_engine/skin_engine.h"
#include "skin_engine/skin_display.h"
#include "appevents.h"
static struct listitem_viewport_cfg *listcfg[NB_SCREENS] = {NULL};
static struct gui_synclist *current_list;
static int current_row;
static int current_column;
void skinlist_set_cfg(enum screen_type screen,
struct listitem_viewport_cfg *cfg)
{
if (listcfg[screen] != cfg)
{
if (listcfg[screen])
screens[screen].scroll_stop_viewport(&listcfg[screen]->selected_item_vp.vp);
listcfg[screen] = cfg;
current_list = NULL;
current_column = -1;
current_row = -1;
}
}
static bool skinlist_is_configured(enum screen_type screen,
struct gui_synclist *list)
{
return (listcfg[screen] != NULL) &&
(!list || (list && list->selected_size == 1));
}
static int current_drawing_line;
static int offset_to_item(int offset, bool wrap)
{
int item = current_drawing_line + offset;
if (!current_list || current_list->nb_items == 0)
return -1;
if (item < 0)
{
if (!wrap)
return -1;
else
item = (item + current_list->nb_items) % current_list->nb_items;
}
else if (item >= current_list->nb_items && !wrap)
return -1;
else
item = item % current_list->nb_items;
return item;
}
int skinlist_get_item_number()
{
return current_drawing_line;
}
int skinlist_get_item_row()
{
return current_row;
}
int skinlist_get_item_column()
{
return current_column;
}
const char* skinlist_get_item_text(int offset, bool wrap, char* buf, size_t buf_size)
{
int item = offset_to_item(offset, wrap);
if (item < 0 || !current_list)
return NULL;
const char* ret = current_list->callback_get_item_name(
item, current_list->data, buf, buf_size);
return P2STR((unsigned char*)ret);
}
enum themable_icons skinlist_get_item_icon(int offset, bool wrap)
{
int item = offset_to_item(offset, wrap);
if (item < 0 || !current_list || current_list->callback_get_item_icon == NULL)
return Icon_NOICON;
return current_list->callback_get_item_icon(item, current_list->data);
}
static bool is_selected = false;
bool skinlist_is_selected_item(void)
{
return is_selected;
}
int skinlist_get_line_count(enum screen_type screen, struct gui_synclist *list)
{
struct viewport *parent = (list->parent[screen]);
if (!skinlist_is_configured(screen, list))
return -1;
if (listcfg[screen]->tile == true)
{
int rows = (parent->height / listcfg[screen]->height);
int cols = (parent->width / listcfg[screen]->width);
return rows*cols;
}
else
return (parent->height / listcfg[screen]->height);
}
static int current_item;
static int current_nbitems;
static bool needs_scrollbar[NB_SCREENS];
bool skinlist_needs_scrollbar(enum screen_type screen)
{
return needs_scrollbar[screen];
}
void skinlist_get_scrollbar(int* nb_item, int* first_shown, int* last_shown)
{
if (!skinlist_is_configured(0, NULL))
{
*nb_item = 0;
*first_shown = 0;
*last_shown = 0;
}
else
{
*nb_item = current_item;
*first_shown = 0;
*last_shown = current_nbitems;
}
}
bool skinlist_get_item(struct screen *display, struct gui_synclist *list, int x, int y, int *item)
{
const int screen = display->screen_type;
if (!skinlist_is_configured(screen, list))
return false;
int row = y / listcfg[screen]->height;
int column = x / listcfg[screen]->width;
struct viewport *parent = (list->parent[screen]);
int cols = (parent->width / listcfg[screen]->width);
*item = row * cols+ column;
return true;
}
bool skinlist_draw(struct screen *display, struct gui_synclist *list)
{
int cur_line, display_lines;
const int screen = display->screen_type;
struct viewport *parent = (list->parent[screen]);
char* label = NULL;
const int list_start_item = list->start_item[screen];
struct gui_wps wps;
if (!skinlist_is_configured(screen, list))
return false;
current_list = list;
wps.display = display;
wps.data = listcfg[screen]->data;
display_lines = skinlist_get_line_count(screen, list);
label = (char *)SKINOFFSETTOPTR(get_skin_buffer(wps.data), listcfg[screen]->label);
if (!label)
return false;
display->set_viewport(parent);
display->clear_viewport();
current_item = list->selected_item;
current_nbitems = list->nb_items;
needs_scrollbar[screen] = list->nb_items > display_lines;
for (cur_line = 0; cur_line < display_lines; cur_line++)
{
struct skin_element* viewport;
struct skin_viewport* skin_viewport = NULL;
if (list_start_item+cur_line+1 > list->nb_items)
break;
current_drawing_line = list_start_item+cur_line;
is_selected = list_start_item+cur_line == list->selected_item;
for (viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), listcfg[screen]->data->tree);
viewport;
viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->next))
{
int original_x, original_y;
skin_viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->data);
char *viewport_label = NULL;
if (skin_viewport)
viewport_label = SKINOFFSETTOPTR(get_skin_buffer(wps.data), skin_viewport->label);
if (viewport->children == 0 || !viewport_label ||
(skin_viewport->label && strcmp(label, viewport_label))
)
continue;
if (is_selected)
{
memcpy(&listcfg[screen]->selected_item_vp, skin_viewport, sizeof(struct skin_viewport));
skin_viewport = &listcfg[screen]->selected_item_vp;
}
original_x = skin_viewport->vp.x;
original_y = skin_viewport->vp.y;
if (listcfg[screen]->tile)
{
int cols = (parent->width / listcfg[screen]->width);
current_column = (cur_line)%cols;
current_row = (cur_line)/cols;
skin_viewport->vp.x = parent->x + listcfg[screen]->width*current_column + original_x;
skin_viewport->vp.y = parent->y + listcfg[screen]->height*current_row + original_y;
}
else
{
current_column = 1;
current_row = cur_line;
skin_viewport->vp.x = parent->x + original_x;
skin_viewport->vp.y = parent->y + original_y +
(listcfg[screen]->height*cur_line);
}
display->set_viewport(&skin_viewport->vp);
/* Set images to not to be displayed */
struct skin_token_list *imglist = SKINOFFSETTOPTR(get_skin_buffer(wps.data), wps.data->images);
while (imglist)
{
struct wps_token *token = SKINOFFSETTOPTR(get_skin_buffer(wps.data), imglist->token);
struct gui_img *img = NULL;
if (token)
img = SKINOFFSETTOPTR(get_skin_buffer(wps.data), token->value.data);
if (img)
img->display = -1;
imglist = SKINOFFSETTOPTR(get_skin_buffer(wps.data), imglist->next);
}
struct skin_element** children = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->children);
if (children && *children)
skin_render_viewport(SKINOFFSETTOPTR(get_skin_buffer(wps.data), (intptr_t)children[0]),
&wps, skin_viewport, SKIN_REFRESH_ALL);
wps_display_images(&wps, &skin_viewport->vp);
/* force disableing scroll because it breaks later */
if (!is_selected)
{
display->scroll_stop_viewport(&skin_viewport->vp);
skin_viewport->vp.x = original_x;
skin_viewport->vp.y = original_y;
}
}
}
current_column = -1;
current_row = -1;
display->set_viewport(parent);
display->update_viewport();
current_drawing_line = list->selected_item;
return true;
}