From 945c8a221ade41c462a93f8452320a806e5645b3 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Mon, 7 Jan 2008 20:34:11 +0000 Subject: Add viewport capabilities to all the LCD drivers, and adapt scrolling code. This is the firmware/ part of FS#8385 - the changes to the WPS code still need more work and will be committed at a later date. NOTE: There are no user-visible changes with this commit - just the infrastructure. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16018 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/lcd-16bit.c | 478 +++++++++++++-------- firmware/drivers/lcd-1bit-vert.c | 250 +++++++---- firmware/drivers/lcd-2bit-horz.c | 277 ++++++++---- firmware/drivers/lcd-2bit-vert.c | 294 +++++++++---- firmware/drivers/lcd-charcell.c | 159 +++++-- firmware/drivers/lcd-remote-1bit-v.c | 260 +++++++---- firmware/drivers/lcd-remote-2bit-vi.c | 294 +++++++++---- firmware/export/lcd-remote.h | 7 + firmware/export/lcd.h | 28 ++ firmware/export/scroll_engine.h | 14 +- firmware/scroll_engine.c | 68 +++ .../target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c | 7 +- 12 files changed, 1473 insertions(+), 663 deletions(-) (limited to 'firmware') diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c index b990f556d3..cc5a6c5ab7 100644 --- a/firmware/drivers/lcd-16bit.c +++ b/firmware/drivers/lcd-16bit.c @@ -49,25 +49,31 @@ fb_data lcd_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH] static fb_data* lcd_backdrop = NULL; static long lcd_backdrop_offset IDATA_ATTR = 0; +static struct viewport default_vp = +{ + .x = 0, + .y = 0, + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, + .fg_pattern = LCD_DEFAULT_FG, + .bg_pattern = LCD_DEFAULT_BG, + .lss_pattern = LCD_DEFAULT_BG, + .lse_pattern = LCD_DEFAULT_BG, + .lst_pattern = LCD_DEFAULT_BG, +}; + +/* The Gigabeat target build requires access to the current fg_pattern + in lcd-meg-fx.c */ #if !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) -static unsigned fg_pattern IDATA_ATTR = LCD_DEFAULT_FG; -static unsigned bg_pattern IDATA_ATTR = LCD_DEFAULT_BG; -static unsigned lss_pattern IDATA_ATTR = LCD_DEFAULT_LS; -static unsigned lse_pattern IDATA_ATTR = LCD_DEFAULT_BG; -static unsigned lst_pattern IDATA_ATTR = LCD_DEFAULT_FG; +static struct viewport* current_vp IDATA_ATTR = &default_vp; #else -unsigned fg_pattern IDATA_ATTR = LCD_DEFAULT_FG; -unsigned bg_pattern IDATA_ATTR = LCD_DEFAULT_BG; -unsigned lss_pattern IDATA_ATTR = LCD_DEFAULT_LS; -unsigned lse_pattern IDATA_ATTR = LCD_DEFAULT_BG; -unsigned lst_pattern IDATA_ATTR = LCD_DEFAULT_FG; +struct viewport* current_vp IDATA_ATTR = &default_vp; #endif -static int drawmode = DRMODE_SOLID; -static int xmargin = 0; -static int ymargin = 0; -static int curfont = FONT_SYSFIXED; - /* LCD init */ void lcd_init(void) { @@ -78,84 +84,115 @@ void lcd_init(void) scroll_init(); } +/*** Viewports ***/ + +void lcd_set_viewport(struct viewport* vp) +{ + if (vp == NULL) + current_vp = &default_vp; + else + current_vp = vp; +} + +void lcd_update_viewport(void) +{ + lcd_update_rect(current_vp->x, current_vp->y, + current_vp->width, current_vp->height); +} + +void lcd_update_viewport_rect(int x, int y, int width, int height) +{ + lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height); +} + /*** parameter handling ***/ void lcd_set_drawmode(int mode) { - drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); + current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } int lcd_get_drawmode(void) { - return drawmode; + return current_vp->drawmode; } void lcd_set_foreground(unsigned color) { - fg_pattern = color; + current_vp->fg_pattern = color; } unsigned lcd_get_foreground(void) { - return fg_pattern; + return current_vp->fg_pattern; } void lcd_set_background(unsigned color) { - bg_pattern = color; + current_vp->bg_pattern = color; } unsigned lcd_get_background(void) { - return bg_pattern; + return current_vp->bg_pattern; } void lcd_set_selector_start(unsigned color) { - lss_pattern = color; + current_vp->lss_pattern = color; } void lcd_set_selector_end(unsigned color) { - lse_pattern = color; + current_vp->lse_pattern = color; } void lcd_set_selector_text(unsigned color) { - lst_pattern = color; + current_vp->lst_pattern = color; } void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color) { lcd_set_drawmode(mode); - fg_pattern = fg_color; - bg_pattern = bg_color; + current_vp->fg_pattern = fg_color; + current_vp->bg_pattern = bg_color; } void lcd_setmargins(int x, int y) { - xmargin = x; - ymargin = y; + current_vp->xmargin = x; + current_vp->ymargin = y; +} + +int lcd_getwidth(void) +{ + return current_vp->width; +} + +int lcd_getheight(void) +{ + return current_vp->height; } int lcd_getxmargin(void) { - return xmargin; + return current_vp->xmargin; } int lcd_getymargin(void) { - return ymargin; + return current_vp->ymargin; } void lcd_setfont(int newfont) { - curfont = newfont; + current_vp->font = newfont; } int lcd_getstringsize(const unsigned char *str, int *w, int *h) { - return font_getstringsize(str, w, h, curfont); + return font_getstringsize(str, w, h, current_vp->font); } /*** low-level drawing functions ***/ @@ -165,13 +202,13 @@ int lcd_getstringsize(const unsigned char *str, int *w, int *h) static void setpixel(fb_data *address) ICODE_ATTR; static void setpixel(fb_data *address) { - *address = fg_pattern; + *address = current_vp->fg_pattern; } static void clearpixel(fb_data *address) ICODE_ATTR; static void clearpixel(fb_data *address) { - *address = bg_pattern; + *address = current_vp->bg_pattern; } static void clearimgpixel(fb_data *address) ICODE_ATTR; @@ -226,31 +263,74 @@ fb_data* lcd_get_backdrop(void) /*** drawing functions ***/ -/* Clear the whole display */ -void lcd_clear_display(void) +/* Clear the current viewport */ +void lcd_clear_viewport(void) { - fb_data *dst = LCDADDR(0, 0); + fb_data *dst, *dst_end; + + dst = LCDADDR(current_vp->x, current_vp->y); + dst_end = dst + current_vp->height * LCD_WIDTH; - if (drawmode & DRMODE_INVERSEVID) + if (current_vp->drawmode & DRMODE_INVERSEVID) { - memset16(dst, fg_pattern, LCD_WIDTH*LCD_HEIGHT); + do + { + memset16(dst, current_vp->fg_pattern, current_vp->width); + dst += LCD_WIDTH; + } + while (dst < dst_end); } else { if (!lcd_backdrop) - memset16(dst, bg_pattern, LCD_WIDTH*LCD_HEIGHT); + { + do + { + memset16(dst, current_vp->bg_pattern, current_vp->width); + dst += LCD_WIDTH; + } + while (dst < dst_end); + } else - memcpy(dst, lcd_backdrop, sizeof(lcd_framebuffer)); + { + do + { + memcpy(dst, (void *)((long)dst + lcd_backdrop_offset), + current_vp->width * sizeof(fb_data)); + dst += LCD_WIDTH; + } + while (dst < dst_end); + } } - lcd_scroll_info.lines = 0; + if (current_vp == &default_vp) + { + lcd_scroll_info.lines = 0; + } + else + { + lcd_scroll_stop(current_vp); + } +} + +/* Clear the whole display */ +void lcd_clear_display(void) +{ + struct viewport* old_vp = current_vp; + + current_vp = &default_vp; + + lcd_clear_viewport(); + + current_vp = old_vp; } /* Set a single pixel */ void lcd_drawpixel(int x, int y) { - if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) - lcd_fastpixelfuncs[drawmode](LCDADDR(x, y)); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + lcd_fastpixelfuncs[current_vp->drawmode](LCDADDR(current_vp->x+x, current_vp->y+y)); } /* Draw a line */ @@ -262,7 +342,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2) int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; - lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -306,8 +386,8 @@ void lcd_drawline(int x1, int y1, int x2, int y2) for (i = 0; i < numpixels; i++) { - if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) - pfunc(LCDADDR(x, y)); + if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height)) + pfunc(LCDADDR(x + current_vp->x, y + current_vp->y)); if (d < 0) { @@ -331,7 +411,7 @@ void lcd_hline(int x1, int x2, int y) unsigned bits = 0; enum fill_opt fillopt = OPT_NONE; fb_data *dst, *dst_end; - lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; /* direction flip */ if (x2 < x1) @@ -342,23 +422,31 @@ void lcd_hline(int x1, int x2, int y) } /* nothing to draw? */ - if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) + if (((unsigned)y >= (unsigned)current_vp->height) || + (x1 >= current_vp->width) || + (x2 < 0)) return; /* clipping */ if (x1 < 0) x1 = 0; - if (x2 >= LCD_WIDTH) - x2 = LCD_WIDTH-1; + if (x2 >= current_vp->width) + x2 = current_vp->width-1; + + width = x2 - x1 + 1; - if (drawmode & DRMODE_INVERSEVID) + /* Adjust x1 and y to viewport */ + x1 += current_vp->x; + y += current_vp->y; + + if (current_vp->drawmode & DRMODE_INVERSEVID) { - if (drawmode & DRMODE_BG) + if (current_vp->drawmode & DRMODE_BG) { if (!lcd_backdrop) { fillopt = OPT_SET; - bits = bg_pattern; + bits = current_vp->bg_pattern; } else fillopt = OPT_COPY; @@ -366,14 +454,13 @@ void lcd_hline(int x1, int x2, int y) } else { - if (drawmode & DRMODE_FG) + if (current_vp->drawmode & DRMODE_FG) { fillopt = OPT_SET; - bits = fg_pattern; + bits = current_vp->fg_pattern; } } dst = LCDADDR(x1, y); - width = x2 - x1 + 1; switch (fillopt) { @@ -400,7 +487,7 @@ void lcd_vline(int x, int y1, int y2) { int y; fb_data *dst, *dst_end; - lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; /* direction flip */ if (y2 < y1) @@ -411,16 +498,18 @@ void lcd_vline(int x, int y1, int y2) } /* nothing to draw? */ - if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) + if ((x >= current_vp->width) || + (y1 >= current_vp->height) || + (y2 < 0)) return; /* clipping */ if (y1 < 0) y1 = 0; - if (y2 >= LCD_HEIGHT) - y2 = LCD_HEIGHT-1; + if (y2 >= current_vp->height) + y2 = current_vp->height-1; - dst = LCDADDR(x, y1); + dst = LCDADDR(x + current_vp->x, y1 + current_vp->y); dst_end = dst + (y2 - y1) * LCD_WIDTH; do @@ -452,11 +541,11 @@ void lcd_fillrect(int x, int y, int width, int height) unsigned bits = 0; enum fill_opt fillopt = OPT_NONE; fb_data *dst, *dst_end; - lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -470,19 +559,19 @@ void lcd_fillrect(int x, int y, int width, int height) height += y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; - if (drawmode & DRMODE_INVERSEVID) + if (current_vp->drawmode & DRMODE_INVERSEVID) { - if (drawmode & DRMODE_BG) + if (current_vp->drawmode & DRMODE_BG) { if (!lcd_backdrop) { fillopt = OPT_SET; - bits = bg_pattern; + bits = current_vp->bg_pattern; } else fillopt = OPT_COPY; @@ -490,13 +579,13 @@ void lcd_fillrect(int x, int y, int width, int height) } else { - if (drawmode & DRMODE_FG) + if (current_vp->drawmode & DRMODE_FG) { fillopt = OPT_SET; - bits = fg_pattern; + bits = current_vp->fg_pattern; } } - dst = LCDADDR(x, y); + dst = LCDADDR(current_vp->x + x, current_vp->y + y); dst_end = dst + height * LCD_WIDTH; do @@ -530,24 +619,28 @@ void lcd_fillrect(int x, int y, int width, int height) /* Fill a rectangle with a gradient */ void lcd_gradient_rect(int x1, int x2, int y, int h) { + int old_pattern = current_vp->fg_pattern; + if (h == 0) return; - int h_r = RGB_UNPACK_RED(lss_pattern) << 16; - int h_b = RGB_UNPACK_BLUE(lss_pattern) << 16; - int h_g = RGB_UNPACK_GREEN(lss_pattern) << 16; - int rstep = (h_r - ((signed)RGB_UNPACK_RED(lse_pattern) << 16)) / h; - int gstep = (h_g - ((signed)RGB_UNPACK_GREEN(lse_pattern) << 16)) / h; - int bstep = (h_b - ((signed)RGB_UNPACK_BLUE(lse_pattern) << 16)) / h; + int h_r = RGB_UNPACK_RED(current_vp->lss_pattern) << 16; + int h_b = RGB_UNPACK_BLUE(current_vp->lss_pattern) << 16; + int h_g = RGB_UNPACK_GREEN(current_vp->lss_pattern) << 16; + int rstep = (h_r - ((signed)RGB_UNPACK_RED(current_vp->lse_pattern) << 16)) / h; + int gstep = (h_g - ((signed)RGB_UNPACK_GREEN(current_vp->lse_pattern) << 16)) / h; + int bstep = (h_b - ((signed)RGB_UNPACK_BLUE(current_vp->lse_pattern) << 16)) / h; int count; - fg_pattern = lss_pattern; + current_vp->fg_pattern = current_vp->lss_pattern; for(count = 0; count < h; count++) { lcd_hline(x1, x2, y + count); h_r -= rstep; h_g -= gstep; h_b -= bstep; - fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16); + current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16); } + + current_vp->fg_pattern = old_pattern; } #define H_COLOR(lss, lse, cur_line, max_line) \ @@ -562,14 +655,14 @@ void lcd_gradient_rect_scroll(int x1, int x2, int y, int h, { if (h == 0 || num_lines == 0) return; - unsigned tmp_lss = lss_pattern; - unsigned tmp_lse = lse_pattern; - int lss_r = (signed)RGB_UNPACK_RED(lss_pattern); - int lss_b = (signed)RGB_UNPACK_BLUE(lss_pattern); - int lss_g = (signed)RGB_UNPACK_GREEN(lss_pattern); - int lse_r = (signed)RGB_UNPACK_RED(lse_pattern); - int lse_b = (signed)RGB_UNPACK_BLUE(lse_pattern); - int lse_g = (signed)RGB_UNPACK_GREEN(lse_pattern); + unsigned tmp_lss = current_vp->lss_pattern; + unsigned tmp_lse = current_vp->lse_pattern; + int lss_r = (signed)RGB_UNPACK_RED(current_vp->lss_pattern); + int lss_b = (signed)RGB_UNPACK_BLUE(current_vp->lss_pattern); + int lss_g = (signed)RGB_UNPACK_GREEN(current_vp->lss_pattern); + int lse_r = (signed)RGB_UNPACK_RED(current_vp->lse_pattern); + int lse_b = (signed)RGB_UNPACK_BLUE(current_vp->lse_pattern); + int lse_g = (signed)RGB_UNPACK_GREEN(current_vp->lse_pattern); int h_r = H_COLOR(lss_r, lse_r, cur_line, num_lines); int h_g = H_COLOR(lss_g, lse_g, cur_line, num_lines); @@ -583,8 +676,8 @@ void lcd_gradient_rect_scroll(int x1, int x2, int y, int h, lcd_gradient_rect(x1, x2, y, h); - lcd_set_selector_start(tmp_lss); - lcd_set_selector_end(tmp_lse); + current_vp->lss_pattern = tmp_lss; + current_vp->lse_pattern = tmp_lse; } /* About Rockbox' internal monochrome bitmap format: @@ -613,8 +706,8 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, lcd_fastpixelfunc_type *fgfunc, *bgfunc; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -630,20 +723,20 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; src += stride * (src_y >> 3) + src_x; /* move starting point */ src_y &= 7; src_end = src + width; - dst = LCDADDR(x, y); + dst = LCDADDR(current_vp->x + x, current_vp->y + y); has_backdrop = (lcd_backdrop != NULL); - backdrop = lcd_backdrop + y * LCD_WIDTH + x; - fgfunc = lcd_fastpixelfuncs[drawmode]; - bgfunc = lcd_fastpixelfuncs[drawmode ^ DRMODE_INVERSEVID]; + backdrop = lcd_backdrop + (current_vp->y + y) * LCD_WIDTH + current_vp->x + x; + fgfunc = lcd_fastpixelfuncs[current_vp->drawmode]; + bgfunc = lcd_fastpixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID]; do { const unsigned char *src_col = src++; @@ -654,23 +747,23 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, dst_end = dst_col + height * LCD_WIDTH; do { - switch (drawmode) + switch (current_vp->drawmode) { case DRMODE_SOLID: if (data & 0x01) - *dst_col = fg_pattern; + *dst_col = current_vp->fg_pattern; else - *dst_col = has_backdrop ? *backdrop_col : bg_pattern; + *dst_col = has_backdrop ? *backdrop_col : current_vp->bg_pattern; break; case DRMODE_FG: if (data & 0x01) - *dst_col = fg_pattern; + *dst_col = current_vp->fg_pattern; break; case (DRMODE_SOLID|DRMODE_INVERSEVID): if (data & 0x01) - *dst_col = has_backdrop ? *backdrop_col : bg_pattern; + *dst_col = has_backdrop ? *backdrop_col : current_vp->bg_pattern; else - *dst_col = fg_pattern; + *dst_col = current_vp->fg_pattern; break; default: if (data & 0x01) @@ -709,8 +802,8 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y, fb_data *dst, *dst_end; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -726,13 +819,13 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; src += stride * src_y + src_x; /* move starting point */ - dst = LCDADDR(x, y); + dst = LCDADDR(current_vp->x + x, current_vp->y + y); dst_end = dst + height * LCD_WIDTH; do @@ -763,8 +856,8 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, fb_data *dst, *dst_end; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -780,13 +873,13 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; src += stride * src_y + src_x; /* move starting point */ - dst = LCDADDR(x, y); + dst = LCDADDR(current_vp->x + x, current_vp->y + y); dst_end = dst + height * LCD_WIDTH; do @@ -795,7 +888,7 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, for(i = 0;i < width;i++) { if (src[i] == REPLACEWITHFG_COLOR) - dst[i] = fg_pattern; + dst[i] = current_vp->fg_pattern; else if(src[i] != TRANSPARENT_COLOR) dst[i] = src[i]; } @@ -818,11 +911,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) { unsigned short ch; unsigned short *ucs; - struct font* pf = font_get(curfont); + struct font* pf = font_get(current_vp->font); ucs = bidi_l2v(str, 1); - while ((ch = *ucs++) != 0 && x < LCD_WIDTH) + while ((ch = *ucs++) != 0 && x < current_vp->width) { int width; const unsigned char *bits; @@ -875,51 +968,51 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str, int style, int offset) { int xpos,ypos,w,h,xrect; - int lastmode = drawmode; - int oldfgcolor = fg_pattern; - int oldbgcolor = bg_pattern; + int lastmode = current_vp->drawmode; + int oldfgcolor = current_vp->fg_pattern; + int oldbgcolor = current_vp->bg_pattern; /* make sure scrolling is turned off on the line we are updating */ - lcd_scroll_info.lines &= ~(1 << y); + lcd_scroll_stop_line(current_vp, y); if(!str || !str[0]) return; lcd_getstringsize(str, &w, &h); - xpos = xmargin + x*w / utf8length(str); - ypos = ymargin + y*h; - drawmode = (style & STYLE_INVERT) ? + xpos = current_vp->xmargin + x*w / utf8length(str); + ypos = current_vp->ymargin + y*h; + current_vp->drawmode = (style & STYLE_INVERT) ? (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; if (style & STYLE_COLORED) { - if (drawmode == DRMODE_SOLID) - fg_pattern = style & STYLE_COLOR_MASK; + if (current_vp->drawmode == DRMODE_SOLID) + current_vp->fg_pattern = style & STYLE_COLOR_MASK; else - bg_pattern = style & STYLE_COLOR_MASK; + current_vp->bg_pattern = style & STYLE_COLOR_MASK; } - drawmode ^= DRMODE_INVERSEVID; + current_vp->drawmode ^= DRMODE_INVERSEVID; xrect = xpos + MAX(w - offset, 0); if (style & STYLE_GRADIENT) { - drawmode = DRMODE_FG; + current_vp->drawmode = DRMODE_FG; if (CURLN_UNPACK(style) == 0) - lcd_gradient_rect(xpos, LCD_WIDTH, ypos, h*NUMLN_UNPACK(style)); - fg_pattern = lst_pattern; + lcd_gradient_rect(xpos, current_vp->width, ypos, h*NUMLN_UNPACK(style)); + current_vp->fg_pattern = current_vp->lst_pattern; } else if (style & STYLE_COLORBAR) { - drawmode = DRMODE_FG; - fg_pattern = lss_pattern; - lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h); - fg_pattern = lst_pattern; + current_vp->drawmode = DRMODE_FG; + current_vp->fg_pattern = current_vp->lss_pattern; + lcd_fillrect(xpos, ypos, current_vp->width - xpos, h); + current_vp->fg_pattern = current_vp->lst_pattern; } else { - lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); - drawmode = (style & STYLE_INVERT) ? + lcd_fillrect(xrect, ypos, current_vp->width - xrect, h); + current_vp->drawmode = (style & STYLE_INVERT) ? (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; } lcd_putsxyofs(xpos, ypos, offset, str); - drawmode = lastmode; - fg_pattern = oldfgcolor; - bg_pattern = oldbgcolor; + current_vp->drawmode = lastmode; + current_vp->fg_pattern = oldfgcolor; + current_vp->bg_pattern = oldbgcolor; } /*** scrolling ***/ @@ -938,15 +1031,23 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, int offse lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset); } +/* Initialise a scrolling line at (x,y) in current viewport */ + void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, int style, int offset) { struct scrollinfo* s; int w, h; - if(y>=LCD_SCROLLABLE_LINES) return; + if ((unsigned)y >= (unsigned)current_vp->height) + return; + + /* remove any previously scrolling line at the same location */ + lcd_scroll_stop_line(current_vp, y); + + if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return; - s = &lcd_scroll_info.scroll[y]; + s = &lcd_scroll_info.scroll[lcd_scroll_info.lines]; s->start_tick = current_tick + lcd_scroll_info.delay; s->style = style; @@ -954,7 +1055,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, lcd_getstringsize(string, &w, &h); - if (LCD_WIDTH - x * 8 - xmargin < w) { + if (current_vp->width - x * 8 - current_vp->xmargin < w) { /* prepare scroll line */ char *end; @@ -967,7 +1068,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, /* scroll bidirectional or forward only depending on the string width */ if ( lcd_scroll_info.bidir_limit ) { - s->bidir = s->width < (LCD_WIDTH - xmargin) * + s->bidir = s->width < (current_vp->width - current_vp->xmargin) * (100 + lcd_scroll_info.bidir_limit) / 100; } else @@ -980,17 +1081,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, } end = strchr(s->line, '\0'); - strncpy(end, string, LCD_WIDTH/2); + strncpy(end, string, current_vp->width/2); + s->vp = current_vp; + s->y = y; s->len = utf8length(string); s->offset = offset; - s->startx = xmargin + x * s->width / s->len; + s->startx = current_vp->xmargin + x * s->width / s->len; s->backward = false; - lcd_scroll_info.lines |= (1<start_tick)) continue; + lcd_set_viewport(s->vp); + old_fgcolor = current_vp->fg_pattern; + old_bgcolor = current_vp->bg_pattern; + if (s->style&STYLE_COLORED) { if (s->style&STYLE_MODE_MASK) { - fg_pattern = old_fgcolor; - bg_pattern = s->style&STYLE_COLOR_MASK; + current_vp->fg_pattern = old_fgcolor; + current_vp->bg_pattern = s->style&STYLE_COLOR_MASK; } else { - fg_pattern = s->style&STYLE_COLOR_MASK; - bg_pattern = old_bgcolor; + current_vp->fg_pattern = s->style&STYLE_COLOR_MASK; + current_vp->bg_pattern = old_bgcolor; } } @@ -1030,9 +1131,9 @@ void lcd_scroll_fn(void) else s->offset += lcd_scroll_info.step; - pf = font_get(curfont); + pf = font_get(current_vp->font); xpos = s->startx; - ypos = ymargin + index * pf->height; + ypos = current_vp->ymargin + s->y * pf->height; if (s->bidir) { /* scroll bidirectional */ if (s->offset <= 0) { @@ -1041,9 +1142,9 @@ void lcd_scroll_fn(void) s->backward = false; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } - if (s->offset >= s->width - (LCD_WIDTH - xpos)) { + if (s->offset >= s->width - (current_vp->width - xpos)) { /* at end of line */ - s->offset = s->width - (LCD_WIDTH - xpos); + s->offset = s->width - (current_vp->width - xpos); s->backward = true; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } @@ -1054,35 +1155,36 @@ void lcd_scroll_fn(void) s->offset %= s->width; } - lastmode = drawmode; + lastmode = current_vp->drawmode; switch (s->style&STYLE_MODE_MASK) { case STYLE_INVERT: - drawmode = DRMODE_SOLID|DRMODE_INVERSEVID; + current_vp->drawmode = DRMODE_SOLID|DRMODE_INVERSEVID; break; case STYLE_COLORBAR: /* Solid colour line selector */ - drawmode = DRMODE_FG; - fg_pattern = lss_pattern; - lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); - fg_pattern = lst_pattern; + current_vp->drawmode = DRMODE_FG; + current_vp->fg_pattern = current_vp->lss_pattern; + lcd_fillrect(xpos, ypos, current_vp->width - xpos, pf->height); + current_vp->fg_pattern = current_vp->lst_pattern; break; case STYLE_GRADIENT: /* Gradient line selector */ - drawmode = DRMODE_FG; - lcd_gradient_rect_scroll(xpos, LCD_WIDTH, ypos, (signed)pf->height, + current_vp->drawmode = DRMODE_FG; + lcd_gradient_rect_scroll(xpos, current_vp->width, ypos, (signed)pf->height, NUMLN_UNPACK(s->style), CURLN_UNPACK(s->style)); - fg_pattern = lst_pattern; + current_vp->fg_pattern = current_vp->lst_pattern; break; default: - drawmode = DRMODE_SOLID; + current_vp->drawmode = DRMODE_SOLID; break; } lcd_putsxyofs(xpos, ypos, s->offset, s->line); - drawmode = lastmode; - lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); + current_vp->drawmode = lastmode; + current_vp->fg_pattern = old_fgcolor; + current_vp->bg_pattern = old_bgcolor; + lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height); } - fg_pattern = old_fgcolor; - bg_pattern = old_bgcolor; + lcd_set_viewport(old_vp); } diff --git a/firmware/drivers/lcd-1bit-vert.c b/firmware/drivers/lcd-1bit-vert.c index bd62e105cb..5c651a9613 100644 --- a/firmware/drivers/lcd-1bit-vert.c +++ b/firmware/drivers/lcd-1bit-vert.c @@ -35,10 +35,40 @@ unsigned char lcd_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH]; -static int drawmode = DRMODE_SOLID; -static int xmargin = 0; -static int ymargin = 0; -static int curfont = FONT_SYSFIXED; +static struct viewport default_vp = +{ + .x = 0, + .y = 0, + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, +}; + +static struct viewport* current_vp = &default_vp; + +/*** Viewports ***/ + +void lcd_set_viewport(struct viewport* vp) +{ + if (vp == NULL) + current_vp = &default_vp; + else + current_vp = vp; +} + +void lcd_update_viewport(void) +{ + lcd_update_rect(current_vp->x, current_vp->y, + current_vp->width, current_vp->height); +} + +void lcd_update_viewport_rect(int x, int y, int width, int height) +{ + lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height); +} /* LCD init */ void lcd_init(void) @@ -53,38 +83,48 @@ void lcd_init(void) void lcd_set_drawmode(int mode) { - drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); + current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } int lcd_get_drawmode(void) { - return drawmode; + return current_vp->drawmode; } void lcd_setmargins(int x, int y) { - xmargin = x; - ymargin = y; + current_vp->xmargin = x; + current_vp->ymargin = y; } int lcd_getxmargin(void) { - return xmargin; + return current_vp->xmargin; } int lcd_getymargin(void) { - return ymargin; + return current_vp->ymargin; +} + +int lcd_getwidth(void) +{ + return current_vp->width; +} + +int lcd_getheight(void) +{ + return current_vp->height; } void lcd_setfont(int newfont) { - curfont = newfont; + current_vp->font = newfont; } int lcd_getstringsize(const unsigned char *str, int *w, int *h) { - return font_getstringsize(str, w, h, curfont); + return font_getstringsize(str, w, h, current_vp->font); } /*** low-level drawing functions ***/ @@ -187,17 +227,42 @@ lcd_blockfunc_type* const lcd_blockfuncs[8] = { /* Clear the whole display */ void lcd_clear_display(void) { - unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; + unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; memset(lcd_framebuffer, bits, sizeof lcd_framebuffer); lcd_scroll_info.lines = 0; } +void lcd_clear_viewport(void) +{ + int oldmode; + + if (current_vp == &default_vp) + { + lcd_clear_display(); + } + else + { + oldmode = current_vp->drawmode; + + /* Invert the INVERSEVID bit and set basic mode to SOLID */ + current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) | + DRMODE_SOLID; + + lcd_fillrect(0, 0, current_vp->width, current_vp->height); + + current_vp->drawmode = oldmode; + + lcd_scroll_stop(current_vp); + } +} + /* Set a single pixel */ void lcd_drawpixel(int x, int y) { - if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) - lcd_pixelfuncs[drawmode](x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y); } /* Draw a line */ @@ -209,7 +274,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2) int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; - lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; + lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode]; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -253,8 +318,9 @@ void lcd_drawline(int x1, int y1, int x2, int y2) for (i = 0; i < numpixels; i++) { - if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) - pfunc(x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + pfunc(current_vp->x + x, current_vp->y + y); if (d < 0) { @@ -288,16 +354,22 @@ void lcd_hline(int x1, int x2, int y) } /* nothing to draw? */ - if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) + if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) + || (x2 < 0)) return; /* clipping */ if (x1 < 0) x1 = 0; - if (x2 >= LCD_WIDTH) - x2 = LCD_WIDTH-1; + if (x2 >= current_vp->width) + x2 = current_vp->width-1; - bfunc = lcd_blockfuncs[drawmode]; + /* adjust for viewport */ + y += current_vp->y; + x1 += current_vp->x; + x2 += current_vp->x; + + bfunc = lcd_blockfuncs[current_vp->drawmode]; dst = &lcd_framebuffer[y>>3][x1]; mask = 1 << (y & 7); @@ -324,16 +396,22 @@ void lcd_vline(int x, int y1, int y2) } /* nothing to draw? */ - if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) + if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) + || (y2 < 0)) return; /* clipping */ if (y1 < 0) y1 = 0; - if (y2 >= LCD_HEIGHT) - y2 = LCD_HEIGHT-1; + if (y2 >= current_vp->height) + y2 = current_vp->height-1; - bfunc = lcd_blockfuncs[drawmode]; + /* adjust for viewport */ + y1 += current_vp->y; + y2 += current_vp->y; + x += current_vp->x; + + bfunc = lcd_blockfuncs[current_vp->drawmode]; dst = &lcd_framebuffer[y1>>3][x]; ny = y2 - (y1 & ~7); mask = 0xFFu << (y1 & 7); @@ -375,8 +453,8 @@ void lcd_fillrect(int x, int y, int width, int height) bool fillopt = false; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) + || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -390,27 +468,31 @@ void lcd_fillrect(int x, int y, int width, int height) height += y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; - if (drawmode & DRMODE_INVERSEVID) + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + + if (current_vp->drawmode & DRMODE_INVERSEVID) { - if (drawmode & DRMODE_BG) + if (current_vp->drawmode & DRMODE_BG) { fillopt = true; } } else { - if (drawmode & DRMODE_FG) + if (current_vp->drawmode & DRMODE_FG) { fillopt = true; bits = 0xFFu; } } - bfunc = lcd_blockfuncs[drawmode]; + bfunc = lcd_blockfuncs[current_vp->drawmode]; dst = &lcd_framebuffer[y>>3][x]; ny = height - 1 + (y & 7); mask = 0xFFu << (y & 7); @@ -470,8 +552,8 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, lcd_blockfunc_type *bfunc; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) + || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -487,10 +569,14 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; src += stride * (src_y >> 3) + src_x; /* move starting point */ src_y &= 7; @@ -499,13 +585,13 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, shift = y & 7; ny = height - 1 + shift + src_y; - bfunc = lcd_blockfuncs[drawmode]; + bfunc = lcd_blockfuncs[current_vp->drawmode]; mask = 0xFFu << (shift + src_y); mask_bottom = 0xFFu >> (~ny & 7); if (shift == 0) { - bool copyopt = (drawmode == DRMODE_SOLID); + bool copyopt = (current_vp->drawmode == DRMODE_SOLID); for (; ny >= 8; ny -= 8) { @@ -582,11 +668,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) { unsigned short ch; unsigned short *ucs; - struct font* pf = font_get(curfont); + struct font* pf = font_get(current_vp->font); ucs = bidi_l2v(str, 1); - while ((ch = *ucs++) != 0 && x < LCD_WIDTH) + while ((ch = *ucs++) != 0 && x < current_vp->width) { int width; const unsigned char *bits; @@ -639,24 +725,24 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str, int style, int offset) { int xpos,ypos,w,h,xrect; - int lastmode = drawmode; + int lastmode = current_vp->drawmode; /* make sure scrolling is turned off on the line we are updating */ - lcd_scroll_info.lines &= ~(1 << y); + lcd_scroll_stop_line(current_vp, y); if(!str || !str[0]) return; lcd_getstringsize(str, &w, &h); - xpos = xmargin + x*w / utf8length(str); - ypos = ymargin + y*h; - drawmode = (style & STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + xpos = current_vp->xmargin + x*w / utf8length(str); + ypos = current_vp->ymargin + y*h; + current_vp->drawmode = (style & STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_putsxyofs(xpos, ypos, offset, str); - drawmode ^= DRMODE_INVERSEVID; + current_vp->drawmode ^= DRMODE_INVERSEVID; xrect = xpos + MAX(w - offset, 0); - lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); - drawmode = lastmode; + lcd_fillrect(xrect, ypos, current_vp->width - xrect, h); + current_vp->drawmode = lastmode; } /*** scrolling ***/ @@ -682,9 +768,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, struct scrollinfo* s; int w, h; - if(y>=LCD_SCROLLABLE_LINES) return; + if ((unsigned)y >= (unsigned)current_vp->height) + return; + + /* remove any previously scrolling line at the same location */ + lcd_scroll_stop_line(current_vp, y); + + if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return; - s = &lcd_scroll_info.scroll[y]; + s = &lcd_scroll_info.scroll[lcd_scroll_info.lines]; s->start_tick = current_tick + lcd_scroll_info.delay; s->style = style; @@ -696,7 +788,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, lcd_getstringsize(string, &w, &h); - if (LCD_WIDTH - x * 8 - xmargin < w) { + if (current_vp->width - x * 8 - current_vp->xmargin < w) { /* prepare scroll line */ char *end; @@ -709,7 +801,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, /* scroll bidirectional or forward only depending on the string width */ if ( lcd_scroll_info.bidir_limit ) { - s->bidir = s->width < (LCD_WIDTH - xmargin) * + s->bidir = s->width < (current_vp->width - current_vp->xmargin) * (100 + lcd_scroll_info.bidir_limit) / 100; } else @@ -722,17 +814,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, } end = strchr(s->line, '\0'); - strncpy(end, string, LCD_WIDTH/2); + strncpy(end, string, current_vp->width/2); + s->vp = current_vp; + s->y = y; s->len = utf8length(string); s->offset = offset; - s->startx = xmargin + x * s->width / s->len;; + s->startx = current_vp->xmargin + x * s->width / s->len;; s->backward = false; - lcd_scroll_info.lines |= (1<start_tick)) continue; + lcd_set_viewport(s->vp); + if (s->backward) s->offset -= lcd_scroll_info.step; else s->offset += lcd_scroll_info.step; - pf = font_get(curfont); + pf = font_get(current_vp->font); xpos = s->startx; - ypos = ymargin + index * pf->height; + ypos = current_vp->ymargin + s->y * pf->height; if (s->bidir) { /* scroll bidirectional */ if (s->offset <= 0) { @@ -770,9 +860,9 @@ void lcd_scroll_fn(void) s->backward = false; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } - if (s->offset >= s->width - (LCD_WIDTH - xpos)) { + if (s->offset >= s->width - (current_vp->width - xpos)) { /* at end of line */ - s->offset = s->width - (LCD_WIDTH - xpos); + s->offset = s->width - (current_vp->width - xpos); s->backward = true; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } @@ -783,11 +873,13 @@ void lcd_scroll_fn(void) s->offset %= s->width; } - lastmode = drawmode; - drawmode = (s->style&STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + lastmode = current_vp->drawmode; + current_vp->drawmode = (s->style&STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_putsxyofs(xpos, ypos, s->offset, s->line); - drawmode = lastmode; - lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); + current_vp->drawmode = lastmode; + lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height); } + + lcd_set_viewport(old_vp); } diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c index 32ebfa7f81..1ee0addba4 100644 --- a/firmware/drivers/lcd-2bit-horz.c +++ b/firmware/drivers/lcd-2bit-horz.c @@ -46,52 +46,92 @@ static const unsigned char pixmask[4] ICONST_ATTR = { static fb_data* lcd_backdrop = NULL; static long lcd_backdrop_offset IDATA_ATTR = 0; -static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ -static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ -static int drawmode = DRMODE_SOLID; -static int xmargin = 0; -static int ymargin = 0; -static int curfont = FONT_SYSFIXED; +static struct viewport default_vp = +{ + .x = 0, + .y = 0, + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, + .fg_pattern = LCD_DEFAULT_FG, + .bg_pattern = LCD_DEFAULT_BG +}; + +static struct viewport* current_vp IBSS_ATTR; +static unsigned fg_pattern IBSS_ATTR; +static unsigned bg_pattern IBSS_ATTR; /* LCD init */ void lcd_init(void) { + /* Initialise the viewport */ + lcd_set_viewport(NULL); + lcd_clear_display(); /* Call device specific init */ lcd_init_device(); scroll_init(); } +/*** Viewports ***/ + +void lcd_set_viewport(struct viewport* vp) +{ + if (vp == NULL) + current_vp = &default_vp; + else + current_vp = vp; + + fg_pattern = 0x55 * (~current_vp->fg_pattern & 3); + bg_pattern = 0x55 * (~current_vp->bg_pattern & 3); +} + +void lcd_update_viewport(void) +{ + lcd_update_rect(current_vp->x, current_vp->y, + current_vp->width, current_vp->height); +} + +void lcd_update_viewport_rect(int x, int y, int width, int height) +{ + lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height); +} + /*** parameter handling ***/ void lcd_set_drawmode(int mode) { - drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); + current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } int lcd_get_drawmode(void) { - return drawmode; + return current_vp->drawmode; } void lcd_set_foreground(unsigned brightness) { + current_vp->fg_pattern = brightness; fg_pattern = 0x55 * (~brightness & 3); } unsigned lcd_get_foreground(void) { - return ~fg_pattern & 3; + return current_vp->fg_pattern; } void lcd_set_background(unsigned brightness) { + current_vp->bg_pattern = brightness; bg_pattern = 0x55 * (~brightness & 3); } unsigned lcd_get_background(void) { - return ~bg_pattern & 3; + return current_vp->bg_pattern; } void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness) @@ -103,28 +143,38 @@ void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness) void lcd_setmargins(int x, int y) { - xmargin = x; - ymargin = y; + current_vp->xmargin = x; + current_vp->ymargin = y; } int lcd_getxmargin(void) { - return xmargin; + return current_vp->xmargin; } int lcd_getymargin(void) { - return ymargin; + return current_vp->ymargin; +} + +int lcd_getwidth(void) +{ + return current_vp->width; +} + +int lcd_getheight(void) +{ + return current_vp->height; } void lcd_setfont(int newfont) { - curfont = newfont; + current_vp->font = newfont; } int lcd_getstringsize(const unsigned char *str, int *w, int *h) { - return font_getstringsize(str, w, h, curfont); + return font_getstringsize(str, w, h, current_vp->font); } /*** low-level drawing functions ***/ @@ -345,7 +395,7 @@ static inline void setblock(fb_data *address, unsigned mask, unsigned bits) /* Clear the whole display */ void lcd_clear_display(void) { - if (drawmode & DRMODE_INVERSEVID) + if (current_vp->drawmode & DRMODE_INVERSEVID) { memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer); } @@ -360,11 +410,37 @@ void lcd_clear_display(void) lcd_scroll_info.lines = 0; } +/* Clear the current viewport */ +void lcd_clear_viewport(void) +{ + int lastmode; + + if (current_vp == &default_vp) + { + lcd_clear_display(); + } + else + { + lastmode = current_vp->drawmode; + + /* Invert the INVERSEVID bit and set basic mode to SOLID */ + current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) | + DRMODE_SOLID; + + lcd_fillrect(0, 0, current_vp->width, current_vp->height); + + current_vp->drawmode = lastmode; + + lcd_scroll_stop(current_vp); + } +} + /* Set a single pixel */ void lcd_drawpixel(int x, int y) { - if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) - lcd_pixelfuncs[drawmode](x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y); } /* Draw a line */ @@ -376,7 +452,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2) int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; - lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; + lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode]; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -420,8 +496,9 @@ void lcd_drawline(int x1, int y1, int x2, int y2) for (i = 0; i < numpixels; i++) { - if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) - pfunc(x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + pfunc(current_vp->x + x, current_vp->y + y); if (d < 0) { @@ -455,16 +532,22 @@ void lcd_hline(int x1, int x2, int y) } /* nothing to draw? */ - if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) + if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) + || (x2 < 0)) return; /* clipping */ if (x1 < 0) x1 = 0; - if (x2 >= LCD_WIDTH) - x2 = LCD_WIDTH-1; + if (x2 >= current_vp->width) + x2 = current_vp->width-1; - bfunc = lcd_blockfuncs[drawmode]; + /* adjust to viewport */ + x1 += current_vp->x; + x2 += current_vp->x; + y += current_vp->y; + + bfunc = lcd_blockfuncs[current_vp->drawmode]; dst = &lcd_framebuffer[y][x1>>2]; nx = x2 - (x1 & ~3); mask = 0xFFu >> (2 * (x1 & 3)); @@ -496,16 +579,22 @@ void lcd_vline(int x, int y1, int y2) } /* nothing to draw? */ - if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) + if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) + || (y2 < 0)) return; /* clipping */ if (y1 < 0) y1 = 0; - if (y2 >= LCD_HEIGHT) - y2 = LCD_HEIGHT-1; + if (y2 >= current_vp->height) + y2 = current_vp->height-1; + + /* adjust for viewport */ + y1 += current_vp->y; + y2 += current_vp->y; + x += current_vp->x; - bfunc = lcd_blockfuncs[drawmode]; + bfunc = lcd_blockfuncs[current_vp->drawmode]; dst = &lcd_framebuffer[y1][x>>2]; mask = pixmask[x & 3]; @@ -542,7 +631,7 @@ void lcd_fillrect(int x, int y, int width, int height) lcd_blockfunc_type *bfunc; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; @@ -557,12 +646,16 @@ void lcd_fillrect(int x, int y, int width, int height) height += y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; - bfunc = lcd_blockfuncs[drawmode]; + bfunc = lcd_blockfuncs[current_vp->drawmode]; dst = &lcd_framebuffer[y][x>>2]; nx = width - 1 + (x & 3); mask = 0xFFu >> (2 * (x & 3)); @@ -616,8 +709,8 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, lcd_pixelfunc_type* bgfunc; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -633,17 +726,21 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; src += stride * (src_y >> 3) + src_x; /* move starting point */ src_y &= 7; src_end = src + width; - fgfunc = lcd_pixelfuncs[drawmode]; - bgfunc = lcd_pixelfuncs[drawmode ^ DRMODE_INVERSEVID]; + fgfunc = lcd_pixelfuncs[current_vp->drawmode]; + bgfunc = lcd_pixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID]; nx = x; do { @@ -704,8 +801,8 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, unsigned mask, mask_right; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -721,10 +818,14 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; stride = (stride + 3) >> 2; /* convert to no. of bytes */ @@ -781,11 +882,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) { unsigned short ch; unsigned short *ucs; - struct font* pf = font_get(curfont); + struct font* pf = font_get(current_vp->font); ucs = bidi_l2v(str, 1); - while ((ch = *ucs++) != 0 && x < LCD_WIDTH) + while ((ch = *ucs++) != 0 && x < current_vp->width) { int width; const unsigned char *bits; @@ -839,24 +940,24 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str, int style, int offset) { int xpos,ypos,w,h,xrect; - int lastmode = drawmode; + int lastmode = current_vp->drawmode; /* make sure scrolling is turned off on the line we are updating */ - lcd_scroll_info.lines &= ~(1 << y); + lcd_scroll_stop_line(current_vp, y); if(!str || !str[0]) return; lcd_getstringsize(str, &w, &h); - xpos = xmargin + x*w / utf8length((char *)str); - ypos = ymargin + y*h; - drawmode = (style & STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + xpos = current_vp->xmargin + x*w / utf8length((char *)str); + ypos = current_vp->ymargin + y*h; + current_vp->drawmode = (style & STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_putsxyofs(xpos, ypos, offset, str); - drawmode ^= DRMODE_INVERSEVID; + current_vp->drawmode ^= DRMODE_INVERSEVID; xrect = xpos + MAX(w - offset, 0); - lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); - drawmode = lastmode; + lcd_fillrect(xrect, ypos, current_vp->width - xrect, h); + current_vp->drawmode = lastmode; } /*** scrolling ***/ @@ -881,9 +982,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, struct scrollinfo* s; int w, h; - if(y>=LCD_SCROLLABLE_LINES) return; + if ((unsigned)y >= (unsigned)current_vp->height) + return; + + /* remove any previously scrolling line at the same location */ + lcd_scroll_stop_line(current_vp, y); - s = &lcd_scroll_info.scroll[y]; + if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return; + + s = &lcd_scroll_info.scroll[lcd_scroll_info.lines]; s->start_tick = current_tick + lcd_scroll_info.delay; s->style = style; @@ -895,7 +1002,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, lcd_getstringsize(string, &w, &h); - if (LCD_WIDTH - x * 8 - xmargin < w) { + if (current_vp->width - x * 8 - current_vp->xmargin < w) { /* prepare scroll line */ char *end; @@ -908,7 +1015,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, /* scroll bidirectional or forward only depending on the string width */ if ( lcd_scroll_info.bidir_limit ) { - s->bidir = s->width < (LCD_WIDTH - xmargin) * + s->bidir = s->width < (current_vp->width - current_vp->xmargin) * (100 + lcd_scroll_info.bidir_limit) / 100; } else @@ -921,17 +1028,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, } end = strchr(s->line, '\0'); - strncpy(end, (char *)string, LCD_WIDTH/2); + strncpy(end, (char *)string, current_vp->width/2); + s->vp = current_vp; + s->y = y; s->len = utf8length((char *)string); s->offset = offset; - s->startx = xmargin + x * s->width / s->len;; + s->startx = current_vp->xmargin + x * s->width / s->len;; s->backward = false; - lcd_scroll_info.lines |= (1<start_tick)) continue; + lcd_set_viewport(s->vp); + if (s->backward) s->offset -= lcd_scroll_info.step; else s->offset += lcd_scroll_info.step; - pf = font_get(curfont); + pf = font_get(current_vp->font); xpos = s->startx; - ypos = ymargin + index * pf->height; + ypos = current_vp->ymargin + s->y * pf->height; if (s->bidir) { /* scroll bidirectional */ if (s->offset <= 0) { @@ -969,9 +1074,9 @@ void lcd_scroll_fn(void) s->backward = false; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } - if (s->offset >= s->width - (LCD_WIDTH - xpos)) { + if (s->offset >= s->width - (current_vp->width - xpos)) { /* at end of line */ - s->offset = s->width - (LCD_WIDTH - xpos); + s->offset = s->width - (current_vp->width - xpos); s->backward = true; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } @@ -982,11 +1087,13 @@ void lcd_scroll_fn(void) s->offset %= s->width; } - lastmode = drawmode; - drawmode = (s->style&STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + lastmode = current_vp->drawmode; + current_vp->drawmode = (s->style&STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_putsxyofs(xpos, ypos, s->offset, s->line); - drawmode = lastmode; - lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); + current_vp->drawmode = lastmode; + lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height); } + + lcd_set_viewport(old_vp); } diff --git a/firmware/drivers/lcd-2bit-vert.c b/firmware/drivers/lcd-2bit-vert.c index aa3cd2cc3b..2341ddb3df 100644 --- a/firmware/drivers/lcd-2bit-vert.c +++ b/firmware/drivers/lcd-2bit-vert.c @@ -48,52 +48,93 @@ static const unsigned char pixmask[4] ICONST_ATTR = { static fb_data* lcd_backdrop = NULL; static long lcd_backdrop_offset IDATA_ATTR = 0; -static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ -static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ -static int drawmode = DRMODE_SOLID; -static int xmargin = 0; -static int ymargin = 0; -static int curfont = FONT_SYSFIXED; +static struct viewport default_vp = +{ + .x = 0, + .y = 0, + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, + .fg_pattern = LCD_DEFAULT_FG, + .bg_pattern = LCD_DEFAULT_BG +}; + +static struct viewport* current_vp IBSS_ATTR; +static unsigned fg_pattern IBSS_ATTR; +static unsigned bg_pattern IBSS_ATTR; /* LCD init */ void lcd_init(void) { + /* Initialise the viewport */ + lcd_set_viewport(NULL); + lcd_clear_display(); /* Call device specific init */ lcd_init_device(); scroll_init(); } +/*** Viewports ***/ + +void lcd_set_viewport(struct viewport* vp) +{ + if (vp == NULL) + current_vp = &default_vp; + else + current_vp = vp; + + fg_pattern = 0x55 * (~current_vp->fg_pattern & 3); + bg_pattern = 0x55 * (~current_vp->bg_pattern & 3); +} + +void lcd_update_viewport(void) +{ + lcd_update_rect(current_vp->x, current_vp->y, + current_vp->width, current_vp->height); +} + +void lcd_update_viewport_rect(int x, int y, int width, int height) +{ + lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height); +} + + /*** parameter handling ***/ void lcd_set_drawmode(int mode) { - drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); + current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } int lcd_get_drawmode(void) { - return drawmode; + return current_vp->drawmode; } void lcd_set_foreground(unsigned brightness) { + current_vp->fg_pattern = brightness; fg_pattern = 0x55 * (~brightness & 3); } unsigned lcd_get_foreground(void) { - return ~fg_pattern & 3; + return current_vp->fg_pattern; } void lcd_set_background(unsigned brightness) { + current_vp->fg_pattern = brightness; bg_pattern = 0x55 * (~brightness & 3); } unsigned lcd_get_background(void) { - return ~bg_pattern & 3; + return current_vp->bg_pattern; } void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness) @@ -105,28 +146,38 @@ void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness) void lcd_setmargins(int x, int y) { - xmargin = x; - ymargin = y; + current_vp->xmargin = x; + current_vp->ymargin = y; } int lcd_getxmargin(void) { - return xmargin; + return current_vp->xmargin; } int lcd_getymargin(void) { - return ymargin; + return current_vp->ymargin; +} + +int lcd_getwidth(void) +{ + return current_vp->width; +} + +int lcd_getheight(void) +{ + return current_vp->height; } void lcd_setfont(int newfont) { - curfont = newfont; + current_vp->font = newfont; } int lcd_getstringsize(const unsigned char *str, int *w, int *h) { - return font_getstringsize(str, w, h, curfont); + return font_getstringsize(str, w, h, current_vp->font); } /*** low-level drawing functions ***/ @@ -347,7 +398,7 @@ static inline void setblock(fb_data *address, unsigned mask, unsigned bits) /* Clear the whole display */ void lcd_clear_display(void) { - if (drawmode & DRMODE_INVERSEVID) + if (current_vp->drawmode & DRMODE_INVERSEVID) { memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer); } @@ -362,11 +413,37 @@ void lcd_clear_display(void) lcd_scroll_info.lines = 0; } +/* Clear the current viewport */ +void lcd_clear_viewport(void) +{ + int lastmode; + + if (current_vp == &default_vp) + { + lcd_clear_display(); + } + else + { + lastmode = current_vp->drawmode; + + /* Invert the INVERSEVID bit and set basic mode to SOLID */ + current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) | + DRMODE_SOLID; + + lcd_fillrect(0, 0, current_vp->width, current_vp->height); + + current_vp->drawmode = lastmode; + + lcd_scroll_stop(current_vp); + } +} + /* Set a single pixel */ void lcd_drawpixel(int x, int y) { - if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) - lcd_pixelfuncs[drawmode](x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y); } /* Draw a line */ @@ -378,7 +455,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2) int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; - lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; + lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode]; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -422,8 +499,9 @@ void lcd_drawline(int x1, int y1, int x2, int y2) for (i = 0; i < numpixels; i++) { - if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) - pfunc(x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + pfunc(current_vp->x + x, current_vp->y + y); if (d < 0) { @@ -444,6 +522,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2) void lcd_hline(int x1, int x2, int y) { int x; + int width; fb_data *dst, *dst_end; unsigned mask; lcd_blockfunc_type *bfunc; @@ -457,23 +536,30 @@ void lcd_hline(int x1, int x2, int y) } /* nothing to draw? */ - if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) + if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) + || (x2 < 0)) return; /* clipping */ if (x1 < 0) x1 = 0; - if (x2 >= LCD_WIDTH) - x2 = LCD_WIDTH-1; - - bfunc = lcd_blockfuncs[drawmode]; + if (x2 >= current_vp->width) + x2 = current_vp->width-1; + + width = x2 - x1 + 1; + + /* adjust x1 and y to viewport */ + x1 += current_vp->x; + y += current_vp->y; + + bfunc = lcd_blockfuncs[current_vp->drawmode]; dst = &lcd_framebuffer[y>>2][x1]; mask = pixmask[y & 3]; - dst_end = dst + x2 - x1; + dst_end = dst + width; do bfunc(dst++, mask, 0xFFu); - while (dst <= dst_end); + while (dst < dst_end); } /* Draw a vertical line (optimised) */ @@ -493,16 +579,22 @@ void lcd_vline(int x, int y1, int y2) } /* nothing to draw? */ - if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) + if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) + || (y2 < 0)) return; /* clipping */ if (y1 < 0) y1 = 0; - if (y2 >= LCD_HEIGHT) - y2 = LCD_HEIGHT-1; + if (y2 >= current_vp->height) + y2 = current_vp->height-1; - bfunc = lcd_blockfuncs[drawmode]; + /* adjust for viewport */ + y1 += current_vp->y; + y2 += current_vp->y; + x += current_vp->x; + + bfunc = lcd_blockfuncs[current_vp->drawmode]; dst = &lcd_framebuffer[y1>>2][x]; ny = y2 - (y1 & ~3); mask = 0xFFu << (2 * (y1 & 3)); @@ -544,8 +636,8 @@ void lcd_fillrect(int x, int y, int width, int height) bool fillopt = false; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) + || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -559,14 +651,18 @@ void lcd_fillrect(int x, int y, int width, int height) height += y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; - if (drawmode & DRMODE_INVERSEVID) + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + + if (current_vp->drawmode & DRMODE_INVERSEVID) { - if ((drawmode & DRMODE_BG) && !lcd_backdrop) + if ((current_vp->drawmode & DRMODE_BG) && !lcd_backdrop) { fillopt = true; bits = bg_pattern; @@ -574,13 +670,13 @@ void lcd_fillrect(int x, int y, int width, int height) } else { - if (drawmode & DRMODE_FG) + if (current_vp->drawmode & DRMODE_FG) { fillopt = true; bits = fg_pattern; } } - bfunc = lcd_blockfuncs[drawmode]; + bfunc = lcd_blockfuncs[current_vp->drawmode]; dst = &lcd_framebuffer[y>>2][x]; ny = height - 1 + (y & 3); mask = 0xFFu << (2 * (y & 3)); @@ -640,8 +736,8 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, lcd_blockfunc_type *bfunc; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -657,10 +753,14 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; src += stride * (src_y >> 3) + src_x; /* move starting point */ src_y &= 7; @@ -669,7 +769,7 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, shift = y & 3; ny = height - 1 + shift + src_y; - bfunc = lcd_blockfuncs[drawmode]; + bfunc = lcd_blockfuncs[current_vp->drawmode]; mask = 0xFFu << (shift + src_y); mask_bottom = 0xFFu >> (~ny & 7); @@ -807,8 +907,8 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y, unsigned mask, mask_bottom; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) + || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -824,10 +924,14 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; src += stride * (src_y >> 2) + src_x; /* move starting point */ src_y &= 3; @@ -916,11 +1020,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) { unsigned short ch; unsigned short *ucs; - struct font* pf = font_get(curfont); + struct font* pf = font_get(current_vp->font); ucs = bidi_l2v(str, 1); - while ((ch = *ucs++) != 0 && x < LCD_WIDTH) + while ((ch = *ucs++) != 0 && x < current_vp->width) { int width; const unsigned char *bits; @@ -974,24 +1078,24 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str, int style, int offset) { int xpos,ypos,w,h,xrect; - int lastmode = drawmode; + int lastmode = current_vp->drawmode; /* make sure scrolling is turned off on the line we are updating */ - lcd_scroll_info.lines &= ~(1 << y); + lcd_scroll_stop_line(current_vp, y); if(!str || !str[0]) return; lcd_getstringsize(str, &w, &h); - xpos = xmargin + x*w / utf8length((char *)str); - ypos = ymargin + y*h; - drawmode = (style & STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + xpos = current_vp->xmargin + x*w / utf8length((char *)str); + ypos = current_vp->ymargin + y*h; + current_vp->drawmode = (style & STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_putsxyofs(xpos, ypos, offset, str); - drawmode ^= DRMODE_INVERSEVID; + current_vp->drawmode ^= DRMODE_INVERSEVID; xrect = xpos + MAX(w - offset, 0); - lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); - drawmode = lastmode; + lcd_fillrect(xrect, ypos, current_vp->width - xrect, h); + current_vp->drawmode = lastmode; } /*** scrolling ***/ @@ -1017,9 +1121,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, struct scrollinfo* s; int w, h; - if(y>=LCD_SCROLLABLE_LINES) return; + if ((unsigned)y >= (unsigned)current_vp->height) + return; + + /* remove any previously scrolling line at the same location */ + lcd_scroll_stop_line(current_vp, y); + + if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return; - s = &lcd_scroll_info.scroll[y]; + s = &lcd_scroll_info.scroll[lcd_scroll_info.lines]; s->start_tick = current_tick + lcd_scroll_info.delay; s->style = style; @@ -1031,7 +1141,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, lcd_getstringsize(string, &w, &h); - if (LCD_WIDTH - x * 8 - xmargin < w) { + if (current_vp->width - x * 8 - current_vp->xmargin < w) { /* prepare scroll line */ char *end; @@ -1044,7 +1154,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, /* scroll bidirectional or forward only depending on the string width */ if ( lcd_scroll_info.bidir_limit ) { - s->bidir = s->width < (LCD_WIDTH - xmargin) * + s->bidir = s->width < (current_vp->width - current_vp->xmargin) * (100 + lcd_scroll_info.bidir_limit) / 100; } else @@ -1057,17 +1167,17 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, } end = strchr(s->line, '\0'); - strncpy(end, (char *)string, LCD_WIDTH/2); + strncpy(end, (char *)string, current_vp->width/2); + s->vp = current_vp; + s->y = y; s->len = utf8length((char *)string); s->offset = offset; - s->startx = xmargin + x * s->width / s->len; + s->startx = current_vp->xmargin + x * s->width / s->len; s->backward = false; - lcd_scroll_info.lines |= (1<start_tick)) continue; + lcd_set_viewport(s->vp); + if (s->backward) s->offset -= lcd_scroll_info.step; else s->offset += lcd_scroll_info.step; - pf = font_get(curfont); + pf = font_get(current_vp->font); xpos = s->startx; - ypos = ymargin + index * pf->height; + ypos = current_vp->ymargin + s->y * pf->height; if (s->bidir) { /* scroll bidirectional */ if (s->offset <= 0) { @@ -1105,9 +1214,9 @@ void lcd_scroll_fn(void) s->backward = false; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } - if (s->offset >= s->width - (LCD_WIDTH - xpos)) { + if (s->offset >= s->width - (current_vp->width - xpos)) { /* at end of line */ - s->offset = s->width - (LCD_WIDTH - xpos); + s->offset = s->width - (current_vp->width - xpos); s->backward = true; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } @@ -1118,11 +1227,14 @@ void lcd_scroll_fn(void) s->offset %= s->width; } - lastmode = drawmode; - drawmode = (s->style&STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + lastmode = current_vp->drawmode; + current_vp->drawmode = (s->style&STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_putsxyofs(xpos, ypos, s->offset, s->line); - drawmode = lastmode; - lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); + current_vp->drawmode = lastmode; + lcd_update_viewport_rect(xpos, ypos, + current_vp->width - xpos, pf->height); } + + lcd_set_viewport(old_vp); } diff --git a/firmware/drivers/lcd-charcell.c b/firmware/drivers/lcd-charcell.c index 0fd41481c5..1bc634cd2f 100644 --- a/firmware/drivers/lcd-charcell.c +++ b/firmware/drivers/lcd-charcell.c @@ -52,8 +52,17 @@ static unsigned char xfont_variable[VARIABLE_XCHARS][HW_PATTERN_SIZE]; static bool xfont_variable_locked[VARIABLE_XCHARS]; static int xspace; /* stores xhcar id of ' ' - often needed */ -static int xmargin = 0; -static int ymargin = 0; +static struct viewport default_vp = + { + .x = 0, + .y = 0, + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + .xmargin = 0, + .ymargin = 0, + }; + +static struct viewport* current_vp = &default_vp; /* LCD init */ void lcd_init (void) @@ -66,22 +75,47 @@ void lcd_init (void) scroll_init(); } +/* Viewports */ + +void lcd_set_viewport(struct viewport* vp) +{ + if (vp == NULL) + current_vp = &default_vp; + else + current_vp = vp; +} + +void lcd_update_viewport(void) +{ + lcd_update(); +} + /** parameter handling **/ void lcd_setmargins(int x, int y) { - xmargin = x; - ymargin = y; + current_vp->xmargin = x; + current_vp->ymargin = y; } int lcd_getxmargin(void) { - return xmargin; + return current_vp->xmargin; } int lcd_getymargin(void) { - return ymargin; + return current_vp->ymargin; +} + +int lcd_getwidth(void) +{ + return current_vp->width; +} + +int lcd_getheight(void) +{ + return current_vp->height; } int lcd_getstringsize(const unsigned char *str, int *w, int *h) @@ -225,7 +259,13 @@ static int map_xchar(int xchar, unsigned char *substitute) static void lcd_putxchar(int x, int y, int xchar) { - int lcd_char = lcd_charbuffer[y][x]; + int lcd_char; + + /* Adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + + lcd_char = lcd_charbuffer[y][x]; if (lcd_char < lcd_pattern_count) /* old char was soft */ lcd_patterns[lcd_char].count--; /* decrease old reference count */ @@ -283,19 +323,55 @@ void lcd_define_pattern(unsigned long ucs, const char *pattern) void lcd_clear_display(void) { int x, y; + struct viewport* old_vp = current_vp; - lcd_stop_scroll(); + lcd_scroll_info.lines = 0; lcd_remove_cursor(); + /* Set the default viewport - required for lcd_putxchar */ + current_vp = &default_vp; + for (x = 0; x < LCD_WIDTH; x++) for (y = 0; y < LCD_HEIGHT; y++) lcd_putxchar(x, y, xspace); + + current_vp = old_vp; +} + +/* Clear the current viewport */ +void lcd_clear_viewport(void) +{ + int x, y; + + if (current_vp == &default_vp) + { + lcd_clear_display(); + } + else + { + /* Remove the cursor if it is within the current viewport */ + if (lcd_cursor.enabled && + (lcd_cursor.x >= current_vp->x) && + (lcd_cursor.x <= current_vp->x + current_vp->width) && + (lcd_cursor.y >= current_vp->y) && + (lcd_cursor.y <= current_vp->y + current_vp->height)) + { + lcd_remove_cursor(); + } + + for (x = 0; x < current_vp->width; x++) + for (y = 0; y < current_vp->height; y++) + lcd_putxchar(x, y, xspace); + + lcd_scroll_stop(current_vp); + } } /* Put an unicode character at the given position */ void lcd_putc(int x, int y, unsigned long ucs) { - if ((unsigned)x >= LCD_WIDTH || (unsigned)y >= LCD_HEIGHT) + if ((unsigned)x >= (unsigned)current_vp->width || + (unsigned)y >= (unsigned)current_vp->height) return; lcd_putxchar(x, y, find_xchar(ucs)); @@ -304,15 +380,16 @@ void lcd_putc(int x, int y, unsigned long ucs) /* Show cursor (alternating with existing character) at the given position */ void lcd_put_cursor(int x, int y, unsigned long cursor_ucs) { - if ((unsigned)x >= LCD_WIDTH || (unsigned)y >= LCD_HEIGHT - || lcd_cursor.enabled) + if ((unsigned)x >= (unsigned)current_vp->width || + (unsigned)y >= (unsigned)current_vp->height || + lcd_cursor.enabled) return; lcd_cursor.enabled = true; lcd_cursor.visible = false; lcd_cursor.hw_char = map_xchar(find_xchar(cursor_ucs), &lcd_cursor.subst_char); - lcd_cursor.x = x; - lcd_cursor.y = y; + lcd_cursor.x = current_vp->x + x; + lcd_cursor.y = current_vp->y + y; lcd_cursor.downcount = 0; lcd_cursor.divider = MAX((HZ/2) / lcd_scroll_info.ticks, 1); } @@ -335,7 +412,7 @@ static int lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) unsigned short ucs; const unsigned char *utf8 = str; - while (*utf8 && x < LCD_WIDTH) + while (*utf8 && x < current_vp->width) { utf8 = utf8decode(utf8, &ucs); @@ -352,7 +429,7 @@ static int lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) /* Put a string at a given position */ void lcd_putsxy(int x, int y, const unsigned char *str) { - if ((unsigned)y >= LCD_HEIGHT) + if ((unsigned)y >= (unsigned)current_vp->height) return; lcd_putsxyofs(x, y, 0, str); @@ -369,17 +446,14 @@ void lcd_puts(int x, int y, const unsigned char *str) /* Put a string at a given char position, skipping first offset chars */ void lcd_puts_offset(int x, int y, const unsigned char *str, int offset) { - x += xmargin; - y += ymargin; - - if ((unsigned)y >= LCD_HEIGHT) + if ((unsigned)y >= (unsigned)current_vp->height) return; /* make sure scrolling is turned off on the line we are updating */ - lcd_scroll_info.lines &= ~(1 << y); + lcd_scroll_stop_line(current_vp, y); x = lcd_putsxyofs(x, y, offset, str); - while (x < LCD_WIDTH) + while (x < current_vp->width) lcd_putxchar(x++, y, xspace); } @@ -395,16 +469,22 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, struct scrollinfo* s; int len; - if(y>=LCD_SCROLLABLE_LINES) return; + if ((unsigned)y >= (unsigned)current_vp->height) + return; + + /* remove any previously scrolling line at the same location */ + lcd_scroll_stop_line(current_vp, y); - s = &lcd_scroll_info.scroll[y]; + if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return; + + s = &lcd_scroll_info.scroll[lcd_scroll_info.lines]; s->start_tick = current_tick + lcd_scroll_info.delay; lcd_puts_offset(x, y, string, offset); len = utf8length(string); - if (LCD_WIDTH - x - xmargin < len) + if (current_vp->width - x - current_vp->xmargin < len) { /* prepare scroll line */ char *end; @@ -418,7 +498,7 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, /* scroll bidirectional or forward only depending on the string width */ if (lcd_scroll_info.bidir_limit) { - s->bidir = s->len < (LCD_WIDTH - xmargin) * + s->bidir = s->len < (current_vp->width - current_vp->xmargin) * (100 + lcd_scroll_info.bidir_limit) / 100; } else @@ -432,16 +512,15 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, } end = strchr(s->line, '\0'); - strncpy(end, string, utf8seek(s->line, LCD_WIDTH)); + strncpy(end, string, utf8seek(s->line, current_vp->width)); + s->vp = current_vp; + s->y = y; s->offset = offset; - s->startx = xmargin + x; + s->startx = current_vp->xmargin + x; s->backward = false; - lcd_scroll_info.lines |= (1<start_tick)) continue; + lcd_set_viewport(s->vp); + if (s->backward) s->offset--; else s->offset++; xpos = s->startx; - ypos = ymargin + index; + ypos = current_vp->ymargin + s->y; if (s->bidir) /* scroll bidirectional */ { @@ -480,9 +557,9 @@ void lcd_scroll_fn(void) s->backward = false; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } - if (s->offset >= s->len - (LCD_WIDTH - xpos)) { + if (s->offset >= s->len - (current_vp->width - xpos)) { /* at end of line */ - s->offset = s->len - (LCD_WIDTH - xpos); + s->offset = s->len - (current_vp->width - xpos); s->backward = true; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } @@ -497,6 +574,8 @@ void lcd_scroll_fn(void) update = true; } + lcd_set_viewport(old_vp); + if (lcd_cursor.enabled) { if (--lcd_cursor.downcount <= 0) diff --git a/firmware/drivers/lcd-remote-1bit-v.c b/firmware/drivers/lcd-remote-1bit-v.c index 9bfbf580d9..a33648b76a 100644 --- a/firmware/drivers/lcd-remote-1bit-v.c +++ b/firmware/drivers/lcd-remote-1bit-v.c @@ -38,47 +38,88 @@ fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH] IBSS_ATTR; -static int drawmode = DRMODE_SOLID; -static int xmargin = 0; -static int ymargin = 0; -static int curfont = FONT_SYSFIXED; +static struct viewport default_vp = +{ + .x = 0, + .y = 0, + .width = LCD_REMOTE_WIDTH, + .height = LCD_REMOTE_HEIGHT, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, +}; + +static struct viewport* current_vp IDATA_ATTR = &default_vp; + +/*** Viewports ***/ + +void lcd_remote_set_viewport(struct viewport* vp) +{ + if (vp == NULL) + current_vp = &default_vp; + else + current_vp = vp; +} + +void lcd_remote_update_viewport(void) +{ + lcd_remote_update_rect(current_vp->x, current_vp->y, + current_vp->width, current_vp->height); +} + +void lcd_remote_update_viewport_rect(int x, int y, int width, int height) +{ + lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height); +} + /*** parameter handling ***/ void lcd_remote_set_drawmode(int mode) { - drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); + current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } int lcd_remote_get_drawmode(void) { - return drawmode; + return current_vp->drawmode; } void lcd_remote_setmargins(int x, int y) { - xmargin = x; - ymargin = y; + current_vp->xmargin = x; + current_vp->ymargin = y; +} + +int lcd_remote_getwidth(void) +{ + return current_vp->width; +} + +int lcd_remote_getheight(void) +{ + return current_vp->height; } int lcd_remote_getxmargin(void) { - return xmargin; + return current_vp->xmargin; } int lcd_remote_getymargin(void) { - return ymargin; + return current_vp->ymargin; } void lcd_remote_setfont(int newfont) { - curfont = newfont; + current_vp->font = newfont; } int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h) { - return font_getstringsize(str, w, h, curfont); + return font_getstringsize(str, w, h, current_vp->font); } /*** low-level drawing functions ***/ @@ -181,17 +222,44 @@ lcd_remote_blockfunc_type* const lcd_remote_blockfuncs[8] = { /* Clear the whole display */ void lcd_remote_clear_display(void) { - unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; + unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer); + lcd_remote_scroll_info.lines = 0; } +/* Clear the current viewport */ +void lcd_remote_clear_viewport(void) +{ + int oldmode; + + if (current_vp == &default_vp) + { + lcd_remote_clear_display(); + } + else + { + oldmode = current_vp->drawmode; + + /* Invert the INVERSEVID bit and set basic mode to SOLID */ + current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) | + DRMODE_SOLID; + + lcd_remote_fillrect(0, 0, current_vp->width, current_vp->height); + + current_vp->drawmode = oldmode; + + lcd_remote_scroll_stop(current_vp); + } +} + /* Set a single pixel */ void lcd_remote_drawpixel(int x, int y) { - if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) - lcd_remote_pixelfuncs[drawmode](x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y); } /* Draw a line */ @@ -203,7 +271,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2) int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; - lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[drawmode]; + lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode]; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -247,8 +315,8 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2) for (i = 0; i < numpixels; i++) { - if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) - pfunc(x, y); + if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height)) + pfunc(x + current_vp->x, y + current_vp->y); if (d < 0) { @@ -268,7 +336,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2) /* Draw a horizontal line (optimised) */ void lcd_remote_hline(int x1, int x2, int y) { - int x; + int x, width; fb_remote_data *dst, *dst_end; unsigned mask; lcd_remote_blockfunc_type *bfunc; @@ -282,24 +350,30 @@ void lcd_remote_hline(int x1, int x2, int y) } /* nothing to draw? */ - if (((unsigned)y >= LCD_REMOTE_HEIGHT) || (x1 >= LCD_REMOTE_WIDTH) + if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) || (x2 < 0)) return; /* clipping */ if (x1 < 0) x1 = 0; - if (x2 >= LCD_REMOTE_WIDTH) - x2 = LCD_REMOTE_WIDTH-1; + if (x2 >= current_vp->width) + x2 = current_vp->width-1; - bfunc = lcd_remote_blockfuncs[drawmode]; + width = x2 - x1 + 1; + + /* Adjust x1 and y to viewport */ + x1 += current_vp->x; + y += current_vp->y; + + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y>>3][x1]; mask = 1 << (y & 7); - dst_end = dst + x2 - x1; + dst_end = dst + width; do bfunc(dst++, mask, 0xFFu); - while (dst <= dst_end); + while (dst < dst_end); } /* Draw a vertical line (optimised) */ @@ -319,17 +393,22 @@ void lcd_remote_vline(int x, int y1, int y2) } /* nothing to draw? */ - if (((unsigned)x >= LCD_REMOTE_WIDTH) || (y1 >= LCD_REMOTE_HEIGHT) + if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) || (y2 < 0)) return; /* clipping */ if (y1 < 0) y1 = 0; - if (y2 >= LCD_REMOTE_HEIGHT) - y2 = LCD_REMOTE_HEIGHT-1; + if (y2 >= current_vp->height) + y2 = current_vp->height-1; + + /* adjust for viewport */ + y1 += current_vp->y; + y2 += current_vp->y; + x += current_vp->x; - bfunc = lcd_remote_blockfuncs[drawmode]; + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y1>>3][x]; ny = y2 - (y1 & ~7); mask = 0xFFu << (y1 & 7); @@ -371,8 +450,8 @@ void lcd_remote_fillrect(int x, int y, int width, int height) bool fillopt = false; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) - || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) + || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -386,27 +465,32 @@ void lcd_remote_fillrect(int x, int y, int width, int height) height += y; y = 0; } - if (x + width > LCD_REMOTE_WIDTH) - width = LCD_REMOTE_WIDTH - x; - if (y + height > LCD_REMOTE_HEIGHT) - height = LCD_REMOTE_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; - if (drawmode & DRMODE_INVERSEVID) + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + + if (current_vp->drawmode & DRMODE_INVERSEVID) { - if (drawmode & DRMODE_BG) + if (current_vp->drawmode & DRMODE_BG) { fillopt = true; } } else { - if (drawmode & DRMODE_FG) + if (current_vp->drawmode & DRMODE_FG) { fillopt = true; bits = 0xFFu; } } - bfunc = lcd_remote_blockfuncs[drawmode]; + + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y>>3][x]; ny = height - 1 + (y & 7); mask = 0xFFu << (y & 7); @@ -466,8 +550,8 @@ void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y, lcd_remote_blockfunc_type *bfunc; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) - || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) + || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -483,10 +567,14 @@ void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_REMOTE_WIDTH) - width = LCD_REMOTE_WIDTH - x; - if (y + height > LCD_REMOTE_HEIGHT) - height = LCD_REMOTE_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewports */ + x += current_vp->x; + y += current_vp->y; src += stride * (src_y >> 3) + src_x; /* move starting point */ src_y &= 7; @@ -495,13 +583,13 @@ void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y, shift = y & 7; ny = height - 1 + shift + src_y; - bfunc = lcd_remote_blockfuncs[drawmode]; + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; mask = 0xFFu << (shift + src_y); mask_bottom = 0xFFu >> (~ny & 7); if (shift == 0) { - bool copyopt = (drawmode == DRMODE_SOLID); + bool copyopt = (current_vp->drawmode == DRMODE_SOLID); for (; ny >= 8; ny -= 8) { @@ -579,11 +667,11 @@ void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str) { unsigned short ch; unsigned short *ucs; - struct font* pf = font_get(curfont); + struct font* pf = font_get(current_vp->font); ucs = bidi_l2v(str, 1); - while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH) + while ((ch = *ucs++) != 0 && x < current_vp->width) { int width; const unsigned char *bits; @@ -637,24 +725,24 @@ void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str, int style, int offset) { int xpos,ypos,w,h,xrect; - int lastmode = drawmode; + int lastmode = current_vp->drawmode; /* make sure scrolling is turned off on the line we are updating */ - lcd_remote_scroll_info.lines &= ~(1 << y); + lcd_remote_scroll_stop_line(current_vp, y); if(!str || !str[0]) return; lcd_remote_getstringsize(str, &w, &h); - xpos = xmargin + x*w / utf8length((char *)str); - ypos = ymargin + y*h; - drawmode = (style & STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + xpos = current_vp->xmargin + x*w / utf8length((char *)str); + ypos = current_vp->ymargin + y*h; + current_vp->drawmode = (style & STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_remote_putsxyofs(xpos, ypos, offset, str); - drawmode ^= DRMODE_INVERSEVID; + current_vp->drawmode ^= DRMODE_INVERSEVID; xrect = xpos + MAX(w - offset, 0); - lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h); - drawmode = lastmode; + lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h); + current_vp->drawmode = lastmode; } /*** scrolling ***/ @@ -680,9 +768,15 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri struct scrollinfo* s; int w, h; - if(y>=LCD_REMOTE_SCROLLABLE_LINES) return; + if ((unsigned)y >= (unsigned)current_vp->height) + return; + + /* remove any previously scrolling line at the same location */ + lcd_remote_scroll_stop_line(current_vp, y); + + if (lcd_remote_scroll_info.lines >= LCD_REMOTE_SCROLLABLE_LINES) return; - s = &lcd_remote_scroll_info.scroll[y]; + s = &lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines]; s->start_tick = current_tick + lcd_remote_scroll_info.delay; s->style = style; @@ -694,7 +788,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri lcd_remote_getstringsize(string, &w, &h); - if (LCD_REMOTE_WIDTH - x * 8 - xmargin < w) { + if (current_vp->width - x * 8 - current_vp->xmargin < w) { /* prepare scroll line */ char *end; @@ -707,7 +801,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri /* scroll bidirectional or forward only depending on the string width */ if ( lcd_remote_scroll_info.bidir_limit ) { - s->bidir = s->width < (LCD_REMOTE_WIDTH - xmargin) * + s->bidir = s->width < (current_vp->width - current_vp->xmargin) * (100 + lcd_remote_scroll_info.bidir_limit) / 100; } else @@ -720,17 +814,17 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri } end = strchr(s->line, '\0'); - strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2); + strncpy(end, (char *)string, current_vp->width/2); + s->vp = current_vp; + s->y = y; s->len = utf8length((char *)string); s->offset = offset; - s->startx = xmargin + x * s->width / s->len;; + s->startx = current_vp->xmargin + x * s->width / s->len; s->backward = false; - lcd_remote_scroll_info.lines |= (1<start_tick)) continue; + lcd_remote_set_viewport(s->vp); + if (s->backward) s->offset -= lcd_remote_scroll_info.step; else s->offset += lcd_remote_scroll_info.step; - pf = font_get(curfont); + pf = font_get(current_vp->font); xpos = s->startx; - ypos = ymargin + index * pf->height; + ypos = current_vp->ymargin + s->y * pf->height; if (s->bidir) { /* scroll bidirectional */ if (s->offset <= 0) { @@ -768,9 +861,9 @@ void lcd_remote_scroll_fn(void) s->backward = false; s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; } - if (s->offset >= s->width - (LCD_REMOTE_WIDTH - xpos)) { + if (s->offset >= s->width - (current_vp->width - xpos)) { /* at end of line */ - s->offset = s->width - (LCD_REMOTE_WIDTH - xpos); + s->offset = s->width - (current_vp->width - xpos); s->backward = true; s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; } @@ -781,13 +874,16 @@ void lcd_remote_scroll_fn(void) s->offset %= s->width; } - lastmode = drawmode; - drawmode = (s->style&STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + lastmode = current_vp->drawmode; + current_vp->drawmode = (s->style&STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line); - drawmode = lastmode; - lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height); + current_vp->drawmode = lastmode; + lcd_remote_update_viewport_rect(xpos, ypos, + current_vp->width - xpos, pf->height); } + + lcd_remote_set_viewport(old_vp); } /* LCD init */ diff --git a/firmware/drivers/lcd-remote-2bit-vi.c b/firmware/drivers/lcd-remote-2bit-vi.c index d5757f4dbb..9ab98c69aa 100644 --- a/firmware/drivers/lcd-remote-2bit-vi.c +++ b/firmware/drivers/lcd-remote-2bit-vi.c @@ -46,12 +46,48 @@ static const fb_remote_data patterns[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000}; static fb_remote_data* remote_backdrop = NULL; static long remote_backdrop_offset IDATA_ATTR = 0; -static unsigned fg_pattern IDATA_ATTR = 0xFFFF; /* initially black */ -static unsigned bg_pattern IDATA_ATTR = 0x0000; /* initially white */ -static int drawmode = DRMODE_SOLID; -static int xmargin = 0; -static int ymargin = 0; -static int curfont = FONT_SYSFIXED; +static struct viewport default_vp = +{ + .x = 0, + .y = 0, + .width = LCD_REMOTE_WIDTH, + .height = LCD_REMOTE_HEIGHT, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, + .fg_pattern = LCD_REMOTE_DEFAULT_FG, + .bg_pattern = LCD_REMOTE_DEFAULT_BG +}; + +static unsigned fg_pattern IBSS_ATTR; +static unsigned bg_pattern IBSS_ATTR; + +static struct viewport* current_vp IBSS_ATTR;; + +/*** Viewports ***/ + +void lcd_remote_set_viewport(struct viewport* vp) +{ + if (vp == NULL) + current_vp = &default_vp; + else + current_vp = vp; + + fg_pattern = patterns[current_vp->fg_pattern & 3]; + bg_pattern = patterns[current_vp->bg_pattern & 3]; +} + +void lcd_remote_update_viewport(void) +{ + lcd_remote_update_rect(current_vp->x, current_vp->y, + current_vp->width, current_vp->height); +} + +void lcd_remote_update_viewport_rect(int x, int y, int width, int height) +{ + lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height); +} /*** parameter handling ***/ unsigned lcd_remote_color_to_native(unsigned color) @@ -69,32 +105,34 @@ unsigned lcd_remote_color_to_native(unsigned color) void lcd_remote_set_drawmode(int mode) { - drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); + current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } int lcd_remote_get_drawmode(void) { - return drawmode; + return current_vp->drawmode; } void lcd_remote_set_foreground(unsigned brightness) { + current_vp->fg_pattern = brightness; fg_pattern = patterns[brightness & 3]; } unsigned lcd_remote_get_foreground(void) { - return (~fg_pattern >> 7) & 3; + return current_vp->fg_pattern; } void lcd_remote_set_background(unsigned brightness) { + current_vp->bg_pattern = brightness; bg_pattern = patterns[brightness & 3]; } unsigned lcd_remote_get_background(void) { - return (~bg_pattern >> 7) & 3; + return current_vp->bg_pattern; } void lcd_remote_set_drawinfo(int mode, unsigned fg_brightness, @@ -105,30 +143,40 @@ void lcd_remote_set_drawinfo(int mode, unsigned fg_brightness, lcd_remote_set_background(bg_brightness); } +int lcd_remote_getwidth(void) +{ + return current_vp->width; +} + +int lcd_remote_getheight(void) +{ + return current_vp->height; +} + void lcd_remote_setmargins(int x, int y) { - xmargin = x; - ymargin = y; + current_vp->xmargin = x; + current_vp->ymargin = y; } int lcd_remote_getxmargin(void) { - return xmargin; + return current_vp->xmargin; } int lcd_remote_getymargin(void) { - return ymargin; + return current_vp->ymargin; } void lcd_remote_setfont(int newfont) { - curfont = newfont; + current_vp->font = newfont; } int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h) { - return font_getstringsize(str, w, h, curfont); + return font_getstringsize(str, w, h, current_vp->font); } /*** low-level drawing functions ***/ @@ -351,9 +399,9 @@ static inline void setblock(fb_remote_data *address, unsigned mask, unsigned bit /* Clear the whole display */ void lcd_remote_clear_display(void) { - if (drawmode & DRMODE_INVERSEVID) + if (default_vp.drawmode & DRMODE_INVERSEVID) { - memset(lcd_remote_framebuffer, fg_pattern, + memset(lcd_remote_framebuffer, patterns[default_vp.fg_pattern & 3], sizeof lcd_remote_framebuffer); } else @@ -362,18 +410,44 @@ void lcd_remote_clear_display(void) memcpy(lcd_remote_framebuffer, remote_backdrop, sizeof lcd_remote_framebuffer); else - memset(lcd_remote_framebuffer, bg_pattern, + memset(lcd_remote_framebuffer, patterns[default_vp.bg_pattern & 3], sizeof lcd_remote_framebuffer); } lcd_remote_scroll_info.lines = 0; } +/* Clear the current viewport */ +void lcd_remote_clear_viewport(void) +{ + int lastmode; + + if (current_vp == &default_vp) + { + lcd_remote_clear_display(); + } + else + { + lastmode = current_vp->drawmode; + + /* Invert the INVERSEVID bit and set basic mode to SOLID */ + current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) | + DRMODE_SOLID; + + lcd_remote_fillrect(0, 0, current_vp->width, current_vp->height); + + current_vp->drawmode = lastmode; + + lcd_remote_scroll_stop(current_vp); + } +} + /* Set a single pixel */ void lcd_remote_drawpixel(int x, int y) { - if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) - lcd_remote_pixelfuncs[drawmode](x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y); } /* Draw a line */ @@ -385,7 +459,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2) int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; - lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[drawmode]; + lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode]; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -429,8 +503,9 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2) for (i = 0; i < numpixels; i++) { - if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) - pfunc(x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + pfunc(current_vp->x + x, current_vp->y + y); if (d < 0) { @@ -451,6 +526,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2) void lcd_remote_hline(int x1, int x2, int y) { int x; + int width; fb_remote_data *dst, *dst_end; unsigned mask; lcd_remote_blockfunc_type *bfunc; @@ -464,24 +540,30 @@ void lcd_remote_hline(int x1, int x2, int y) } /* nothing to draw? */ - if (((unsigned)y >= LCD_REMOTE_HEIGHT) || (x1 >= LCD_REMOTE_WIDTH) + if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) || (x2 < 0)) return; /* clipping */ if (x1 < 0) x1 = 0; - if (x2 >= LCD_REMOTE_WIDTH) - x2 = LCD_REMOTE_WIDTH-1; + if (x2 >= current_vp->width) + x2 = current_vp->width-1; - bfunc = lcd_remote_blockfuncs[drawmode]; + width = x2 - x1 + 1; + + /* adjust x1 and y to viewport */ + x1 += current_vp->x; + y += current_vp->y; + + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y>>3][x1]; mask = 0x0101 << (y & 7); - dst_end = dst + x2 - x1; + dst_end = dst + width; do bfunc(dst++, mask, 0xFFFFu); - while (dst <= dst_end); + while (dst < dst_end); } /* Draw a vertical line (optimised) */ @@ -501,17 +583,22 @@ void lcd_remote_vline(int x, int y1, int y2) } /* nothing to draw? */ - if (((unsigned)x >= LCD_REMOTE_WIDTH) || (y1 >= LCD_REMOTE_HEIGHT) + if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) || (y2 < 0)) return; /* clipping */ if (y1 < 0) y1 = 0; - if (y2 >= LCD_REMOTE_HEIGHT) - y2 = LCD_REMOTE_HEIGHT-1; + if (y2 >= current_vp->height) + y2 = current_vp->height-1; + + /* adjust for viewport */ + y1 += current_vp->y; + y2 += current_vp->y; + x += current_vp->x; - bfunc = lcd_remote_blockfuncs[drawmode]; + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y1>>3][x]; ny = y2 - (y1 & ~7); mask = (0xFFu << (y1 & 7)) & 0xFFu; @@ -555,8 +642,8 @@ void lcd_remote_fillrect(int x, int y, int width, int height) bool fillopt = false; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) - || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) + || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -570,14 +657,18 @@ void lcd_remote_fillrect(int x, int y, int width, int height) height += y; y = 0; } - if (x + width > LCD_REMOTE_WIDTH) - width = LCD_REMOTE_WIDTH - x; - if (y + height > LCD_REMOTE_HEIGHT) - height = LCD_REMOTE_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; - if (drawmode & DRMODE_INVERSEVID) + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + + if (current_vp->drawmode & DRMODE_INVERSEVID) { - if ((drawmode & DRMODE_BG) && !remote_backdrop) + if ((current_vp->drawmode & DRMODE_BG) && !remote_backdrop) { fillopt = true; bits = bg_pattern; @@ -585,13 +676,13 @@ void lcd_remote_fillrect(int x, int y, int width, int height) } else { - if (drawmode & DRMODE_FG) + if (current_vp->drawmode & DRMODE_FG) { fillopt = true; bits = fg_pattern; } } - bfunc = lcd_remote_blockfuncs[drawmode]; + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y>>3][x]; ny = height - 1 + (y & 7); mask = (0xFFu << (y & 7)) & 0xFFu; @@ -653,8 +744,8 @@ void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, lcd_remote_blockfunc_type *bfunc; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) - || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -670,10 +761,14 @@ void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_REMOTE_WIDTH) - width = LCD_REMOTE_WIDTH - x; - if (y + height > LCD_REMOTE_HEIGHT) - height = LCD_REMOTE_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; src += stride * (src_y >> 3) + src_x; /* move starting point */ src_y &= 7; @@ -682,7 +777,7 @@ void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, shift = y & 7; ny = height - 1 + shift + src_y; - bfunc = lcd_remote_blockfuncs[drawmode]; + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; mask = 0xFFu << (shift + src_y); /* not byte-doubled here because shift+src_y can be > 7 */ mask_bottom = 0xFFu >> (~ny & 7); @@ -793,8 +888,8 @@ void lcd_remote_bitmap_part(const fb_remote_data *src, int src_x, int src_y, unsigned mask, mask_bottom; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) - || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) + || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -810,10 +905,14 @@ void lcd_remote_bitmap_part(const fb_remote_data *src, int src_x, int src_y, src_y -= y; y = 0; } - if (x + width > LCD_REMOTE_WIDTH) - width = LCD_REMOTE_WIDTH - x; - if (y + height > LCD_REMOTE_HEIGHT) - height = LCD_REMOTE_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; src += stride * (src_y >> 3) + src_x; /* move starting point */ src_y &= 7; @@ -917,11 +1016,11 @@ void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str) { unsigned short ch; unsigned short *ucs; - struct font* pf = font_get(curfont); + struct font* pf = font_get(current_vp->font); ucs = bidi_l2v(str, 1); - while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH) + while ((ch = *ucs++) != 0 && x < current_vp->width) { int width; const unsigned char *bits; @@ -975,24 +1074,24 @@ void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str, int style, int offset) { int xpos,ypos,w,h,xrect; - int lastmode = drawmode; + int lastmode = current_vp->drawmode; /* make sure scrolling is turned off on the line we are updating */ - lcd_remote_scroll_info.lines &= ~(1 << y); + lcd_remote_scroll_stop_line(current_vp, y); if(!str || !str[0]) return; lcd_remote_getstringsize(str, &w, &h); - xpos = xmargin + x*w / utf8length((char *)str); - ypos = ymargin + y*h; - drawmode = (style & STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + xpos = current_vp->xmargin + x*w / utf8length((char *)str); + ypos = current_vp->ymargin + y*h; + current_vp->drawmode = (style & STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_remote_putsxyofs(xpos, ypos, offset, str); - drawmode ^= DRMODE_INVERSEVID; + current_vp->drawmode ^= DRMODE_INVERSEVID; xrect = xpos + MAX(w - offset, 0); - lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h); - drawmode = lastmode; + lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h); + current_vp->drawmode = lastmode; } /*** scrolling ***/ @@ -1017,9 +1116,15 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri struct scrollinfo* s; int w, h; - if(y>=LCD_REMOTE_SCROLLABLE_LINES) return; + if ((unsigned)y >= (unsigned)current_vp->height) + return; - s = &lcd_remote_scroll_info.scroll[y]; + /* remove any previously scrolling line at the same location */ + lcd_remote_scroll_stop_line(current_vp, y); + + if (lcd_remote_scroll_info.lines >= LCD_REMOTE_SCROLLABLE_LINES) return; + + s = &lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines]; s->start_tick = current_tick + lcd_remote_scroll_info.delay; s->style = style; @@ -1031,7 +1136,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri lcd_remote_getstringsize(string, &w, &h); - if (LCD_REMOTE_WIDTH - x * 8 - xmargin < w) { + if (current_vp->width - x * 8 - current_vp->xmargin < w) { /* prepare scroll line */ char *end; @@ -1044,7 +1149,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri /* scroll bidirectional or forward only depending on the string width */ if ( lcd_remote_scroll_info.bidir_limit ) { - s->bidir = s->width < (LCD_REMOTE_WIDTH - xmargin) * + s->bidir = s->width < (current_vp->width - current_vp->xmargin) * (100 + lcd_remote_scroll_info.bidir_limit) / 100; } else @@ -1057,17 +1162,17 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri } end = strchr(s->line, '\0'); - strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2); + strncpy(end, (char *)string, current_vp->width/2); + s->vp = current_vp; + s->y = y; s->len = utf8length((char *)string); s->offset = offset; - s->startx = xmargin + x * s->width / s->len;; + s->startx = current_vp->xmargin + x * s->width / s->len; s->backward = false; - lcd_remote_scroll_info.lines |= (1<start_tick)) continue; + lcd_remote_set_viewport(s->vp); + if (s->backward) s->offset -= lcd_remote_scroll_info.step; else s->offset += lcd_remote_scroll_info.step; - pf = font_get(curfont); + pf = font_get(current_vp->font); xpos = s->startx; - ypos = ymargin + index * pf->height; + ypos = current_vp->ymargin + s->y * pf->height; if (s->bidir) { /* scroll bidirectional */ if (s->offset <= 0) { @@ -1105,9 +1209,9 @@ void lcd_remote_scroll_fn(void) s->backward = false; s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; } - if (s->offset >= s->width - (LCD_REMOTE_WIDTH - xpos)) { + if (s->offset >= s->width - (current_vp->width - xpos)) { /* at end of line */ - s->offset = s->width - (LCD_REMOTE_WIDTH - xpos); + s->offset = s->width - (current_vp->width - xpos); s->backward = true; s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; } @@ -1118,18 +1222,24 @@ void lcd_remote_scroll_fn(void) s->offset %= s->width; } - lastmode = drawmode; - drawmode = (s->style&STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + lastmode = current_vp->drawmode; + current_vp->drawmode = (s->style&STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line); - drawmode = lastmode; - lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height); + current_vp->drawmode = lastmode; + lcd_remote_update_viewport_rect(xpos, ypos, + current_vp->width - xpos, pf->height); } + + lcd_remote_set_viewport(old_vp); } /* LCD init */ void lcd_remote_init(void) { + /* Initialise the viewport */ + lcd_remote_set_viewport(NULL); + #ifndef SIMULATOR /* Call device specific init */ lcd_remote_init_device(); diff --git a/firmware/export/lcd-remote.h b/firmware/export/lcd-remote.h index 3be23747ea..34c40e52c1 100644 --- a/firmware/export/lcd-remote.h +++ b/firmware/export/lcd-remote.h @@ -24,6 +24,7 @@ #include "cpu.h" #include "config.h" #include "adc.h" +#include "lcd.h" #ifdef HAVE_REMOTE_LCD @@ -109,7 +110,9 @@ extern void lcd_remote_init(void); extern int lcd_remote_default_contrast(void); extern void lcd_remote_set_contrast(int val); +extern void lcd_remote_set_viewport(struct viewport* vp); extern void lcd_remote_clear_display(void); +extern void lcd_remote_clear_viewport(void); extern void lcd_remote_puts(int x, int y, const unsigned char *str); extern void lcd_remote_puts_style(int x, int y, const unsigned char *str, int style); @@ -132,6 +135,8 @@ extern void lcd_remote_puts_scroll_style_offset(int x, int y, extern void lcd_remote_update(void); extern void lcd_remote_update_rect(int x, int y, int width, int height); +extern void lcd_remote_update_viewport(void); +extern void lcd_remote_update_viewport_rect(int x, int y, int width, int height); extern void lcd_remote_set_invert_display(bool yesno); extern void lcd_remote_set_flip(bool yesno); @@ -141,6 +146,8 @@ extern int lcd_remote_get_drawmode(void); extern void lcd_remote_setmargins(int xmargin, int ymargin); extern int lcd_remote_getxmargin(void); extern int lcd_remote_getymargin(void); +extern int lcd_remote_getwidth(void); +extern int lcd_remote_getheight(void); extern void lcd_remote_setfont(int font); extern int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h); diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 60d9efaf92..276dcdfedc 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -24,6 +24,28 @@ #include "cpu.h" #include "config.h" +struct viewport { + int x; + int y; + int width; + int height; +#ifdef HAVE_LCD_BITMAP + int font; + int drawmode; +#endif + int xmargin; /* During the transition only - to be removed */ + int ymargin; /* During the transition only - to be removed */ +#if LCD_DEPTH > 1 + unsigned fg_pattern; + unsigned bg_pattern; +#ifdef HAVE_LCD_COLOR + unsigned lss_pattern; + unsigned lse_pattern; + unsigned lst_pattern; +#endif +#endif +}; + #define STYLE_DEFAULT 0x00000000 #define STYLE_COLORED 0x10000000 #define STYLE_INVERT 0x20000000 @@ -76,9 +98,14 @@ extern void lcd_set_contrast(int val); extern void lcd_setmargins(int xmargin, int ymargin); extern int lcd_getxmargin(void); extern int lcd_getymargin(void); +extern int lcd_getwidth(void); +extern int lcd_getheight(void); extern int lcd_getstringsize(const unsigned char *str, int *w, int *h); +extern void lcd_set_viewport(struct viewport* vp); extern void lcd_update(void); +extern void lcd_update_viewport(void); +extern void lcd_clear_viewport(void); extern void lcd_clear_display(void); extern void lcd_putsxy(int x, int y, const unsigned char *string); extern void lcd_puts(int x, int y, const unsigned char *string); @@ -119,6 +146,7 @@ extern void lcd_blit(const fb_data* data, int x, int by, int width, /* update a fraction of the screen */ extern void lcd_update_rect(int x, int y, int width, int height); +extern void lcd_update_viewport_rect(int x, int y, int width, int height); #ifdef HAVE_REMOTE_LCD extern void lcd_remote_update(void); diff --git a/firmware/export/scroll_engine.h b/firmware/export/scroll_engine.h index 5e39990129..48d5c5cb8c 100644 --- a/firmware/export/scroll_engine.h +++ b/firmware/export/scroll_engine.h @@ -23,9 +23,17 @@ #ifndef __SCROLL_ENGINE_H__ #define __SCROLL_ENGINE_H__ +#include + void scroll_init(void); +void lcd_scroll_stop(struct viewport* vp); +void lcd_scroll_stop_line(struct viewport* vp, int y); void lcd_scroll_fn(void); +#ifdef HAVE_REMOTE_LCD void lcd_remote_scroll_fn(void); +void lcd_remote_scroll_stop(struct viewport* vp); +void lcd_remote_scroll_stop_line(struct viewport* vp, int y); +#endif /* internal usage, but in multiple drivers */ #define SCROLL_SPACING 3 @@ -37,8 +45,10 @@ void lcd_remote_scroll_fn(void); struct scrollinfo { + struct viewport* vp; char line[SCROLL_LINE_SIZE]; int len; /* length of line in chars */ + int y; /* Position of the line on the screen (char co-ordinates) */ int offset; int startx; #ifdef HAVE_LCD_BITMAP @@ -54,7 +64,7 @@ struct scroll_screen_info { struct scrollinfo * const scroll; const int num_scroll; /* number of scrollable lines (also number of scroll structs) */ - int lines; /* Bitpattern of which lines are scrolling */ + int lines; /* Number of currently scrolling lines */ long ticks; /* # of ticks between updates*/ long delay; /* ticks delay before start */ int bidir_limit; /* percent */ @@ -74,7 +84,7 @@ struct scroll_screen_info #ifdef HAVE_LCD_BITMAP #define LCD_SCROLLABLE_LINES ((LCD_HEIGHT+4)/5 < 32 ? (LCD_HEIGHT+4)/5 : 32) #else -#define LCD_SCROLLABLE_LINES LCD_HEIGHT +#define LCD_SCROLLABLE_LINES LCD_HEIGHT * 2 #endif extern struct scroll_screen_info lcd_scroll_info; diff --git a/firmware/scroll_engine.c b/firmware/scroll_engine.c index 599e7f58b5..4783e9f1ef 100644 --- a/firmware/scroll_engine.c +++ b/firmware/scroll_engine.c @@ -82,6 +82,40 @@ void lcd_stop_scroll(void) lcd_scroll_info.lines = 0; } +/* Stop scrolling line y in the specified viewport, or all lines if y < 0 */ +void lcd_scroll_stop_line(struct viewport* current_vp, int y) +{ + int i = 0; + + while (i < lcd_scroll_info.lines) + { + if ((lcd_scroll_info.scroll[i].vp == current_vp) && + ((y < 0) || (lcd_scroll_info.scroll[i].y == y))) + { + /* If i is not the last active line in the array, then move + the last item to position i */ + if ((i + 1) != lcd_scroll_info.lines) + { + lcd_scroll_info.scroll[i] = lcd_scroll_info.scroll[lcd_scroll_info.lines-1]; + } + lcd_scroll_info.lines--; + + /* A line can only appear once, so we're done. */ + return ; + } + else + { + i++; + } + } +} + +/* Stop all scrolling lines in the specified viewport */ +void lcd_scroll_stop(struct viewport* vp) +{ + lcd_scroll_stop_line(vp, -1); +} + void lcd_scroll_speed(int speed) { lcd_scroll_info.ticks = scroll_tick_table[speed]; @@ -122,6 +156,40 @@ void lcd_remote_stop_scroll(void) lcd_remote_scroll_info.lines = 0; } +/* Stop scrolling line y in the specified viewport, or all lines if y < 0 */ +void lcd_remote_scroll_stop_line(struct viewport* current_vp, int y) +{ + int i = 0; + + while (i < lcd_remote_scroll_info.lines) + { + if ((lcd_remote_scroll_info.scroll[i].vp == current_vp) && + ((y < 0) || (lcd_remote_scroll_info.scroll[i].y == y))) + { + /* If i is not the last active line in the array, then move + the last item to position i */ + if ((i + 1) != lcd_remote_scroll_info.lines) + { + lcd_remote_scroll_info.scroll[i] = lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines-1]; + } + lcd_remote_scroll_info.lines--; + + /* A line can only appear once, so we're done. */ + return ; + } + else + { + i++; + } + } +} + +/* Stop all scrolling lines in the specified viewport */ +void lcd_remote_scroll_stop(struct viewport* vp) +{ + lcd_remote_scroll_stop_line(vp, -1); +} + void lcd_remote_scroll_speed(int speed) { lcd_remote_scroll_info.ticks = scroll_tick_table[speed]; diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c index 91b2eae986..9b066d61d0 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c @@ -11,10 +11,9 @@ static volatile bool lcd_on = true; volatile bool lcd_poweroff = false; static unsigned lcd_yuv_options = 0; /* -** These are imported from lcd-16bit.c +** This is imported from lcd-16bit.c */ -extern unsigned fg_pattern; -extern unsigned bg_pattern; +extern struct viewport* current_vp; /* Copies a rectangle from one framebuffer to another. Can be used in single transfer mode with width = num pixels, and height = 1 which @@ -245,7 +244,7 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, [dstp]"r"(LCD_WIDTH - width), [transcolor]"r"(TRANSPARENT_COLOR), [fgcolor]"r"(REPLACEWITHFG_COLOR), - [fgpat]"r"(fg_pattern) + [fgpat]"r"(current_vp->fg_pattern) ); } -- cgit v1.2.3