rockbox/apps/gui/statusbar-skinned.c
Jonathan Gordon a398c2846a Touchregion support for the Base Skin and FM Skins. display obviously needs to be in stylus mode for this to work. Just about all screens should be mostly useable if your sbs has the next/prev/select/cancel/menu regions defined.
Plenty of room to add new action abilities if they are wanted.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27004 a1c6a512-1295-4272-9138-f99709370657
2010-06-21 06:04:19 +00:00

289 lines
8.7 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2009 Thomas Martitz
*
* 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 "action.h"
#include "system.h"
#include "settings.h"
#include "appevents.h"
#include "screens.h"
#include "screen_access.h"
#include "skin_engine/skin_engine.h"
#include "skin_engine/wps_internals.h"
#include "viewport.h"
#include "statusbar.h"
#include "statusbar-skinned.h"
#include "debug.h"
#include "font.h"
#include "icon.h"
/* currently only one wps_state is needed */
extern struct wps_state wps_state; /* from wps.c */
static struct gui_wps sb_skin[NB_SCREENS] = {{ .data = NULL }};
static struct wps_data sb_skin_data[NB_SCREENS] = {{ .wps_loaded = 0 }};
static struct wps_sync_data sb_skin_sync_data = { .do_full_update = false };
/* initial setup of wps_data */
static int update_delay = DEFAULT_UPDATE_DELAY;
bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen)
{
int i;
bool retval = false;
for(i=0; i<sb_skin_data[screen].num_tokens; i++)
{
if (sb_skin_data[screen].tokens[i].type == WPS_TOKEN_LIST_TITLE_TEXT)
{
sb_skin_data[screen].tokens[i].value.data = title;
retval = true;
}
else if (sb_skin_data[screen].tokens[i].type == WPS_TOKEN_LIST_TITLE_ICON)
{
/* Icon_NOICON == -1 which the skin engine wants at position 1, so + 2 */
sb_skin_data[screen].tokens[i].value.i = icon+2;
}
}
return retval;
}
void sb_skin_data_load(enum screen_type screen, const char *buf, bool isfile)
{
struct wps_data *data = sb_skin[screen].data;
int success;
success = buf && skin_data_load(screen, data, buf, isfile);
if (success)
{ /* hide the sb's default viewport because it has nasty effect with stuff
* not part of the statusbar,
* hence .sbs's without any other vps are unsupported*/
struct skin_viewport *vp = find_viewport(VP_DEFAULT_LABEL, data);
struct skin_token_list *next_vp = data->viewports->next;
if (!next_vp)
{ /* no second viewport, let parsing fail */
success = false;
}
/* hide this viewport, forever */
vp->hidden_flags = VP_NEVER_VISIBLE;
sb_set_info_vp(screen, VP_INFO_LABEL|VP_DEFAULT_LABEL);
}
if (!success && isfile)
sb_create_from_settings(screen);
}
static char infovp_label[NB_SCREENS];
static char oldinfovp_label[NB_SCREENS];
void sb_set_info_vp(enum screen_type screen, char label)
{
infovp_label[screen] = label;
}
struct viewport *sb_skin_get_info_vp(enum screen_type screen)
{
if (oldinfovp_label[screen] != infovp_label[screen])
{
/* UI viewport changed, so force a redraw */
oldinfovp_label[screen] = infovp_label[screen];
viewportmanager_theme_enable(screen, false, NULL);
viewportmanager_theme_undo(screen, true);
}
return &find_viewport(infovp_label[screen], sb_skin[screen].data)->vp;
}
#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
char* sb_get_backdrop(enum screen_type screen)
{
return sb_skin[screen].data->backdrop;
}
bool sb_set_backdrop(enum screen_type screen, char* filename)
{
if (!filename)
{
sb_skin[screen].data->backdrop = NULL;
return true;
}
else if (!sb_skin[screen].data->backdrop)
{
/* need to make room on the buffer */
size_t buf_size;
#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
if (screen == SCREEN_REMOTE)
buf_size = REMOTE_LCD_BACKDROP_BYTES;
else
#endif
buf_size = LCD_BACKDROP_BYTES;
sb_skin[screen].data->backdrop = skin_buffer_alloc(buf_size);
if (!sb_skin[screen].data->backdrop)
return false;
}
if (!screens[screen].backdrop_load(filename, sb_skin[screen].data->backdrop))
sb_skin[screen].data->backdrop = NULL;
return sb_skin[screen].data->backdrop != NULL;
}
#endif
void sb_skin_update(enum screen_type screen, bool force)
{
static long next_update[NB_SCREENS] = {0};
int i = screen;
if (TIME_AFTER(current_tick, next_update[i]) || force)
{
#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
/* currently, all remotes are readable without backlight
* so still update those */
if (lcd_active() || (i != SCREEN_MAIN))
#endif
skin_update(&sb_skin[i], force?
WPS_REFRESH_ALL : WPS_REFRESH_NON_STATIC);
next_update[i] = current_tick + update_delay; /* don't update too often */
sb_skin[SCREEN_MAIN].sync_data->do_full_update = false;
}
}
void do_sbs_update_callback(void *param)
{
(void)param;
/* the WPS handles changing the actual id3 data in the id3 pointers
* we imported, we just want a full update */
sb_skin_sync_data.do_full_update = true;
/* force timeout in wps main loop, so that the update is instantly */
queue_post(&button_queue, BUTTON_NONE, 0);
}
void sb_skin_set_update_delay(int delay)
{
update_delay = delay;
}
/* This creates and loads a ".sbs" based on the user settings for:
* - regular statusbar
* - colours
* - ui viewport
* - backdrop
*/
void sb_create_from_settings(enum screen_type screen)
{
char buf[128], *ptr, *ptr2;
int len, remaining = sizeof(buf);
int bar_position = statusbar_position(screen);
ptr = buf;
ptr[0] = '\0';
/* setup the inbuilt statusbar */
if (bar_position != STATUSBAR_OFF)
{
int y = 0, height = STATUSBAR_HEIGHT;
if (bar_position == STATUSBAR_BOTTOM)
{
y = screens[screen].lcdheight - STATUSBAR_HEIGHT;
}
len = snprintf(ptr, remaining, "%%V(0,%d,-,%d,0)\n%%wi\n",
y, height);
remaining -= len;
ptr += len;
}
/* %Vi viewport, colours handled by the parser */
#if NB_SCREENS > 1
if (screen == SCREEN_REMOTE)
ptr2 = global_settings.remote_ui_vp_config;
else
#endif
ptr2 = global_settings.ui_vp_config;
if (ptr2[0] && ptr2[0] != '-') /* from ui viewport setting */
{
len = snprintf(ptr, remaining, "%%ax%%Vi(-,%s)\n", ptr2);
}
else
{
int y = 0, height;
switch (bar_position)
{
case STATUSBAR_TOP:
y = STATUSBAR_HEIGHT;
case STATUSBAR_BOTTOM:
height = screens[screen].lcdheight - STATUSBAR_HEIGHT;
break;
default:
height = screens[screen].lcdheight;
}
len = snprintf(ptr, remaining, "%%ax%%Vi(-,0,%d,-,%d,1)\n",
y, height);
}
sb_skin_data_load(screen, buf, false);
}
void sb_skin_init(void)
{
int i;
FOR_NB_SCREENS(i)
{
#ifdef HAVE_ALBUMART
sb_skin_data[i].albumart = NULL;
sb_skin_data[i].playback_aa_slot = -1;
#endif
sb_skin[i].data = &sb_skin_data[i];
sb_skin[i].display = &screens[i];
/* Currently no seperate wps_state needed/possible
so use the only available ( "global" ) one */
sb_skin[i].state = &wps_state;
sb_skin[i].sync_data = &sb_skin_sync_data;
}
}
#ifdef HAVE_TOUCHSCREEN
static bool bypass_sb_touchregions = true;
void sb_bypass_touchregions(bool enable)
{
bypass_sb_touchregions = enable;
}
int sb_touch_to_button(int context)
{
static int last_context = -1;
int button, offset;
if (bypass_sb_touchregions)
return ACTION_TOUCHSCREEN;
if (last_context != context)
skin_disarm_touchregions(&sb_skin_data[SCREEN_MAIN]);
last_context = context;
button = skin_get_touchaction(&sb_skin_data[SCREEN_MAIN], &offset);
switch (button)
{
#ifdef HAVE_VOLUME_IN_LIST
case ACTION_WPS_VOLUP:
return ACTION_LIST_VOLUP;
case ACTION_WPS_VOLDOWN:
return ACTION_LIST_VOLDOWN;
#endif
/* TODO */
}
return button;
}
#endif