From 685cf5900825b10c952f36301abbbd9968567435 Mon Sep 17 00:00:00 2001 From: Jonathan Gordon Date: Mon, 3 Dec 2012 20:43:58 +1100 Subject: [PATCH] 9 segment bitmap drawing: Use %x9(id) to draw an image in the whole current viewport using the 9 segment drawer (which draws the corners as normal and *tiles* the middle segments to the needed width/height). Future work is to make it scale instead of tile Change-Id: Ic3ed1cad93f96091694801eb442e0da5a2401203 --- apps/gui/skin_engine/skin_display.c | 13 +++++++---- apps/gui/skin_engine/skin_display.h | 1 - apps/gui/skin_engine/skin_parser.c | 5 ++++ apps/gui/skin_engine/skin_render.c | 1 + apps/gui/skin_engine/wps_internals.h | 1 + apps/screen_access.c | 1 + apps/screen_access.h | 4 ++++ firmware/drivers/lcd-bitmap-common.c | 45 ++++++++++++++++++++++++++++++++++++ firmware/export/lcd.h | 2 ++ lib/skin_parser/tag_table.c | 1 + lib/skin_parser/tag_table.h | 1 + manual/appendix/wps_tags.tex | 7 ++++++ 12 files changed, 76 insertions(+), 6 deletions(-) diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c index 4f491dea24..24958a46f2 100644 --- a/apps/gui/skin_engine/skin_display.c +++ b/apps/gui/skin_engine/skin_display.c @@ -302,17 +302,20 @@ void clear_image_pos(struct gui_wps *gwps, struct gui_img *img) gwps->display->set_drawmode(DRMODE_SOLID); } -void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage) +void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, + int subimage, struct viewport* vp) { struct screen *display = gwps->display; img->bm.data = core_get_data(img->buflib_handle); display->set_drawmode(DRMODE_SOLID); - display->bmp_part(&img->bm, 0, img->subimage_height * subimage, - img->x, img->y, img->bm.width, img->subimage_height); + if (img->is_9_segment) + display->nine_segment_bmp(&img->bm, 0, 0, vp->width, vp->height); + else + display->bmp_part(&img->bm, 0, img->subimage_height * subimage, + img->x, img->y, img->bm.width, img->subimage_height); } - void wps_display_images(struct gui_wps *gwps, struct viewport* vp) { if(!gwps || !gwps->data || !gwps->display) @@ -334,7 +337,7 @@ void wps_display_images(struct gui_wps *gwps, struct viewport* vp) { if (img->display >= 0) { - wps_draw_image(gwps, img, img->display); + wps_draw_image(gwps, img, img->display, vp); } } list = SKINOFFSETTOPTR(get_skin_buffer(data), list->next); diff --git a/apps/gui/skin_engine/skin_display.h b/apps/gui/skin_engine/skin_display.h index 81d04e5a60..b3422b0360 100644 --- a/apps/gui/skin_engine/skin_display.h +++ b/apps/gui/skin_engine/skin_display.h @@ -34,7 +34,6 @@ void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb); void draw_playlist_viewer_list(struct gui_wps *gwps, struct playlistviewer *viewer); /* clears the area where the image was shown */ void clear_image_pos(struct gui_wps *gwps, struct gui_img *img); -void wps_draw_image(struct gui_wps *gwps, struct gui_img *img, int subimage); void wps_display_images(struct gui_wps *gwps, struct viewport* vp); diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c index 93f310df56..94adaf3116 100644 --- a/apps/gui/skin_engine/skin_parser.c +++ b/apps/gui/skin_engine/skin_parser.c @@ -344,6 +344,9 @@ static int parse_image_display(struct skin_element *element, token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON; } + if (token->type == SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT) + img->is_9_segment = true; + if (element->params_count > 1) { if (get_param(element, 1)->type == CODE) @@ -417,6 +420,7 @@ static int parse_image_load(struct skin_element *element, img->display = -1; img->using_preloaded_icons = false; img->buflib_handle = -1; + img->is_9_segment = false; /* save current viewport */ img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp); @@ -2181,6 +2185,7 @@ static int skin_element_callback(struct skin_element* element, void* data) token->value.data = get_param(element, 0)->data.text; break; case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY: + case SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT: function = parse_image_display; break; case SKIN_TOKEN_IMAGE_PRELOAD: diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c index 0fdf6b019f..e01972fc3b 100644 --- a/apps/gui/skin_engine/skin_render.c +++ b/apps/gui/skin_engine/skin_render.c @@ -231,6 +231,7 @@ static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info, break; case SKIN_TOKEN_IMAGE_DISPLAY_LISTICON: case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY: + case SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT: { struct image_display *id = SKINOFFSETTOPTR(skin_buffer, token->value.data); const char* label = SKINOFFSETTOPTR(skin_buffer, id->label); diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h index 8cd5d9cb60..72bab9b668 100644 --- a/apps/gui/skin_engine/wps_internals.h +++ b/apps/gui/skin_engine/wps_internals.h @@ -82,6 +82,7 @@ struct gui_img { bool loaded; /* load state */ int display; bool using_preloaded_icons; /* using the icon system instead of a bmp */ + bool is_9_segment; }; struct image_display { diff --git a/apps/screen_access.c b/apps/screen_access.c index fc92210981..79ab459475 100644 --- a/apps/screen_access.c +++ b/apps/screen_access.c @@ -195,6 +195,7 @@ struct screen screens[NB_SCREENS] = #endif .bmp = &lcd_bmp, .bmp_part = &lcd_bmp_part, + .nine_segment_bmp = &lcd_nine_segment_bmp, #if LCD_DEPTH > 1 #if defined(HAVE_LCD_COLOR) && defined(LCD_REMOTE_DEPTH) && LCD_REMOTE_DEPTH > 1 .color_to_native=&lcd_color_to_native, diff --git a/apps/screen_access.h b/apps/screen_access.h index ab2ef4f14d..ea05a2294d 100644 --- a/apps/screen_access.h +++ b/apps/screen_access.h @@ -167,6 +167,10 @@ struct screen unsigned start, unsigned end); #endif #endif +#if defined(HAVE_LCD_BITMAP) + void (*nine_segment_bmp)(const struct bitmap* bm, int x, int y, + int width, int height); +#endif }; #if defined(HAVE_LCD_BITMAP) || defined(HAVE_REMOTE_LCD) diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c index 0bae790e58..a149e8aaa9 100644 --- a/firmware/drivers/lcd-bitmap-common.c +++ b/firmware/drivers/lcd-bitmap-common.c @@ -615,3 +615,48 @@ void LCDFN(bmp)(const struct bitmap* bm, int x, int y) } #endif + +void LCDFN(nine_segment_bmp)(const struct bitmap* bm, int x, int y, + int width, int height) +{ + int seg_w = bm->width / 3; + int seg_h = bm->height / 3; + int src_x, src_y, dst_x, dst_y; + + /* top */ + src_x = seg_w; src_y = 0; + dst_x = seg_w; dst_y = 0; + for (; dst_x < width - seg_w; dst_x += seg_w) + LCDFN(bmp_part)(bm, src_x, src_y, dst_x, dst_y, seg_w, seg_h); + /* bottom */ + src_x = seg_w; src_y = bm->height - seg_h; + dst_x = seg_w; dst_y = height - seg_h; + for (; dst_x < width - seg_w; dst_x += seg_w) + LCDFN(bmp_part)(bm, src_x, src_y, dst_x, dst_y, seg_w, seg_h); + + /* left */ + src_x = 0; src_y = seg_h; + dst_x = 0; dst_y = seg_h; + for (; dst_y < height - seg_h; dst_y += seg_h) + LCDFN(bmp_part)(bm, src_x, src_y, dst_x, dst_y, seg_w, seg_h); + /* right */ + src_x = bm->width - seg_w; src_y = seg_h; + dst_x = width - seg_w; dst_y = seg_h; + for (; dst_y < height - seg_h; dst_y += seg_h) + LCDFN(bmp_part)(bm, src_x, src_y, dst_x, dst_y, seg_w, seg_h); + /* center */ + dst_y = seg_h; src_y = seg_h; src_x = seg_w; + for (; dst_y < height - seg_h; dst_y += seg_h) + { + dst_x = seg_w; + for (; dst_x < width - seg_w; dst_x += seg_w) + LCDFN(bmp_part)(bm, src_x, src_y, dst_x, dst_y, seg_w, seg_h); + } + + /* 4 corners */ + LCDFN(bmp_part)(bm, 0, 0, x, y, seg_w, seg_h); + LCDFN(bmp_part)(bm, bm->width - seg_w, 0, width - seg_w, 0, seg_w, seg_h); + LCDFN(bmp_part)(bm, 0, bm->width - seg_h, 0, height - seg_h, seg_w, seg_h); + LCDFN(bmp_part)(bm, bm->width - seg_w, bm->width - seg_h, + width - seg_w, height - seg_h, seg_w, seg_h); +} diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index dbb3a781b8..a82c00534d 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -568,6 +568,8 @@ extern void lcd_bitmap_transparent(const fb_data *src, int x, int y, extern void lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y, int x, int y, int width, int height); extern void lcd_bmp(const struct bitmap* bm, int x, int y); +extern void lcd_nine_segment_bmp(const struct bitmap* bm, int x, int y, + int width, int height); #endif /* HAVE_LCD_BITMAP */ diff --git a/lib/skin_parser/tag_table.c b/lib/skin_parser/tag_table.c index ec1476fb80..24dcf181d4 100644 --- a/lib/skin_parser/tag_table.c +++ b/lib/skin_parser/tag_table.c @@ -179,6 +179,7 @@ static const struct tag_info legal_tags[] = { SKIN_TOKEN_IMAGE_PRELOAD, "xl", "SF|III", 0|NOBREAK }, { SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", "S|[IT]I", 0 }, { SKIN_TOKEN_IMAGE_DISPLAY, "x", "SF|II", SKIN_REFRESH_STATIC|NOBREAK }, + { SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT, "x9", "S", 0 }, { SKIN_TOKEN_LOAD_FONT, "Fl" , "IF|I", 0|NOBREAK }, { SKIN_TOKEN_ALBUMART_LOAD, "Cl" , "IIII|ss", 0|NOBREAK }, diff --git a/lib/skin_parser/tag_table.h b/lib/skin_parser/tag_table.h index 41f7d7dd86..94f82fd759 100644 --- a/lib/skin_parser/tag_table.h +++ b/lib/skin_parser/tag_table.h @@ -163,6 +163,7 @@ enum skin_token_type { SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY, SKIN_TOKEN_IMAGE_DISPLAY, SKIN_TOKEN_IMAGE_DISPLAY_LISTICON, + SKIN_TOKEN_IMAGE_DISPLAY_9SEGMENT, /* Albumart */ SKIN_TOKEN_ALBUMART_LOAD, diff --git a/manual/appendix/wps_tags.tex b/manual/appendix/wps_tags.tex index 9fea2bade3..7551276bdf 100644 --- a/manual/appendix/wps_tags.tex +++ b/manual/appendix/wps_tags.tex @@ -403,6 +403,13 @@ Examples: use the first subimage when \config{\%mh} is on and the second when it is off\newline \config{offset}: (optional) Add this number to the value from the \config{tag} when chosing the subimage (may be negative)\\ + \config{\%x9(n)} + & Display an image as a 9-patch bitmap covering the entire viewport.\newline + 9-patch images are bitmaps split into 9 segments where the four corners + are unscaled, the four middle sections are scaled along one axis and the middle + section is scaled on both axis.\newline + \config{n}: image ID\\ + \end{tagmap} Examples: -- 2.11.4.GIT