diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c index a967114125..02e9d39711 100644 --- a/apps/gui/skin_engine/skin_display.c +++ b/apps/gui/skin_engine/skin_display.c @@ -450,15 +450,12 @@ int evaluate_conditional(struct gui_wps *gwps, int offset, line is the index of the line on the screen. scroll indicates whether the line is a scrolling one or not. */ -void write_line(struct screen *display, - struct align_pos *format_align, - int line, - bool scroll) +void write_line(struct screen *display, struct align_pos *format_align, + int line, bool scroll, unsigned style) { int left_width = 0, left_xpos; int center_width = 0, center_xpos; int right_width = 0, right_xpos; - int ypos; int space_width; int string_height; int scroll_width; @@ -565,22 +562,19 @@ void write_line(struct screen *display, right_width = 0; } - ypos = (line * string_height); - - if (scroll && ((left_width > scroll_width) || (center_width > scroll_width) || (right_width > scroll_width))) { - display->puts_scroll(0, line, - (unsigned char *)format_align->left); + display->puts_scroll_style(0, line, + (unsigned char *)format_align->left, style); } else { #ifdef HAVE_LCD_BITMAP /* clear the line first */ display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); - display->fillrect(left_xpos, ypos, display->getwidth(), string_height); + display->fillrect(left_xpos, line*string_height, display->getwidth(), string_height); display->set_drawmode(DRMODE_SOLID); #endif @@ -591,18 +585,19 @@ void write_line(struct screen *display, /* print aligned strings */ if (left_width != 0) { - display->putsxy(left_xpos, ypos, - (unsigned char *)format_align->left); + display->puts_style_xyoffset(left_xpos/space_width, line, + (unsigned char *)format_align->left, style, 0, 0); + } if (center_width != 0) { - display->putsxy(center_xpos, ypos, - (unsigned char *)format_align->center); + display->puts_style_xyoffset(center_xpos/space_width, line, + (unsigned char *)format_align->center, style, 0, 0); } if (right_width != 0) { - display->putsxy(right_xpos, ypos, - (unsigned char *)format_align->right); + display->puts_style_xyoffset(right_xpos/space_width, line, + (unsigned char *)format_align->right, style, 0, 0); } } } diff --git a/apps/gui/skin_engine/skin_display.h b/apps/gui/skin_engine/skin_display.h index da4bb92aef..9faaea30cf 100644 --- a/apps/gui/skin_engine/skin_display.h +++ b/apps/gui/skin_engine/skin_display.h @@ -48,10 +48,8 @@ int evaluate_conditional(struct gui_wps *gwps, int offset, line is the index of the line on the screen. scroll indicates whether the line is a scrolling one or not. */ -void write_line(struct screen *display, - struct align_pos *format_align, - int line, - bool scroll); +void write_line(struct screen *display, struct align_pos *format_align, + int line, bool scroll, unsigned style); void draw_peakmeters(struct gui_wps *gwps, int line_number, struct viewport *viewport); #endif diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c index 53e1efedd8..b7bb045411 100644 --- a/apps/gui/skin_engine/skin_parser.c +++ b/apps/gui/skin_engine/skin_parser.c @@ -453,6 +453,77 @@ static int parse_playlistview(struct skin_element *element, return 0; } #endif +#ifdef HAVE_LCD_COLOR +static int parse_viewport_gradient_setup(struct skin_element *element, + struct wps_token *token, + struct wps_data *wps_data) +{ + (void)wps_data; + struct gradient_config *cfg; + if (element->params_count < 2) /* only start and end are required */ + return 1; + cfg = (struct gradient_config *)skin_buffer_alloc(sizeof(struct gradient_config)); + if (!cfg) + return 1; + if (!parse_color(curr_screen, element->params[0].data.text, &cfg->start) || + !parse_color(curr_screen, element->params[1].data.text, &cfg->end)) + return 1; + if (element->params_count > 2) + { + if (!parse_color(curr_screen, element->params[2].data.text, &cfg->text)) + return 1; + } + else + { + cfg->text = curr_vp->vp.fg_pattern; + } + + token->value.data = cfg; + return 0; +} +#endif +static int parse_viewporttextstyle(struct skin_element *element, + struct wps_token *token, + struct wps_data *wps_data) +{ + (void)wps_data; + int style; + char *mode = element->params[0].data.text; + unsigned colour; + + if (!strcmp(mode, "invert")) + { + style = STYLE_INVERT; + } + else if (!strcmp(mode, "colour") || !strcmp(mode, "color")) + { + if (element->params_count < 2 || + !parse_color(curr_screen, element->params[1].data.text, &colour)) + return 1; + style = STYLE_COLORED|(STYLE_COLOR_MASK&colour); + } +#ifdef HAVE_LCD_COLOR + else if (!strcmp(mode, "gradient")) + { + int num_lines; + if (element->params_count < 2) + num_lines = 1; + else /* atoi() instead of using a number in the parser is because [si] + * will select the number for something which looks like a colour + * making the "colour" case (above) harder to parse */ + num_lines = atoi(element->params[1].data.text); + style = STYLE_GRADIENT|NUMLN_PACK(num_lines)|CURLN_PACK(0); + } +#endif + else if (!strcmp(mode, "clear")) + { + style = STYLE_DEFAULT; + } + else + return 1; + token->value.l = style; + return 0; +} #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) @@ -1514,6 +1585,11 @@ static int convert_viewport(struct wps_data *data, struct skin_element* element) skin_vp->start_fgcolour = skin_vp->vp.fg_pattern; skin_vp->start_bgcolour = skin_vp->vp.bg_pattern; #endif +#ifdef HAVE_LCD_COLOR + skin_vp->start_gradient.start = skin_vp->vp.lss_pattern; + skin_vp->start_gradient.end = skin_vp->vp.lse_pattern; + skin_vp->start_gradient.text = skin_vp->vp.lst_pattern; +#endif struct skin_tag_parameter *param = element->params; @@ -1683,6 +1759,14 @@ static int skin_element_callback(struct skin_element* element, void* data) case SKIN_TOKEN_IMAGE_BACKDROP: function = parse_image_special; break; +#endif + case SKIN_TOKEN_VIEWPORT_TEXTSTYLE: + function = parse_viewporttextstyle; + break; +#ifdef HAVE_LCD_COLOR + case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP: + function = parse_viewport_gradient_setup; + break; #endif case SKIN_TOKEN_TRANSLATEDSTRING: case SKIN_TOKEN_SETTING: diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c index 13eb69c744..27e6747c29 100644 --- a/apps/gui/skin_engine/skin_render.c +++ b/apps/gui/skin_engine/skin_render.c @@ -55,6 +55,7 @@ struct skin_draw_info { struct skin_viewport *skin_vp; int line_number; unsigned long refresh_type; + unsigned text_style; char* cur_align_start; struct align_pos align; @@ -106,6 +107,19 @@ static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info, col->vp->bg_pattern = col->colour; } break; + case SKIN_TOKEN_VIEWPORT_TEXTSTYLE: + info->text_style = token->value.l; + break; +#endif +#ifdef HAVE_LCD_COLOR + case SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP: + { + struct gradient_config *cfg = token->value.data; + vp->lss_pattern = cfg->start; + vp->lse_pattern = cfg->end; + vp->lst_pattern = cfg->text; + } + break; #endif case SKIN_TOKEN_VIEWPORT_ENABLE: { @@ -614,7 +628,8 @@ static void skin_render_viewport(struct skin_element* viewport, struct gui_wps * .line_scrolls = false, .refresh_type = refresh_type, .skin_vp = skin_viewport, - .offset = 0 + .offset = 0, + .text_style = STYLE_DEFAULT }; struct align_pos * align = &info.align; @@ -636,7 +651,17 @@ static void skin_render_viewport(struct skin_element* viewport, struct gui_wps * info.no_line_break = false; info.line_scrolls = false; info.force_redraw = false; - +#ifdef HAVE_LCD_COLOR + if (info.text_style&STYLE_GRADIENT) + { + int cur = CURLN_UNPACK(info.text_style); + int num = NUMLN_UNPACK(info.text_style); + if (cur+1 == num) + info.text_style = STYLE_DEFAULT; + else + info.text_style = STYLE_GRADIENT|CURLN_PACK(cur+1)|NUMLN_PACK(num); + } +#endif info.cur_align_start = info.buf; align->left = info.buf; align->center = NULL; @@ -668,10 +693,10 @@ static void skin_render_viewport(struct skin_element* viewport, struct gui_wps * /* if the line is a scrolling one we don't want to update too often, so that it has the time to scroll */ if ((refresh_type & SKIN_REFRESH_SCROLL) || info.force_redraw) - write_line(display, align, info.line_number, true); + write_line(display, align, info.line_number, true, info.text_style); } else - write_line(display, align, info.line_number, false); + write_line(display, align, info.line_number, false, info.text_style); } if (!info.no_line_break) info.line_number++; @@ -717,6 +742,11 @@ void skin_render(struct gui_wps *gwps, unsigned refresh_mode) skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour; skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour; #endif +#ifdef HAVE_LCD_COLOR + skin_viewport->vp.lss_pattern = skin_viewport->start_gradient.start; + skin_viewport->vp.lse_pattern = skin_viewport->start_gradient.end; + skin_viewport->vp.lst_pattern = skin_viewport->start_gradient.text; +#endif /* dont redraw the viewport if its disabled */ if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE) @@ -772,7 +802,8 @@ static __attribute__((noinline)) void skin_render_playlistviewer(struct playlist .line_scrolls = false, .refresh_type = refresh_type, .skin_vp = skin_viewport, - .offset = viewer->start_offset + .offset = viewer->start_offset, + .text_style = STYLE_DEFAULT }; struct align_pos * align = &info.align; @@ -829,10 +860,10 @@ static __attribute__((noinline)) void skin_render_playlistviewer(struct playlist /* if the line is a scrolling one we don't want to update too often, so that it has the time to scroll */ if ((refresh_type & SKIN_REFRESH_SCROLL) || info.force_redraw) - write_line(display, align, info.line_number, true); + write_line(display, align, info.line_number, true, info.text_style); } else - write_line(display, align, info.line_number, false); + write_line(display, align, info.line_number, false, info.text_style); } info.line_number++; info.offset++; diff --git a/apps/gui/skin_engine/skin_tokens.h b/apps/gui/skin_engine/skin_tokens.h index d259fe431c..9df2137ece 100644 --- a/apps/gui/skin_engine/skin_tokens.h +++ b/apps/gui/skin_engine/skin_tokens.h @@ -35,6 +35,7 @@ struct wps_token { union { char c; unsigned short i; + long l; void* data; } value; }; diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h index 6de98455a7..01f67d4a0b 100644 --- a/apps/gui/skin_engine/wps_internals.h +++ b/apps/gui/skin_engine/wps_internals.h @@ -161,6 +161,14 @@ enum wps_parse_error { PARSE_FAIL_COND_INVALID_PARAM, PARSE_FAIL_LIMITS_EXCEEDED, }; +#ifdef HAVE_LCD_COLOR +struct gradient_config { + unsigned start; + unsigned end; + unsigned text; + int lines_count; +}; +#endif #define VP_DRAW_HIDEABLE 0x1 #define VP_DRAW_HIDDEN 0x2 @@ -173,8 +181,13 @@ struct skin_viewport { char hidden_flags; bool is_infovp; char* label; +#if LCD_DEPTH > 1 unsigned start_fgcolour; unsigned start_bgcolour; +#ifdef HAVE_LCD_COLOR + struct gradient_config start_gradient; +#endif +#endif }; struct viewport_colour { struct viewport *vp; diff --git a/lib/skin_parser/tag_table.c b/lib/skin_parser/tag_table.c index dea28b63ea..db8c2e5557 100644 --- a/lib/skin_parser/tag_table.c +++ b/lib/skin_parser/tag_table.c @@ -192,6 +192,8 @@ static const struct tag_info legal_tags[] = { SKIN_TOKEN_VIEWPORT_FGCOLOUR, "Vf" , "s", SKIN_REFRESH_STATIC|NOBREAK }, { SKIN_TOKEN_VIEWPORT_BGCOLOUR, "Vb" , "s", SKIN_REFRESH_STATIC|NOBREAK }, + { SKIN_TOKEN_VIEWPORT_TEXTSTYLE, "Vs" , "S|s", SKIN_REFRESH_STATIC }, + { SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP, "Vg" , "SS|s", SKIN_REFRESH_STATIC|NOBREAK }, { SKIN_TOKEN_VIEWPORT_CONDITIONAL, "Vl" , "SIIiii", 0 }, { SKIN_TOKEN_UIVIEWPORT_LOAD, "Vi" , "sIIiii", 0 }, diff --git a/lib/skin_parser/tag_table.h b/lib/skin_parser/tag_table.h index e52fded61e..58c14b5e0b 100644 --- a/lib/skin_parser/tag_table.h +++ b/lib/skin_parser/tag_table.h @@ -87,6 +87,8 @@ enum skin_token_type { SKIN_TOKEN_UIVIEWPORT_LOAD, SKIN_TOKEN_VIEWPORT_FGCOLOUR, SKIN_TOKEN_VIEWPORT_BGCOLOUR, + SKIN_TOKEN_VIEWPORT_TEXTSTYLE, + SKIN_TOKEN_VIEWPORT_GRADIENT_SETUP, /* Battery */ SKIN_TOKEN_BATTERY_PERCENT,