| /*************************************************************************** |
| * __________ __ ___. |
| * 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 "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; |
| } |
| } |