summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2008-01-07 20:34:11 +0000
committerDave Chapman <dave@dchapman.com>2008-01-07 20:34:11 +0000
commit945c8a221ade41c462a93f8452320a806e5645b3 (patch)
tree2a17823e286e6252e60c44c7f4753d5c18ef5172
parent2a8f39820b49f116820356c2ca224f82f2106c21 (diff)
downloadrockbox-945c8a221ade41c462a93f8452320a806e5645b3.tar.gz
rockbox-945c8a221ade41c462a93f8452320a806e5645b3.tar.bz2
rockbox-945c8a221ade41c462a93f8452320a806e5645b3.zip
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
-rw-r--r--firmware/drivers/lcd-16bit.c478
-rw-r--r--firmware/drivers/lcd-1bit-vert.c250
-rw-r--r--firmware/drivers/lcd-2bit-horz.c277
-rw-r--r--firmware/drivers/lcd-2bit-vert.c294
-rw-r--r--firmware/drivers/lcd-charcell.c159
-rw-r--r--firmware/drivers/lcd-remote-1bit-v.c260
-rw-r--r--firmware/drivers/lcd-remote-2bit-vi.c294
-rw-r--r--firmware/export/lcd-remote.h7
-rw-r--r--firmware/export/lcd.h28
-rw-r--r--firmware/export/scroll_engine.h14
-rw-r--r--firmware/scroll_engine.c68
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c7
12 files changed, 1473 insertions, 663 deletions
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<<y);
+ lcd_scroll_info.lines++;
}
- else
- /* force a bit switch-off since it doesn't scroll */
- lcd_scroll_info.lines &= ~(1<<y);
}
void lcd_scroll_fn(void)
@@ -1000,28 +1100,29 @@ void lcd_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
- unsigned old_fgcolor = fg_pattern;
- unsigned old_bgcolor = bg_pattern;
-
- for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) {
- /* really scroll? */
- if ((lcd_scroll_info.lines & (1 << index)) == 0)
- continue;
+ unsigned old_fgcolor;
+ unsigned old_bgcolor;
+ struct viewport* old_vp = current_vp;
+ for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
s = &lcd_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->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<<y);
+ lcd_scroll_info.lines++;
}
- else
- /* force a bit switch-off since it doesn't scroll */
- lcd_scroll_info.lines &= ~(1<<y);
}
void lcd_scroll_fn(void)
@@ -742,26 +833,25 @@ void lcd_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
+ struct viewport* old_vp = current_vp;
- for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) {
- /* really scroll? */
- if ((lcd_scroll_info.lines & (1 << index)) == 0)
- continue;
-
+ for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
s = &lcd_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->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<<y);
+ lcd_scroll_info.lines++;
}
- else
- /* force a bit switch-off since it doesn't scroll */
- lcd_scroll_info.lines &= ~(1<<y);
}
void lcd_scroll_fn(void)
@@ -941,26 +1047,25 @@ void lcd_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
+ struct viewport* old_vp = current_vp;
- for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) {
- /* really scroll? */
- if ((lcd_scroll_info.lines & (1 << index)) == 0)
- continue;
-
+ for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
s = &lcd_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->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<<y);
+
+ lcd_scroll_info.lines++;
}
- else
- /* force a bit switch-off since it doesn't scroll */
- lcd_scroll_info.lines &= ~(1<<y);
}
void lcd_scroll_fn(void)
@@ -1077,26 +1187,25 @@ void lcd_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
+ struct viewport* old_vp = current_vp;
- for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) {
- /* really scroll? */
- if ((lcd_scroll_info.lines & (1 << index)) == 0)
- continue;
-
+ for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
s = &lcd_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->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<<y);
+ lcd_scroll_info.lines++;
}
- else
- /* force a bit switch-off since it doesn't scroll */
- lcd_scroll_info.lines &= ~(1<<y);
}
void lcd_scroll_fn(void)
@@ -450,27 +529,25 @@ void lcd_scroll_fn(void)
int index;
int xpos, ypos;
bool update;
+ struct viewport* old_vp = current_vp;
update = false;
- for (index = 0; index < LCD_SCROLLABLE_LINES; index++)
- {
- /* really scroll? */
- if ((lcd_scroll_info.lines & (1 << index)) == 0)
- continue;
-
+ for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
s = &lcd_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->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<<y);
+
+ lcd_remote_scroll_info.lines++;
}
- else
- /* force a bit switch-off since it doesn't scroll */
- lcd_remote_scroll_info.lines &= ~(1<<y);
}
void lcd_remote_scroll_fn(void)
@@ -740,26 +834,25 @@ void lcd_remote_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
+ struct viewport* old_vp = current_vp;
- for ( index = 0; index < LCD_REMOTE_SCROLLABLE_LINES; index++ ) {
- /* really scroll? */
- if ((lcd_remote_scroll_info.lines & (1 << index)) == 0)
- continue;
-
+ for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) {
s = &lcd_remote_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->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<<y);
+
+ lcd_remote_scroll_info.lines++;
}
- else
- /* force a bit switch-off since it doesn't scroll */
- lcd_remote_scroll_info.lines &= ~(1<<y);
}
void lcd_remote_scroll_fn(void)
@@ -1077,26 +1182,25 @@ void lcd_remote_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
+ struct viewport* old_vp = current_vp;
- for ( index = 0; index < LCD_REMOTE_SCROLLABLE_LINES; index++ ) {
- /* really scroll? */
- if ((lcd_remote_scroll_info.lines & (1 << index)) == 0)
- continue;
-
+ for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) {
s = &lcd_remote_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->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 <lcd.h>
+
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)
);
}