Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id: skin_parser.c 26752 2010-06-10 21:22:16Z bieber $ |
| 9 | * |
| 10 | * Copyright (C) 2010 Jonathan Gordon |
| 11 | * |
| 12 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License |
| 14 | * as published by the Free Software Foundation; either version 2 |
| 15 | * of the License, or (at your option) any later version. |
| 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
| 21 | |
| 22 | #include <stdlib.h> |
| 23 | #include <stdio.h> |
| 24 | #include <string.h> |
| 25 | #include <stdbool.h> |
| 26 | #include <ctype.h> |
| 27 | #include "strlcat.h" |
| 28 | |
| 29 | #include "config.h" |
| 30 | #include "kernel.h" |
| 31 | #ifdef HAVE_ALBUMART |
| 32 | #include "albumart.h" |
| 33 | #endif |
| 34 | #include "skin_display.h" |
| 35 | #include "skin_engine.h" |
| 36 | #include "skin_parser.h" |
| 37 | #include "tag_table.h" |
| 38 | #include "skin_scan.h" |
| 39 | #if CONFIG_TUNER |
| 40 | #include "radio.h" |
| 41 | #endif |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 42 | #include "viewport.h" |
| 43 | #include "cuesheet.h" |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 44 | #include "language.h" |
| 45 | #include "playback.h" |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 46 | #include "playlist.h" |
Jonathan Gordon | b9093f2 | 2010-08-14 15:23:07 +0000 | [diff] [blame] | 47 | #include "root_menu.h" |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 48 | #include "misc.h" |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 49 | |
| 50 | |
| 51 | #define MAX_LINE 1024 |
| 52 | |
| 53 | struct skin_draw_info { |
| 54 | struct gui_wps *gwps; |
| 55 | struct skin_viewport *skin_vp; |
| 56 | int line_number; |
| 57 | unsigned long refresh_type; |
Jonathan Gordon | 281f1a1 | 2011-08-14 13:50:07 +0000 | [diff] [blame] | 58 | unsigned text_style; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 59 | |
| 60 | char* cur_align_start; |
| 61 | struct align_pos align; |
| 62 | bool no_line_break; |
| 63 | bool line_scrolls; |
| 64 | bool force_redraw; |
| 65 | |
| 66 | char *buf; |
| 67 | size_t buf_size; |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 68 | |
| 69 | int offset; /* used by the playlist viewer */ |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 70 | }; |
| 71 | |
| 72 | typedef bool (*skin_render_func)(struct skin_element* alternator, struct skin_draw_info *info); |
| 73 | bool skin_render_alternator(struct skin_element* alternator, struct skin_draw_info *info); |
| 74 | |
Jonathan Gordon | d23d7a1 | 2010-08-14 15:27:46 +0000 | [diff] [blame] | 75 | #ifdef HAVE_LCD_BITMAP |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 76 | static void skin_render_playlistviewer(struct playlistviewer* viewer, |
| 77 | struct gui_wps *gwps, |
| 78 | struct skin_viewport* skin_viewport, |
| 79 | unsigned long refresh_type); |
Jonathan Gordon | d23d7a1 | 2010-08-14 15:27:46 +0000 | [diff] [blame] | 80 | #endif |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 81 | |
Frank Gevaerts | d0bf13b | 2010-10-10 13:21:49 +0000 | [diff] [blame] | 82 | static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info, |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 83 | struct skin_element *element, struct viewport* vp) |
| 84 | { |
| 85 | #ifndef HAVE_LCD_BITMAP |
| 86 | (void)vp; /* silence warnings */ |
Frank Gevaerts | 1f0ab7c | 2010-10-10 23:46:15 +0000 | [diff] [blame] | 87 | (void)info; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 88 | #endif |
| 89 | struct wps_token *token = (struct wps_token *)element->data; |
Frank Gevaerts | 1f0ab7c | 2010-10-10 23:46:15 +0000 | [diff] [blame] | 90 | |
| 91 | #ifdef HAVE_LCD_BITMAP |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 92 | struct wps_data *data = gwps->data; |
| 93 | bool do_refresh = (element->tag->flags & info->refresh_type) > 0; |
Frank Gevaerts | 1f0ab7c | 2010-10-10 23:46:15 +0000 | [diff] [blame] | 94 | #endif |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 95 | switch (token->type) |
| 96 | { |
| 97 | #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) |
| 98 | case SKIN_TOKEN_VIEWPORT_FGCOLOUR: |
| 99 | { |
| 100 | struct viewport_colour *col = token->value.data; |
| 101 | col->vp->fg_pattern = col->colour; |
| 102 | } |
| 103 | break; |
| 104 | case SKIN_TOKEN_VIEWPORT_BGCOLOUR: |
| 105 | { |
| 106 | struct viewport_colour *col = token->value.data; |
| 107 | col->vp->bg_pattern = col->colour; |
| 108 | } |
| 109 | break; |
Jonathan Gordon | 281f1a1 | 2011-08-14 13:50:07 +0000 | [diff] [blame] | 110 | case SKIN_TOKEN_VIEWPORT_TEXTSTYLE: |
| 111 | info->text_style = token->value.l; |
| 112 | break; |
| 113 | #endif |
| 114 | #ifdef HAVE_LCD_COLOR |
| 115 | case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP: |
| 116 | { |
| 117 | struct gradient_config *cfg = token->value.data; |
| 118 | vp->lss_pattern = cfg->start; |
| 119 | vp->lse_pattern = cfg->end; |
| 120 | vp->lst_pattern = cfg->text; |
| 121 | } |
| 122 | break; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 123 | #endif |
| 124 | case SKIN_TOKEN_VIEWPORT_ENABLE: |
| 125 | { |
Jonathan Gordon | ee4f8a9 | 2010-08-02 12:50:23 +0000 | [diff] [blame] | 126 | char *label = token->value.data; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 127 | char temp = VP_DRAW_HIDEABLE; |
| 128 | struct skin_element *viewport = gwps->data->tree; |
| 129 | while (viewport) |
| 130 | { |
| 131 | struct skin_viewport *skinvp = (struct skin_viewport*)viewport->data; |
Jonathan Gordon | ee4f8a9 | 2010-08-02 12:50:23 +0000 | [diff] [blame] | 132 | if (skinvp->label && !skinvp->is_infovp && |
| 133 | !strcmp(skinvp->label, label)) |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 134 | { |
| 135 | if (skinvp->hidden_flags&VP_DRAW_HIDDEN) |
| 136 | { |
| 137 | temp |= VP_DRAW_WASHIDDEN; |
| 138 | } |
| 139 | skinvp->hidden_flags = temp; |
| 140 | } |
| 141 | viewport = viewport->next; |
| 142 | } |
| 143 | } |
| 144 | break; |
| 145 | #ifdef HAVE_LCD_BITMAP |
| 146 | case SKIN_TOKEN_UIVIEWPORT_ENABLE: |
| 147 | sb_set_info_vp(gwps->display->screen_type, |
Jonathan Gordon | ee4f8a9 | 2010-08-02 12:50:23 +0000 | [diff] [blame] | 148 | token->value.data); |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 149 | break; |
| 150 | case SKIN_TOKEN_PEAKMETER: |
| 151 | data->peak_meter_enabled = true; |
| 152 | if (do_refresh) |
| 153 | draw_peakmeters(gwps, info->line_number, vp); |
| 154 | break; |
| 155 | #endif |
Jonathan Gordon | 261c56b | 2011-01-13 06:48:39 +0000 | [diff] [blame] | 156 | #ifdef HAVE_LCD_BITMAP |
| 157 | case SKIN_TOKEN_PEAKMETER_LEFTBAR: |
| 158 | case SKIN_TOKEN_PEAKMETER_RIGHTBAR: |
| 159 | data->peak_meter_enabled = true; |
| 160 | /* fall through to the progressbar code */ |
| 161 | #endif |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 162 | case SKIN_TOKEN_VOLUMEBAR: |
| 163 | case SKIN_TOKEN_BATTERY_PERCENTBAR: |
Frank Gevaerts | 1f0ab7c | 2010-10-10 23:46:15 +0000 | [diff] [blame] | 164 | #ifdef HAVE_LCD_BITMAP |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 165 | case SKIN_TOKEN_PROGRESSBAR: |
Jonathan Gordon | 1ce7ba4 | 2010-11-18 11:47:42 +0000 | [diff] [blame] | 166 | case SKIN_TOKEN_TUNER_RSSI_BAR: |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 167 | { |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 168 | struct progressbar *bar = (struct progressbar*)token->value.data; |
| 169 | if (do_refresh) |
| 170 | draw_progressbar(gwps, info->line_number, bar); |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 171 | } |
Frank Gevaerts | 1f0ab7c | 2010-10-10 23:46:15 +0000 | [diff] [blame] | 172 | #endif |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 173 | break; |
| 174 | #ifdef HAVE_LCD_BITMAP |
Jonathan Gordon | 70ebe46 | 2010-08-12 13:27:10 +0000 | [diff] [blame] | 175 | case SKIN_TOKEN_IMAGE_DISPLAY_LISTICON: |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 176 | case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY: |
| 177 | { |
Jonathan Gordon | 3f8e7fc | 2010-08-05 11:28:48 +0000 | [diff] [blame] | 178 | struct image_display *id = token->value.data; |
Jonathan Gordon | ff8d43d | 2010-08-14 11:40:20 +0000 | [diff] [blame] | 179 | const char* label = id->label; |
Jonathan Gordon | 343001b | 2011-03-07 12:45:45 +0000 | [diff] [blame] | 180 | struct gui_img *img = skin_find_item(label,SKIN_FIND_IMAGE, data); |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 181 | if (img && img->loaded) |
Jonathan Gordon | 3f8e7fc | 2010-08-05 11:28:48 +0000 | [diff] [blame] | 182 | { |
| 183 | if (id->token == NULL) |
| 184 | { |
| 185 | img->display = id->subimage; |
| 186 | } |
| 187 | else |
| 188 | { |
| 189 | char buf[16]; |
| 190 | const char *out; |
Magnus Holmgren | 6d7900e | 2010-08-12 10:01:46 +0000 | [diff] [blame] | 191 | int a = img->num_subimages; |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 192 | out = get_token_value(gwps, id->token, info->offset, |
| 193 | buf, sizeof(buf), &a); |
Magnus Holmgren | 6d7900e | 2010-08-12 10:01:46 +0000 | [diff] [blame] | 194 | |
Jonathan Gordon | 3f8e7fc | 2010-08-05 11:28:48 +0000 | [diff] [blame] | 195 | /* NOTE: get_token_value() returns values starting at 1! */ |
| 196 | if (a == -1) |
| 197 | a = (out && *out) ? 1 : 2; |
Jonathan Gordon | 70ebe46 | 2010-08-12 13:27:10 +0000 | [diff] [blame] | 198 | if (token->type == SKIN_TOKEN_IMAGE_DISPLAY_LISTICON) |
| 199 | a -= 2; /* 2 is added in statusbar-skinned.c! */ |
| 200 | else |
| 201 | a--; |
Jonathan Gordon | 3f8e7fc | 2010-08-05 11:28:48 +0000 | [diff] [blame] | 202 | a += id->offset; |
Magnus Holmgren | 6d7900e | 2010-08-12 10:01:46 +0000 | [diff] [blame] | 203 | |
| 204 | /* Clear the image, as in conditionals */ |
| 205 | clear_image_pos(gwps, img); |
| 206 | |
Jonathan Gordon | 3f8e7fc | 2010-08-05 11:28:48 +0000 | [diff] [blame] | 207 | /* If the token returned a value which is higher than |
Magnus Holmgren | 6d7900e | 2010-08-12 10:01:46 +0000 | [diff] [blame] | 208 | * the amount of subimages, don't draw it. */ |
| 209 | if (a >= 0 && a < img->num_subimages) |
Jonathan Gordon | 3f8e7fc | 2010-08-05 11:28:48 +0000 | [diff] [blame] | 210 | { |
Jonathan Gordon | 3f8e7fc | 2010-08-05 11:28:48 +0000 | [diff] [blame] | 211 | img->display = a; |
Magnus Holmgren | 6d7900e | 2010-08-12 10:01:46 +0000 | [diff] [blame] | 212 | } |
Jonathan Gordon | 3f8e7fc | 2010-08-05 11:28:48 +0000 | [diff] [blame] | 213 | } |
| 214 | } |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 215 | break; |
| 216 | } |
| 217 | #ifdef HAVE_ALBUMART |
| 218 | case SKIN_TOKEN_ALBUMART_DISPLAY: |
| 219 | /* now draw the AA */ |
Jonathan Gordon | f3a6d24 | 2010-08-05 12:45:46 +0000 | [diff] [blame] | 220 | if (do_refresh && data->albumart) |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 221 | { |
| 222 | int handle = playback_current_aa_hid(data->playback_aa_slot); |
| 223 | #if CONFIG_TUNER |
| 224 | if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF)) |
| 225 | { |
| 226 | struct dim dim = {data->albumart->width, data->albumart->height}; |
| 227 | handle = radio_get_art_hid(&dim); |
| 228 | } |
| 229 | #endif |
| 230 | data->albumart->draw_handle = handle; |
| 231 | } |
| 232 | break; |
| 233 | #endif |
| 234 | case SKIN_TOKEN_DRAW_INBUILTBAR: |
| 235 | gui_statusbar_draw(&(statusbars.statusbars[gwps->display->screen_type]), |
| 236 | info->refresh_type == SKIN_REFRESH_ALL, |
| 237 | token->value.data); |
| 238 | break; |
| 239 | case SKIN_TOKEN_VIEWPORT_CUSTOMLIST: |
| 240 | if (do_refresh) |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 241 | skin_render_playlistviewer(token->value.data, gwps, |
| 242 | info->skin_vp, info->refresh_type); |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 243 | break; |
| 244 | |
| 245 | #endif /* HAVE_LCD_BITMAP */ |
Jonathan Gordon | 87aa86c | 2011-03-27 08:01:58 +0000 | [diff] [blame] | 246 | #ifdef HAVE_SKIN_VARIABLES |
| 247 | case SKIN_TOKEN_VAR_SET: |
| 248 | if (do_refresh) |
| 249 | { |
| 250 | struct skin_var_changer *data = token->value.data; |
| 251 | if (data->direct) |
| 252 | data->var->value = data->newval; |
| 253 | else |
| 254 | { |
| 255 | data->var->value += data->newval; |
| 256 | if (data->max) |
| 257 | { |
| 258 | if (data->var->value > data->max) |
| 259 | data->var->value = 1; |
| 260 | else if (data->var->value < 1) |
| 261 | data->var->value = data->max; |
| 262 | } |
| 263 | } |
| 264 | if (data->var->value < 1) |
| 265 | data->var->value = 1; |
| 266 | data->var->last_changed = current_tick; |
| 267 | } |
| 268 | break; |
| 269 | #endif |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 270 | default: |
| 271 | return false; |
| 272 | } |
| 273 | return true; |
| 274 | } |
| 275 | |
| 276 | |
| 277 | |
Frank Gevaerts | d0bf13b | 2010-10-10 13:21:49 +0000 | [diff] [blame] | 278 | static void do_tags_in_hidden_conditional(struct skin_element* branch, |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 279 | struct skin_draw_info *info) |
| 280 | { |
| 281 | #ifdef HAVE_LCD_BITMAP |
| 282 | struct gui_wps *gwps = info->gwps; |
| 283 | struct wps_data *data = gwps->data; |
| 284 | #endif |
| 285 | /* Tags here are ones which need to be "turned off" or cleared |
| 286 | * if they are in a conditional branch which isnt being used */ |
| 287 | if (branch->type == LINE_ALTERNATOR) |
| 288 | { |
| 289 | int i; |
| 290 | for (i=0; i<branch->children_count; i++) |
| 291 | { |
| 292 | do_tags_in_hidden_conditional(branch->children[i], info); |
| 293 | } |
| 294 | } |
| 295 | else if (branch->type == LINE && branch->children_count) |
| 296 | { |
| 297 | struct skin_element *child = branch->children[0]; |
| 298 | struct wps_token *token; |
| 299 | while (child) |
| 300 | { |
| 301 | if (child->type == CONDITIONAL) |
| 302 | { |
| 303 | int i; |
| 304 | for (i=0; i<child->children_count; i++) |
| 305 | { |
| 306 | do_tags_in_hidden_conditional(child->children[i], info); |
| 307 | } |
| 308 | child = child->next; |
| 309 | continue; |
| 310 | } |
| 311 | else if (child->type != TAG || !child->data) |
| 312 | { |
| 313 | child = child->next; |
| 314 | continue; |
| 315 | } |
| 316 | token = (struct wps_token *)child->data; |
| 317 | #ifdef HAVE_LCD_BITMAP |
| 318 | /* clear all pictures in the conditional and nested ones */ |
| 319 | if (token->type == SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY) |
| 320 | { |
Jonathan Gordon | 3f8e7fc | 2010-08-05 11:28:48 +0000 | [diff] [blame] | 321 | struct image_display *id = token->value.data; |
Jonathan Gordon | 343001b | 2011-03-07 12:45:45 +0000 | [diff] [blame] | 322 | struct gui_img *img = skin_find_item(id->label, |
| 323 | SKIN_FIND_IMAGE, data); |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 324 | clear_image_pos(gwps, img); |
| 325 | } |
| 326 | else if (token->type == SKIN_TOKEN_PEAKMETER) |
| 327 | { |
| 328 | data->peak_meter_enabled = false; |
| 329 | } |
| 330 | else if (token->type == SKIN_TOKEN_VIEWPORT_ENABLE) |
| 331 | { |
Jonathan Gordon | ee4f8a9 | 2010-08-02 12:50:23 +0000 | [diff] [blame] | 332 | char *label = token->value.data; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 333 | struct skin_element *viewport; |
| 334 | for (viewport = data->tree; |
| 335 | viewport; |
| 336 | viewport = viewport->next) |
| 337 | { |
| 338 | struct skin_viewport *skin_viewport = (struct skin_viewport*)viewport->data; |
Jonathan Gordon | ee4f8a9 | 2010-08-02 12:50:23 +0000 | [diff] [blame] | 339 | if (skin_viewport->label && strcmp(skin_viewport->label, label)) |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 340 | continue; |
| 341 | if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE) |
| 342 | { |
| 343 | continue; |
| 344 | } |
| 345 | if (skin_viewport->hidden_flags&VP_DRAW_HIDEABLE) |
| 346 | { |
| 347 | if (skin_viewport->hidden_flags&VP_DRAW_HIDDEN) |
| 348 | skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN; |
| 349 | else |
| 350 | { |
| 351 | gwps->display->set_viewport(&skin_viewport->vp); |
| 352 | gwps->display->clear_viewport(); |
| 353 | gwps->display->scroll_stop(&skin_viewport->vp); |
| 354 | gwps->display->set_viewport(&info->skin_vp->vp); |
| 355 | skin_viewport->hidden_flags |= VP_DRAW_HIDDEN; |
| 356 | } |
| 357 | } |
| 358 | } |
| 359 | } |
| 360 | #endif |
| 361 | #ifdef HAVE_ALBUMART |
| 362 | else if (data->albumart && token->type == SKIN_TOKEN_ALBUMART_DISPLAY) |
| 363 | { |
| 364 | draw_album_art(gwps, |
| 365 | playback_current_aa_hid(data->playback_aa_slot), true); |
| 366 | } |
| 367 | #endif |
| 368 | child = child->next; |
| 369 | } |
| 370 | } |
| 371 | } |
| 372 | |
Frank Gevaerts | d0bf13b | 2010-10-10 13:21:49 +0000 | [diff] [blame] | 373 | static void fix_line_alignment(struct skin_draw_info *info, struct skin_element *element) |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 374 | { |
| 375 | struct align_pos *align = &info->align; |
| 376 | char *cur_pos = info->cur_align_start + strlen(info->cur_align_start); |
| 377 | switch (element->tag->type) |
| 378 | { |
| 379 | case SKIN_TOKEN_ALIGN_LEFT: |
| 380 | *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; |
| 381 | align->left = cur_pos; |
| 382 | info->cur_align_start = cur_pos; |
| 383 | break; |
| 384 | case SKIN_TOKEN_ALIGN_LEFT_RTL: |
| 385 | *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; |
| 386 | if (lang_is_rtl()) |
| 387 | align->right = cur_pos; |
| 388 | else |
| 389 | align->left = cur_pos; |
| 390 | info->cur_align_start = cur_pos; |
| 391 | break; |
| 392 | case SKIN_TOKEN_ALIGN_CENTER: |
| 393 | *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; |
| 394 | align->center = cur_pos; |
| 395 | info->cur_align_start = cur_pos; |
| 396 | break; |
| 397 | case SKIN_TOKEN_ALIGN_RIGHT: |
| 398 | *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; |
| 399 | align->right = cur_pos; |
| 400 | info->cur_align_start = cur_pos; |
| 401 | break; |
| 402 | case SKIN_TOKEN_ALIGN_RIGHT_RTL: |
| 403 | *cur_pos = '\0'; cur_pos++; *cur_pos = '\0'; |
| 404 | if (lang_is_rtl()) |
| 405 | align->left = cur_pos; |
| 406 | else |
| 407 | align->right = cur_pos; |
| 408 | info->cur_align_start = cur_pos; |
| 409 | break; |
| 410 | default: |
| 411 | break; |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | /* Draw a LINE element onto the display */ |
Frank Gevaerts | d0bf13b | 2010-10-10 13:21:49 +0000 | [diff] [blame] | 416 | static bool skin_render_line(struct skin_element* line, struct skin_draw_info *info) |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 417 | { |
| 418 | bool needs_update = false; |
| 419 | int last_value, value; |
| 420 | |
| 421 | if (line->children_count == 0) |
| 422 | return false; /* empty line, do nothing */ |
| 423 | |
| 424 | struct skin_element *child = line->children[0]; |
| 425 | struct conditional *conditional; |
| 426 | skin_render_func func = skin_render_line; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 427 | int old_refresh_mode = info->refresh_type; |
| 428 | while (child) |
| 429 | { |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 430 | switch (child->type) |
| 431 | { |
| 432 | case CONDITIONAL: |
| 433 | conditional = (struct conditional*)child->data; |
| 434 | last_value = conditional->last_value; |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 435 | value = evaluate_conditional(info->gwps, info->offset, |
| 436 | conditional, child->children_count); |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 437 | conditional->last_value = value; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 438 | if (child->children_count == 1) |
| 439 | { |
| 440 | /* special handling so |
| 441 | * %?aa<true> and %?<true|false> need special handlng here */ |
| 442 | |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 443 | if (value == -1) /* tag is false */ |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 444 | { |
| 445 | /* we are in a false branch of a %?aa<true> conditional */ |
| 446 | if (last_value == 0) |
| 447 | do_tags_in_hidden_conditional(child->children[0], info); |
| 448 | break; |
| 449 | } |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 450 | } |
| 451 | else |
| 452 | { |
| 453 | if (last_value >= 0 && value != last_value && last_value < child->children_count) |
| 454 | do_tags_in_hidden_conditional(child->children[last_value], info); |
| 455 | } |
| 456 | if (child->children[value]->type == LINE_ALTERNATOR) |
| 457 | { |
| 458 | func = skin_render_alternator; |
| 459 | } |
| 460 | else if (child->children[value]->type == LINE) |
| 461 | func = skin_render_line; |
| 462 | |
| 463 | if (value != last_value) |
| 464 | { |
| 465 | info->refresh_type = SKIN_REFRESH_ALL; |
| 466 | info->force_redraw = true; |
| 467 | } |
| 468 | |
| 469 | if (func(child->children[value], info)) |
| 470 | needs_update = true; |
| 471 | else |
| 472 | needs_update = needs_update || (last_value != value); |
| 473 | |
| 474 | info->refresh_type = old_refresh_mode; |
| 475 | break; |
| 476 | case TAG: |
| 477 | if (child->tag->flags & NOBREAK) |
| 478 | info->no_line_break = true; |
| 479 | if (child->tag->type == SKIN_TOKEN_SUBLINE_SCROLL) |
| 480 | info->line_scrolls = true; |
| 481 | |
| 482 | fix_line_alignment(info, child); |
| 483 | |
| 484 | if (!child->data) |
| 485 | { |
| 486 | break; |
| 487 | } |
| 488 | if (!do_non_text_tags(info->gwps, info, child, &info->skin_vp->vp)) |
| 489 | { |
Jonathan Gordon | 562437b | 2010-09-26 06:43:33 +0000 | [diff] [blame] | 490 | static char tempbuf[128]; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 491 | const char *value = get_token_value(info->gwps, child->data, |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 492 | info->offset, tempbuf, |
| 493 | sizeof(tempbuf), NULL); |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 494 | if (value) |
| 495 | { |
Jonathan Gordon | e8bbbdf | 2010-08-15 14:35:34 +0000 | [diff] [blame] | 496 | #if CONFIG_RTC |
| 497 | if (child->tag->flags&SKIN_RTC_REFRESH) |
| 498 | needs_update = needs_update || info->refresh_type&SKIN_REFRESH_DYNAMIC; |
| 499 | #endif |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 500 | needs_update = needs_update || |
| 501 | ((child->tag->flags&info->refresh_type)!=0); |
| 502 | strlcat(info->cur_align_start, value, |
| 503 | info->buf_size - (info->cur_align_start-info->buf)); |
| 504 | } |
| 505 | } |
| 506 | break; |
| 507 | case TEXT: |
| 508 | strlcat(info->cur_align_start, child->data, |
| 509 | info->buf_size - (info->cur_align_start-info->buf)); |
| 510 | needs_update = needs_update || |
| 511 | (info->refresh_type&SKIN_REFRESH_STATIC) != 0; |
| 512 | break; |
| 513 | case COMMENT: |
| 514 | default: |
| 515 | break; |
| 516 | } |
| 517 | |
| 518 | child = child->next; |
| 519 | } |
| 520 | return needs_update; |
| 521 | } |
| 522 | |
Frank Gevaerts | d0bf13b | 2010-10-10 13:21:49 +0000 | [diff] [blame] | 523 | static int get_subline_timeout(struct gui_wps *gwps, struct skin_element* line) |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 524 | { |
| 525 | struct skin_element *element=line; |
| 526 | struct wps_token *token; |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 527 | int retval = DEFAULT_SUBLINE_TIME_MULTIPLIER*TIMEOUT_UNIT; |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 528 | if (element->type == LINE) |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 529 | { |
| 530 | if (element->children_count == 0) |
| 531 | return retval; /* empty line, so force redraw */ |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 532 | element = element->children[0]; |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 533 | } |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 534 | while (element) |
| 535 | { |
| 536 | if (element->type == TAG && |
| 537 | element->tag->type == SKIN_TOKEN_SUBLINE_TIMEOUT ) |
| 538 | { |
| 539 | token = element->data; |
| 540 | return token->value.i; |
| 541 | } |
| 542 | else if (element->type == CONDITIONAL) |
| 543 | { |
| 544 | struct conditional *conditional = element->data; |
| 545 | int val = evaluate_conditional(gwps, 0, conditional, |
| 546 | element->children_count); |
| 547 | if (val >= 0) |
| 548 | { |
| 549 | retval = get_subline_timeout(gwps, element->children[val]); |
| 550 | if (retval >= 0) |
| 551 | return retval; |
| 552 | } |
| 553 | } |
| 554 | element = element->next; |
| 555 | } |
| 556 | return retval; |
| 557 | } |
| 558 | |
Frank Gevaerts | d0bf13b | 2010-10-10 13:21:49 +0000 | [diff] [blame] | 559 | bool skin_render_alternator(struct skin_element* element, struct skin_draw_info *info) |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 560 | { |
| 561 | bool changed_lines = false; |
| 562 | struct line_alternator *alternator = (struct line_alternator*)element->data; |
| 563 | unsigned old_refresh = info->refresh_type; |
| 564 | if (info->refresh_type == SKIN_REFRESH_ALL) |
| 565 | { |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 566 | alternator->current_line = element->children_count-1; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 567 | changed_lines = true; |
| 568 | } |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 569 | else if (TIME_AFTER(current_tick, alternator->next_change_tick)) |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 570 | { |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 571 | changed_lines = true; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 572 | } |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 573 | |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 574 | if (changed_lines) |
| 575 | { |
Nils Wallménius | 3b04a85 | 2011-06-12 22:17:45 +0000 | [diff] [blame] | 576 | struct skin_element *current_line; |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 577 | int start = alternator->current_line; |
| 578 | int try_line = start; |
| 579 | bool suitable = false; |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 580 | int rettimeout = DEFAULT_SUBLINE_TIME_MULTIPLIER*TIMEOUT_UNIT; |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 581 | |
| 582 | /* find a subline which has at least one token in it, |
| 583 | * and that line doesnt have a timeout set to 0 through conditionals */ |
| 584 | do { |
| 585 | try_line++; |
| 586 | if (try_line >= element->children_count) |
| 587 | try_line = 0; |
| 588 | if (element->children[try_line]->children_count != 0) |
| 589 | { |
| 590 | current_line = element->children[try_line]; |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 591 | rettimeout = get_subline_timeout(info->gwps, |
| 592 | current_line->children[0]); |
| 593 | if (rettimeout > 0) |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 594 | { |
| 595 | suitable = true; |
| 596 | } |
| 597 | } |
| 598 | } |
| 599 | while (try_line != start && !suitable); |
| 600 | |
| 601 | if (suitable) |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 602 | { |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 603 | alternator->current_line = try_line; |
Jonathan Gordon | 0b824da | 2010-10-10 06:47:52 +0000 | [diff] [blame] | 604 | alternator->next_change_tick = current_tick + rettimeout; |
| 605 | } |
Jonathan Gordon | 216ed29 | 2010-09-02 11:43:33 +0000 | [diff] [blame] | 606 | |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 607 | info->refresh_type = SKIN_REFRESH_ALL; |
| 608 | info->force_redraw = true; |
| 609 | } |
| 610 | bool ret = skin_render_line(element->children[alternator->current_line], info); |
| 611 | info->refresh_type = old_refresh; |
| 612 | return changed_lines || ret; |
| 613 | } |
| 614 | |
Frank Gevaerts | d0bf13b | 2010-10-10 13:21:49 +0000 | [diff] [blame] | 615 | static void skin_render_viewport(struct skin_element* viewport, struct gui_wps *gwps, |
Bertrik Sikken | 57933f2 | 2010-07-30 23:47:49 +0000 | [diff] [blame] | 616 | struct skin_viewport* skin_viewport, unsigned long refresh_type) |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 617 | { |
| 618 | struct screen *display = gwps->display; |
| 619 | char linebuf[MAX_LINE]; |
| 620 | skin_render_func func = skin_render_line; |
| 621 | struct skin_element* line = viewport; |
| 622 | struct skin_draw_info info = { |
| 623 | .gwps = gwps, |
| 624 | .buf = linebuf, |
| 625 | .buf_size = sizeof(linebuf), |
| 626 | .line_number = 0, |
| 627 | .no_line_break = false, |
| 628 | .line_scrolls = false, |
| 629 | .refresh_type = refresh_type, |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 630 | .skin_vp = skin_viewport, |
Jonathan Gordon | 281f1a1 | 2011-08-14 13:50:07 +0000 | [diff] [blame] | 631 | .offset = 0, |
| 632 | .text_style = STYLE_DEFAULT |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 633 | }; |
| 634 | |
| 635 | struct align_pos * align = &info.align; |
| 636 | bool needs_update; |
| 637 | #ifdef HAVE_LCD_BITMAP |
| 638 | /* Set images to not to be displayed */ |
| 639 | struct skin_token_list *imglist = gwps->data->images; |
| 640 | while (imglist) |
| 641 | { |
| 642 | struct gui_img *img = (struct gui_img *)imglist->token->value.data; |
| 643 | img->display = -1; |
| 644 | imglist = imglist->next; |
| 645 | } |
| 646 | #endif |
| 647 | |
| 648 | while (line) |
| 649 | { |
| 650 | linebuf[0] = '\0'; |
| 651 | info.no_line_break = false; |
| 652 | info.line_scrolls = false; |
| 653 | info.force_redraw = false; |
Jonathan Gordon | 281f1a1 | 2011-08-14 13:50:07 +0000 | [diff] [blame] | 654 | #ifdef HAVE_LCD_COLOR |
| 655 | if (info.text_style&STYLE_GRADIENT) |
| 656 | { |
| 657 | int cur = CURLN_UNPACK(info.text_style); |
| 658 | int num = NUMLN_UNPACK(info.text_style); |
| 659 | if (cur+1 == num) |
| 660 | info.text_style = STYLE_DEFAULT; |
| 661 | else |
| 662 | info.text_style = STYLE_GRADIENT|CURLN_PACK(cur+1)|NUMLN_PACK(num); |
| 663 | } |
| 664 | #endif |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 665 | info.cur_align_start = info.buf; |
| 666 | align->left = info.buf; |
| 667 | align->center = NULL; |
| 668 | align->right = NULL; |
| 669 | |
| 670 | |
| 671 | if (line->type == LINE_ALTERNATOR) |
| 672 | func = skin_render_alternator; |
| 673 | else if (line->type == LINE) |
| 674 | func = skin_render_line; |
| 675 | |
| 676 | needs_update = func(line, &info); |
Jonathan Gordon | 0432147 | 2010-10-13 09:46:01 +0000 | [diff] [blame] | 677 | #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) |
| 678 | if (skin_viewport->vp.fg_pattern != skin_viewport->start_fgcolour || |
| 679 | skin_viewport->vp.bg_pattern != skin_viewport->start_bgcolour) |
| 680 | { |
| 681 | /* 2bit lcd drivers need lcd_set_viewport() to be called to change |
| 682 | * the colour, 16bit doesnt. But doing this makes static text |
| 683 | * get the new colour also */ |
| 684 | needs_update = true; |
| 685 | display->set_viewport(&skin_viewport->vp); |
| 686 | } |
| 687 | #endif |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 688 | /* only update if the line needs to be, and there is something to write */ |
| 689 | if (refresh_type && needs_update) |
| 690 | { |
| 691 | if (info.line_scrolls) |
| 692 | { |
| 693 | /* if the line is a scrolling one we don't want to update |
| 694 | too often, so that it has the time to scroll */ |
| 695 | if ((refresh_type & SKIN_REFRESH_SCROLL) || info.force_redraw) |
Jonathan Gordon | 281f1a1 | 2011-08-14 13:50:07 +0000 | [diff] [blame] | 696 | write_line(display, align, info.line_number, true, info.text_style); |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 697 | } |
| 698 | else |
Jonathan Gordon | 281f1a1 | 2011-08-14 13:50:07 +0000 | [diff] [blame] | 699 | write_line(display, align, info.line_number, false, info.text_style); |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 700 | } |
| 701 | if (!info.no_line_break) |
| 702 | info.line_number++; |
| 703 | line = line->next; |
| 704 | } |
| 705 | #ifdef HAVE_LCD_BITMAP |
| 706 | wps_display_images(gwps, &skin_viewport->vp); |
| 707 | #endif |
| 708 | } |
| 709 | |
| 710 | void skin_render(struct gui_wps *gwps, unsigned refresh_mode) |
| 711 | { |
| 712 | struct wps_data *data = gwps->data; |
| 713 | struct screen *display = gwps->display; |
| 714 | |
Nils Wallménius | 3b04a85 | 2011-06-12 22:17:45 +0000 | [diff] [blame] | 715 | struct skin_element* viewport; |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 716 | struct skin_viewport* skin_viewport; |
| 717 | |
| 718 | int old_refresh_mode = refresh_mode; |
| 719 | |
| 720 | #ifdef HAVE_LCD_CHARCELLS |
| 721 | int i; |
| 722 | for (i = 0; i < 8; i++) |
| 723 | { |
| 724 | if (data->wps_progress_pat[i] == 0) |
| 725 | data->wps_progress_pat[i] = display->get_locked_pattern(); |
| 726 | } |
| 727 | #endif |
| 728 | viewport = data->tree; |
| 729 | skin_viewport = (struct skin_viewport *)viewport->data; |
Jonathan Gordon | ee4f8a9 | 2010-08-02 12:50:23 +0000 | [diff] [blame] | 730 | if (skin_viewport->label && viewport->next && |
| 731 | !strcmp(skin_viewport->label,VP_DEFAULT_LABEL)) |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 732 | refresh_mode = 0; |
| 733 | |
| 734 | for (viewport = data->tree; |
| 735 | viewport; |
| 736 | viewport = viewport->next) |
| 737 | { |
| 738 | /* SETUP */ |
| 739 | skin_viewport = (struct skin_viewport*)viewport->data; |
| 740 | unsigned vp_refresh_mode = refresh_mode; |
| 741 | #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) |
| 742 | skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour; |
| 743 | skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour; |
| 744 | #endif |
Jonathan Gordon | 281f1a1 | 2011-08-14 13:50:07 +0000 | [diff] [blame] | 745 | #ifdef HAVE_LCD_COLOR |
| 746 | skin_viewport->vp.lss_pattern = skin_viewport->start_gradient.start; |
| 747 | skin_viewport->vp.lse_pattern = skin_viewport->start_gradient.end; |
| 748 | skin_viewport->vp.lst_pattern = skin_viewport->start_gradient.text; |
| 749 | #endif |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 750 | |
| 751 | /* dont redraw the viewport if its disabled */ |
| 752 | if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE) |
| 753 | { /* don't draw anything into this one */ |
| 754 | vp_refresh_mode = 0; |
| 755 | } |
| 756 | else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN)) |
| 757 | { |
| 758 | skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN; |
| 759 | continue; |
| 760 | } |
| 761 | else if (((skin_viewport->hidden_flags& |
| 762 | (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)) |
| 763 | == (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))) |
| 764 | { |
| 765 | vp_refresh_mode = SKIN_REFRESH_ALL; |
| 766 | skin_viewport->hidden_flags = VP_DRAW_HIDEABLE; |
| 767 | } |
| 768 | |
| 769 | display->set_viewport(&skin_viewport->vp); |
| 770 | if ((vp_refresh_mode&SKIN_REFRESH_ALL) == SKIN_REFRESH_ALL) |
| 771 | { |
| 772 | display->clear_viewport(); |
| 773 | } |
| 774 | /* render */ |
Jonathan Gordon | 39cf6dd | 2010-10-12 09:36:59 +0000 | [diff] [blame] | 775 | if (viewport->children_count) |
| 776 | skin_render_viewport(viewport->children[0], gwps, |
| 777 | skin_viewport, vp_refresh_mode); |
Jonathan Gordon | 2d31d77 | 2010-07-29 12:37:48 +0000 | [diff] [blame] | 778 | refresh_mode = old_refresh_mode; |
| 779 | } |
| 780 | |
| 781 | /* Restore the default viewport */ |
| 782 | display->set_viewport(NULL); |
| 783 | display->update(); |
| 784 | } |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 785 | |
Jonathan Gordon | a9d752b | 2010-08-14 15:31:04 +0000 | [diff] [blame] | 786 | #ifdef HAVE_LCD_BITMAP |
Frank Gevaerts | 561999e | 2010-10-10 13:26:51 +0000 | [diff] [blame] | 787 | static __attribute__((noinline)) void skin_render_playlistviewer(struct playlistviewer* viewer, |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 788 | struct gui_wps *gwps, |
| 789 | struct skin_viewport* skin_viewport, |
| 790 | unsigned long refresh_type) |
| 791 | { |
| 792 | struct screen *display = gwps->display; |
| 793 | char linebuf[MAX_LINE]; |
| 794 | skin_render_func func = skin_render_line; |
| 795 | struct skin_element* line; |
| 796 | struct skin_draw_info info = { |
| 797 | .gwps = gwps, |
| 798 | .buf = linebuf, |
| 799 | .buf_size = sizeof(linebuf), |
| 800 | .line_number = 0, |
| 801 | .no_line_break = false, |
| 802 | .line_scrolls = false, |
| 803 | .refresh_type = refresh_type, |
| 804 | .skin_vp = skin_viewport, |
Jonathan Gordon | 281f1a1 | 2011-08-14 13:50:07 +0000 | [diff] [blame] | 805 | .offset = viewer->start_offset, |
| 806 | .text_style = STYLE_DEFAULT |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 807 | }; |
| 808 | |
| 809 | struct align_pos * align = &info.align; |
| 810 | bool needs_update; |
| 811 | int cur_pos, start_item, max; |
| 812 | int nb_lines = viewport_get_nb_lines(viewer->vp); |
| 813 | #if CONFIG_TUNER |
Jonathan Gordon | b58d365 | 2011-06-01 14:41:49 +0000 | [diff] [blame] | 814 | if (get_current_activity() == ACTIVITY_FM) |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 815 | { |
| 816 | cur_pos = radio_current_preset(); |
| 817 | start_item = cur_pos + viewer->start_offset; |
| 818 | max = start_item+radio_preset_count(); |
| 819 | } |
| 820 | else |
| 821 | #endif |
| 822 | { |
Jonathan Gordon | 9928e34 | 2010-09-14 11:56:50 +0000 | [diff] [blame] | 823 | struct cuesheet *cue = skin_get_global_state()->id3 ? |
| 824 | skin_get_global_state()->id3->cuesheet : NULL; |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 825 | cur_pos = playlist_get_display_index(); |
| 826 | max = playlist_amount()+1; |
| 827 | if (cue) |
| 828 | max += cue->track_count; |
| 829 | start_item = MAX(0, cur_pos + viewer->start_offset); |
| 830 | } |
| 831 | if (max-start_item > nb_lines) |
| 832 | max = start_item + nb_lines; |
| 833 | |
| 834 | line = viewer->line; |
| 835 | while (start_item < max) |
| 836 | { |
| 837 | linebuf[0] = '\0'; |
| 838 | info.no_line_break = false; |
| 839 | info.line_scrolls = false; |
| 840 | info.force_redraw = false; |
| 841 | |
| 842 | info.cur_align_start = info.buf; |
| 843 | align->left = info.buf; |
| 844 | align->center = NULL; |
| 845 | align->right = NULL; |
| 846 | |
| 847 | |
| 848 | if (line->type == LINE_ALTERNATOR) |
| 849 | func = skin_render_alternator; |
| 850 | else if (line->type == LINE) |
| 851 | func = skin_render_line; |
| 852 | |
| 853 | needs_update = func(line, &info); |
| 854 | |
| 855 | /* only update if the line needs to be, and there is something to write */ |
| 856 | if (refresh_type && needs_update) |
| 857 | { |
| 858 | if (info.line_scrolls) |
| 859 | { |
| 860 | /* if the line is a scrolling one we don't want to update |
| 861 | too often, so that it has the time to scroll */ |
| 862 | if ((refresh_type & SKIN_REFRESH_SCROLL) || info.force_redraw) |
Jonathan Gordon | 281f1a1 | 2011-08-14 13:50:07 +0000 | [diff] [blame] | 863 | write_line(display, align, info.line_number, true, info.text_style); |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 864 | } |
| 865 | else |
Jonathan Gordon | 281f1a1 | 2011-08-14 13:50:07 +0000 | [diff] [blame] | 866 | write_line(display, align, info.line_number, false, info.text_style); |
Jonathan Gordon | dc3778a | 2010-08-14 15:17:59 +0000 | [diff] [blame] | 867 | } |
| 868 | info.line_number++; |
| 869 | info.offset++; |
| 870 | start_item++; |
| 871 | } |
| 872 | } |
Jonathan Gordon | a9d752b | 2010-08-14 15:31:04 +0000 | [diff] [blame] | 873 | #endif |