summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-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]
49static fb_data* lcd_backdrop = NULL; 49static fb_data* lcd_backdrop = NULL;
50static long lcd_backdrop_offset IDATA_ATTR = 0; 50static long lcd_backdrop_offset IDATA_ATTR = 0;
51 51
52static struct viewport default_vp =
53{
54 .x = 0,
55 .y = 0,
56 .width = LCD_WIDTH,
57 .height = LCD_HEIGHT,
58 .font = FONT_SYSFIXED,
59 .drawmode = DRMODE_SOLID,
60 .xmargin = 0,
61 .ymargin = 0,
62 .fg_pattern = LCD_DEFAULT_FG,
63 .bg_pattern = LCD_DEFAULT_BG,
64 .lss_pattern = LCD_DEFAULT_BG,
65 .lse_pattern = LCD_DEFAULT_BG,
66 .lst_pattern = LCD_DEFAULT_BG,
67};
68
69/* The Gigabeat target build requires access to the current fg_pattern
70 in lcd-meg-fx.c */
52#if !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) 71#if !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR)
53static unsigned fg_pattern IDATA_ATTR = LCD_DEFAULT_FG; 72static struct viewport* current_vp IDATA_ATTR = &default_vp;
54static unsigned bg_pattern IDATA_ATTR = LCD_DEFAULT_BG;
55static unsigned lss_pattern IDATA_ATTR = LCD_DEFAULT_LS;
56static unsigned lse_pattern IDATA_ATTR = LCD_DEFAULT_BG;
57static unsigned lst_pattern IDATA_ATTR = LCD_DEFAULT_FG;
58#else 73#else
59unsigned fg_pattern IDATA_ATTR = LCD_DEFAULT_FG; 74struct viewport* current_vp IDATA_ATTR = &default_vp;
60unsigned bg_pattern IDATA_ATTR = LCD_DEFAULT_BG;
61unsigned lss_pattern IDATA_ATTR = LCD_DEFAULT_LS;
62unsigned lse_pattern IDATA_ATTR = LCD_DEFAULT_BG;
63unsigned lst_pattern IDATA_ATTR = LCD_DEFAULT_FG;
64#endif 75#endif
65 76
66static int drawmode = DRMODE_SOLID;
67static int xmargin = 0;
68static int ymargin = 0;
69static int curfont = FONT_SYSFIXED;
70
71/* LCD init */ 77/* LCD init */
72void lcd_init(void) 78void lcd_init(void)
73{ 79{
@@ -78,84 +84,115 @@ void lcd_init(void)
78 scroll_init(); 84 scroll_init();
79} 85}
80 86
87/*** Viewports ***/
88
89void lcd_set_viewport(struct viewport* vp)
90{
91 if (vp == NULL)
92 current_vp = &default_vp;
93 else
94 current_vp = vp;
95}
96
97void lcd_update_viewport(void)
98{
99 lcd_update_rect(current_vp->x, current_vp->y,
100 current_vp->width, current_vp->height);
101}
102
103void lcd_update_viewport_rect(int x, int y, int width, int height)
104{
105 lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
106}
107
81/*** parameter handling ***/ 108/*** parameter handling ***/
82 109
83void lcd_set_drawmode(int mode) 110void lcd_set_drawmode(int mode)
84{ 111{
85 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); 112 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
86} 113}
87 114
88int lcd_get_drawmode(void) 115int lcd_get_drawmode(void)
89{ 116{
90 return drawmode; 117 return current_vp->drawmode;
91} 118}
92 119
93void lcd_set_foreground(unsigned color) 120void lcd_set_foreground(unsigned color)
94{ 121{
95 fg_pattern = color; 122 current_vp->fg_pattern = color;
96} 123}
97 124
98unsigned lcd_get_foreground(void) 125unsigned lcd_get_foreground(void)
99{ 126{
100 return fg_pattern; 127 return current_vp->fg_pattern;
101} 128}
102 129
103void lcd_set_background(unsigned color) 130void lcd_set_background(unsigned color)
104{ 131{
105 bg_pattern = color; 132 current_vp->bg_pattern = color;
106} 133}
107 134
108unsigned lcd_get_background(void) 135unsigned lcd_get_background(void)
109{ 136{
110 return bg_pattern; 137 return current_vp->bg_pattern;
111} 138}
112 139
113void lcd_set_selector_start(unsigned color) 140void lcd_set_selector_start(unsigned color)
114{ 141{
115 lss_pattern = color; 142 current_vp->lss_pattern = color;
116} 143}
117 144
118void lcd_set_selector_end(unsigned color) 145void lcd_set_selector_end(unsigned color)
119{ 146{
120 lse_pattern = color; 147 current_vp->lse_pattern = color;
121} 148}
122 149
123void lcd_set_selector_text(unsigned color) 150void lcd_set_selector_text(unsigned color)
124{ 151{
125 lst_pattern = color; 152 current_vp->lst_pattern = color;
126} 153}
127 154
128void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color) 155void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color)
129{ 156{
130 lcd_set_drawmode(mode); 157 lcd_set_drawmode(mode);
131 fg_pattern = fg_color; 158 current_vp->fg_pattern = fg_color;
132 bg_pattern = bg_color; 159 current_vp->bg_pattern = bg_color;
133} 160}
134 161
135void lcd_setmargins(int x, int y) 162void lcd_setmargins(int x, int y)
136{ 163{
137 xmargin = x; 164 current_vp->xmargin = x;
138 ymargin = y; 165 current_vp->ymargin = y;
166}
167
168int lcd_getwidth(void)
169{
170 return current_vp->width;
171}
172
173int lcd_getheight(void)
174{
175 return current_vp->height;
139} 176}
140 177
141int lcd_getxmargin(void) 178int lcd_getxmargin(void)
142{ 179{
143 return xmargin; 180 return current_vp->xmargin;
144} 181}
145 182
146int lcd_getymargin(void) 183int lcd_getymargin(void)
147{ 184{
148 return ymargin; 185 return current_vp->ymargin;
149} 186}
150 187
151void lcd_setfont(int newfont) 188void lcd_setfont(int newfont)
152{ 189{
153 curfont = newfont; 190 current_vp->font = newfont;
154} 191}
155 192
156int lcd_getstringsize(const unsigned char *str, int *w, int *h) 193int lcd_getstringsize(const unsigned char *str, int *w, int *h)
157{ 194{
158 return font_getstringsize(str, w, h, curfont); 195 return font_getstringsize(str, w, h, current_vp->font);
159} 196}
160 197
161/*** low-level drawing functions ***/ 198/*** low-level drawing functions ***/
@@ -165,13 +202,13 @@ int lcd_getstringsize(const unsigned char *str, int *w, int *h)
165static void setpixel(fb_data *address) ICODE_ATTR; 202static void setpixel(fb_data *address) ICODE_ATTR;
166static void setpixel(fb_data *address) 203static void setpixel(fb_data *address)
167{ 204{
168 *address = fg_pattern; 205 *address = current_vp->fg_pattern;
169} 206}
170 207
171static void clearpixel(fb_data *address) ICODE_ATTR; 208static void clearpixel(fb_data *address) ICODE_ATTR;
172static void clearpixel(fb_data *address) 209static void clearpixel(fb_data *address)
173{ 210{
174 *address = bg_pattern; 211 *address = current_vp->bg_pattern;
175} 212}
176 213
177static void clearimgpixel(fb_data *address) ICODE_ATTR; 214static void clearimgpixel(fb_data *address) ICODE_ATTR;
@@ -226,31 +263,74 @@ fb_data* lcd_get_backdrop(void)
226 263
227/*** drawing functions ***/ 264/*** drawing functions ***/
228 265
229/* Clear the whole display */ 266/* Clear the current viewport */
230void lcd_clear_display(void) 267void lcd_clear_viewport(void)
231{ 268{
232 fb_data *dst = LCDADDR(0, 0); 269 fb_data *dst, *dst_end;
270
271 dst = LCDADDR(current_vp->x, current_vp->y);
272 dst_end = dst + current_vp->height * LCD_WIDTH;
233 273
234 if (drawmode & DRMODE_INVERSEVID) 274 if (current_vp->drawmode & DRMODE_INVERSEVID)
235 { 275 {
236 memset16(dst, fg_pattern, LCD_WIDTH*LCD_HEIGHT); 276 do
277 {
278 memset16(dst, current_vp->fg_pattern, current_vp->width);
279 dst += LCD_WIDTH;
280 }
281 while (dst < dst_end);
237 } 282 }
238 else 283 else
239 { 284 {
240 if (!lcd_backdrop) 285 if (!lcd_backdrop)
241 memset16(dst, bg_pattern, LCD_WIDTH*LCD_HEIGHT); 286 {
287 do
288 {
289 memset16(dst, current_vp->bg_pattern, current_vp->width);
290 dst += LCD_WIDTH;
291 }
292 while (dst < dst_end);
293 }
242 else 294 else
243 memcpy(dst, lcd_backdrop, sizeof(lcd_framebuffer)); 295 {
296 do
297 {
298 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset),
299 current_vp->width * sizeof(fb_data));
300 dst += LCD_WIDTH;
301 }
302 while (dst < dst_end);
303 }
244 } 304 }
245 305
246 lcd_scroll_info.lines = 0; 306 if (current_vp == &default_vp)
307 {
308 lcd_scroll_info.lines = 0;
309 }
310 else
311 {
312 lcd_scroll_stop(current_vp);
313 }
314}
315
316/* Clear the whole display */
317void lcd_clear_display(void)
318{
319 struct viewport* old_vp = current_vp;
320
321 current_vp = &default_vp;
322
323 lcd_clear_viewport();
324
325 current_vp = old_vp;
247} 326}
248 327
249/* Set a single pixel */ 328/* Set a single pixel */
250void lcd_drawpixel(int x, int y) 329void lcd_drawpixel(int x, int y)
251{ 330{
252 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) 331 if (((unsigned)x < (unsigned)current_vp->width) &&
253 lcd_fastpixelfuncs[drawmode](LCDADDR(x, y)); 332 ((unsigned)y < (unsigned)current_vp->height))
333 lcd_fastpixelfuncs[current_vp->drawmode](LCDADDR(current_vp->x+x, current_vp->y+y));
254} 334}
255 335
256/* Draw a line */ 336/* Draw a line */
@@ -262,7 +342,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
262 int d, dinc1, dinc2; 342 int d, dinc1, dinc2;
263 int x, xinc1, xinc2; 343 int x, xinc1, xinc2;
264 int y, yinc1, yinc2; 344 int y, yinc1, yinc2;
265 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; 345 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
266 346
267 deltax = abs(x2 - x1); 347 deltax = abs(x2 - x1);
268 deltay = abs(y2 - y1); 348 deltay = abs(y2 - y1);
@@ -306,8 +386,8 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
306 386
307 for (i = 0; i < numpixels; i++) 387 for (i = 0; i < numpixels; i++)
308 { 388 {
309 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) 389 if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height))
310 pfunc(LCDADDR(x, y)); 390 pfunc(LCDADDR(x + current_vp->x, y + current_vp->y));
311 391
312 if (d < 0) 392 if (d < 0)
313 { 393 {
@@ -331,7 +411,7 @@ void lcd_hline(int x1, int x2, int y)
331 unsigned bits = 0; 411 unsigned bits = 0;
332 enum fill_opt fillopt = OPT_NONE; 412 enum fill_opt fillopt = OPT_NONE;
333 fb_data *dst, *dst_end; 413 fb_data *dst, *dst_end;
334 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; 414 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
335 415
336 /* direction flip */ 416 /* direction flip */
337 if (x2 < x1) 417 if (x2 < x1)
@@ -342,23 +422,31 @@ void lcd_hline(int x1, int x2, int y)
342 } 422 }
343 423
344 /* nothing to draw? */ 424 /* nothing to draw? */
345 if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) 425 if (((unsigned)y >= (unsigned)current_vp->height) ||
426 (x1 >= current_vp->width) ||
427 (x2 < 0))
346 return; 428 return;
347 429
348 /* clipping */ 430 /* clipping */
349 if (x1 < 0) 431 if (x1 < 0)
350 x1 = 0; 432 x1 = 0;
351 if (x2 >= LCD_WIDTH) 433 if (x2 >= current_vp->width)
352 x2 = LCD_WIDTH-1; 434 x2 = current_vp->width-1;
435
436 width = x2 - x1 + 1;
353 437
354 if (drawmode & DRMODE_INVERSEVID) 438 /* Adjust x1 and y to viewport */
439 x1 += current_vp->x;
440 y += current_vp->y;
441
442 if (current_vp->drawmode & DRMODE_INVERSEVID)
355 { 443 {
356 if (drawmode & DRMODE_BG) 444 if (current_vp->drawmode & DRMODE_BG)
357 { 445 {
358 if (!lcd_backdrop) 446 if (!lcd_backdrop)
359 { 447 {
360 fillopt = OPT_SET; 448 fillopt = OPT_SET;
361 bits = bg_pattern; 449 bits = current_vp->bg_pattern;
362 } 450 }
363 else 451 else
364 fillopt = OPT_COPY; 452 fillopt = OPT_COPY;
@@ -366,14 +454,13 @@ void lcd_hline(int x1, int x2, int y)
366 } 454 }
367 else 455 else
368 { 456 {
369 if (drawmode & DRMODE_FG) 457 if (current_vp->drawmode & DRMODE_FG)
370 { 458 {
371 fillopt = OPT_SET; 459 fillopt = OPT_SET;
372 bits = fg_pattern; 460 bits = current_vp->fg_pattern;
373 } 461 }
374 } 462 }
375 dst = LCDADDR(x1, y); 463 dst = LCDADDR(x1, y);
376 width = x2 - x1 + 1;
377 464
378 switch (fillopt) 465 switch (fillopt)
379 { 466 {
@@ -400,7 +487,7 @@ void lcd_vline(int x, int y1, int y2)
400{ 487{
401 int y; 488 int y;
402 fb_data *dst, *dst_end; 489 fb_data *dst, *dst_end;
403 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; 490 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
404 491
405 /* direction flip */ 492 /* direction flip */
406 if (y2 < y1) 493 if (y2 < y1)
@@ -411,16 +498,18 @@ void lcd_vline(int x, int y1, int y2)
411 } 498 }
412 499
413 /* nothing to draw? */ 500 /* nothing to draw? */
414 if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) 501 if ((x >= current_vp->width) ||
502 (y1 >= current_vp->height) ||
503 (y2 < 0))
415 return; 504 return;
416 505
417 /* clipping */ 506 /* clipping */
418 if (y1 < 0) 507 if (y1 < 0)
419 y1 = 0; 508 y1 = 0;
420 if (y2 >= LCD_HEIGHT) 509 if (y2 >= current_vp->height)
421 y2 = LCD_HEIGHT-1; 510 y2 = current_vp->height-1;
422 511
423 dst = LCDADDR(x, y1); 512 dst = LCDADDR(x + current_vp->x, y1 + current_vp->y);
424 dst_end = dst + (y2 - y1) * LCD_WIDTH; 513 dst_end = dst + (y2 - y1) * LCD_WIDTH;
425 514
426 do 515 do
@@ -452,11 +541,11 @@ void lcd_fillrect(int x, int y, int width, int height)
452 unsigned bits = 0; 541 unsigned bits = 0;
453 enum fill_opt fillopt = OPT_NONE; 542 enum fill_opt fillopt = OPT_NONE;
454 fb_data *dst, *dst_end; 543 fb_data *dst, *dst_end;
455 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; 544 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
456 545
457 /* nothing to draw? */ 546 /* nothing to draw? */
458 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 547 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
459 || (x + width <= 0) || (y + height <= 0)) 548 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
460 return; 549 return;
461 550
462 /* clipping */ 551 /* clipping */
@@ -470,19 +559,19 @@ void lcd_fillrect(int x, int y, int width, int height)
470 height += y; 559 height += y;
471 y = 0; 560 y = 0;
472 } 561 }
473 if (x + width > LCD_WIDTH) 562 if (x + width > current_vp->width)
474 width = LCD_WIDTH - x; 563 width = current_vp->width - x;
475 if (y + height > LCD_HEIGHT) 564 if (y + height > current_vp->height)
476 height = LCD_HEIGHT - y; 565 height = current_vp->height - y;
477 566
478 if (drawmode & DRMODE_INVERSEVID) 567 if (current_vp->drawmode & DRMODE_INVERSEVID)
479 { 568 {
480 if (drawmode & DRMODE_BG) 569 if (current_vp->drawmode & DRMODE_BG)
481 { 570 {
482 if (!lcd_backdrop) 571 if (!lcd_backdrop)
483 { 572 {
484 fillopt = OPT_SET; 573 fillopt = OPT_SET;
485 bits = bg_pattern; 574 bits = current_vp->bg_pattern;
486 } 575 }
487 else 576 else
488 fillopt = OPT_COPY; 577 fillopt = OPT_COPY;
@@ -490,13 +579,13 @@ void lcd_fillrect(int x, int y, int width, int height)
490 } 579 }
491 else 580 else
492 { 581 {
493 if (drawmode & DRMODE_FG) 582 if (current_vp->drawmode & DRMODE_FG)
494 { 583 {
495 fillopt = OPT_SET; 584 fillopt = OPT_SET;
496 bits = fg_pattern; 585 bits = current_vp->fg_pattern;
497 } 586 }
498 } 587 }
499 dst = LCDADDR(x, y); 588 dst = LCDADDR(current_vp->x + x, current_vp->y + y);
500 dst_end = dst + height * LCD_WIDTH; 589 dst_end = dst + height * LCD_WIDTH;
501 590
502 do 591 do
@@ -530,24 +619,28 @@ void lcd_fillrect(int x, int y, int width, int height)
530/* Fill a rectangle with a gradient */ 619/* Fill a rectangle with a gradient */
531void lcd_gradient_rect(int x1, int x2, int y, int h) 620void lcd_gradient_rect(int x1, int x2, int y, int h)
532{ 621{
622 int old_pattern = current_vp->fg_pattern;
623
533 if (h == 0) return; 624 if (h == 0) return;
534 625
535 int h_r = RGB_UNPACK_RED(lss_pattern) << 16; 626 int h_r = RGB_UNPACK_RED(current_vp->lss_pattern) << 16;
536 int h_b = RGB_UNPACK_BLUE(lss_pattern) << 16; 627 int h_b = RGB_UNPACK_BLUE(current_vp->lss_pattern) << 16;
537 int h_g = RGB_UNPACK_GREEN(lss_pattern) << 16; 628 int h_g = RGB_UNPACK_GREEN(current_vp->lss_pattern) << 16;
538 int rstep = (h_r - ((signed)RGB_UNPACK_RED(lse_pattern) << 16)) / h; 629 int rstep = (h_r - ((signed)RGB_UNPACK_RED(current_vp->lse_pattern) << 16)) / h;
539 int gstep = (h_g - ((signed)RGB_UNPACK_GREEN(lse_pattern) << 16)) / h; 630 int gstep = (h_g - ((signed)RGB_UNPACK_GREEN(current_vp->lse_pattern) << 16)) / h;
540 int bstep = (h_b - ((signed)RGB_UNPACK_BLUE(lse_pattern) << 16)) / h; 631 int bstep = (h_b - ((signed)RGB_UNPACK_BLUE(current_vp->lse_pattern) << 16)) / h;
541 int count; 632 int count;
542 633
543 fg_pattern = lss_pattern; 634 current_vp->fg_pattern = current_vp->lss_pattern;
544 for(count = 0; count < h; count++) { 635 for(count = 0; count < h; count++) {
545 lcd_hline(x1, x2, y + count); 636 lcd_hline(x1, x2, y + count);
546 h_r -= rstep; 637 h_r -= rstep;
547 h_g -= gstep; 638 h_g -= gstep;
548 h_b -= bstep; 639 h_b -= bstep;
549 fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16); 640 current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16);
550 } 641 }
642
643 current_vp->fg_pattern = old_pattern;
551} 644}
552 645
553#define H_COLOR(lss, lse, cur_line, max_line) \ 646#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,
562{ 655{
563 if (h == 0 || num_lines == 0) return; 656 if (h == 0 || num_lines == 0) return;
564 657
565 unsigned tmp_lss = lss_pattern; 658 unsigned tmp_lss = current_vp->lss_pattern;
566 unsigned tmp_lse = lse_pattern; 659 unsigned tmp_lse = current_vp->lse_pattern;
567 int lss_r = (signed)RGB_UNPACK_RED(lss_pattern); 660 int lss_r = (signed)RGB_UNPACK_RED(current_vp->lss_pattern);
568 int lss_b = (signed)RGB_UNPACK_BLUE(lss_pattern); 661 int lss_b = (signed)RGB_UNPACK_BLUE(current_vp->lss_pattern);
569 int lss_g = (signed)RGB_UNPACK_GREEN(lss_pattern); 662 int lss_g = (signed)RGB_UNPACK_GREEN(current_vp->lss_pattern);
570 int lse_r = (signed)RGB_UNPACK_RED(lse_pattern); 663 int lse_r = (signed)RGB_UNPACK_RED(current_vp->lse_pattern);
571 int lse_b = (signed)RGB_UNPACK_BLUE(lse_pattern); 664 int lse_b = (signed)RGB_UNPACK_BLUE(current_vp->lse_pattern);
572 int lse_g = (signed)RGB_UNPACK_GREEN(lse_pattern); 665 int lse_g = (signed)RGB_UNPACK_GREEN(current_vp->lse_pattern);
573 666
574 int h_r = H_COLOR(lss_r, lse_r, cur_line, num_lines); 667 int h_r = H_COLOR(lss_r, lse_r, cur_line, num_lines);
575 int h_g = H_COLOR(lss_g, lse_g, cur_line, num_lines); 668 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,
583 676
584 lcd_gradient_rect(x1, x2, y, h); 677 lcd_gradient_rect(x1, x2, y, h);
585 678
586 lcd_set_selector_start(tmp_lss); 679 current_vp->lss_pattern = tmp_lss;
587 lcd_set_selector_end(tmp_lse); 680 current_vp->lse_pattern = tmp_lse;
588} 681}
589 682
590/* About Rockbox' internal monochrome bitmap format: 683/* 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,
613 lcd_fastpixelfunc_type *fgfunc, *bgfunc; 706 lcd_fastpixelfunc_type *fgfunc, *bgfunc;
614 707
615 /* nothing to draw? */ 708 /* nothing to draw? */
616 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 709 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
617 || (x + width <= 0) || (y + height <= 0)) 710 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
618 return; 711 return;
619 712
620 /* clipping */ 713 /* clipping */
@@ -630,20 +723,20 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
630 src_y -= y; 723 src_y -= y;
631 y = 0; 724 y = 0;
632 } 725 }
633 if (x + width > LCD_WIDTH) 726 if (x + width > current_vp->width)
634 width = LCD_WIDTH - x; 727 width = current_vp->width - x;
635 if (y + height > LCD_HEIGHT) 728 if (y + height > current_vp->height)
636 height = LCD_HEIGHT - y; 729 height = current_vp->height - y;
637 730
638 src += stride * (src_y >> 3) + src_x; /* move starting point */ 731 src += stride * (src_y >> 3) + src_x; /* move starting point */
639 src_y &= 7; 732 src_y &= 7;
640 src_end = src + width; 733 src_end = src + width;
641 734
642 dst = LCDADDR(x, y); 735 dst = LCDADDR(current_vp->x + x, current_vp->y + y);
643 has_backdrop = (lcd_backdrop != NULL); 736 has_backdrop = (lcd_backdrop != NULL);
644 backdrop = lcd_backdrop + y * LCD_WIDTH + x; 737 backdrop = lcd_backdrop + (current_vp->y + y) * LCD_WIDTH + current_vp->x + x;
645 fgfunc = lcd_fastpixelfuncs[drawmode]; 738 fgfunc = lcd_fastpixelfuncs[current_vp->drawmode];
646 bgfunc = lcd_fastpixelfuncs[drawmode ^ DRMODE_INVERSEVID]; 739 bgfunc = lcd_fastpixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID];
647 do 740 do
648 { 741 {
649 const unsigned char *src_col = src++; 742 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,
654 dst_end = dst_col + height * LCD_WIDTH; 747 dst_end = dst_col + height * LCD_WIDTH;
655 do 748 do
656 { 749 {
657 switch (drawmode) 750 switch (current_vp->drawmode)
658 { 751 {
659 case DRMODE_SOLID: 752 case DRMODE_SOLID:
660 if (data & 0x01) 753 if (data & 0x01)
661 *dst_col = fg_pattern; 754 *dst_col = current_vp->fg_pattern;
662 else 755 else
663 *dst_col = has_backdrop ? *backdrop_col : bg_pattern; 756 *dst_col = has_backdrop ? *backdrop_col : current_vp->bg_pattern;
664 break; 757 break;
665 case DRMODE_FG: 758 case DRMODE_FG:
666 if (data & 0x01) 759 if (data & 0x01)
667 *dst_col = fg_pattern; 760 *dst_col = current_vp->fg_pattern;
668 break; 761 break;
669 case (DRMODE_SOLID|DRMODE_INVERSEVID): 762 case (DRMODE_SOLID|DRMODE_INVERSEVID):
670 if (data & 0x01) 763 if (data & 0x01)
671 *dst_col = has_backdrop ? *backdrop_col : bg_pattern; 764 *dst_col = has_backdrop ? *backdrop_col : current_vp->bg_pattern;
672 else 765 else
673 *dst_col = fg_pattern; 766 *dst_col = current_vp->fg_pattern;
674 break; 767 break;
675 default: 768 default:
676 if (data & 0x01) 769 if (data & 0x01)
@@ -709,8 +802,8 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
709 fb_data *dst, *dst_end; 802 fb_data *dst, *dst_end;
710 803
711 /* nothing to draw? */ 804 /* nothing to draw? */
712 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 805 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
713 || (x + width <= 0) || (y + height <= 0)) 806 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
714 return; 807 return;
715 808
716 /* clipping */ 809 /* clipping */
@@ -726,13 +819,13 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
726 src_y -= y; 819 src_y -= y;
727 y = 0; 820 y = 0;
728 } 821 }
729 if (x + width > LCD_WIDTH) 822 if (x + width > current_vp->width)
730 width = LCD_WIDTH - x; 823 width = current_vp->width - x;
731 if (y + height > LCD_HEIGHT) 824 if (y + height > current_vp->height)
732 height = LCD_HEIGHT - y; 825 height = current_vp->height - y;
733 826
734 src += stride * src_y + src_x; /* move starting point */ 827 src += stride * src_y + src_x; /* move starting point */
735 dst = LCDADDR(x, y); 828 dst = LCDADDR(current_vp->x + x, current_vp->y + y);
736 dst_end = dst + height * LCD_WIDTH; 829 dst_end = dst + height * LCD_WIDTH;
737 830
738 do 831 do
@@ -763,8 +856,8 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y,
763 fb_data *dst, *dst_end; 856 fb_data *dst, *dst_end;
764 857
765 /* nothing to draw? */ 858 /* nothing to draw? */
766 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 859 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
767 || (x + width <= 0) || (y + height <= 0)) 860 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
768 return; 861 return;
769 862
770 /* clipping */ 863 /* clipping */
@@ -780,13 +873,13 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y,
780 src_y -= y; 873 src_y -= y;
781 y = 0; 874 y = 0;
782 } 875 }
783 if (x + width > LCD_WIDTH) 876 if (x + width > current_vp->width)
784 width = LCD_WIDTH - x; 877 width = current_vp->width - x;
785 if (y + height > LCD_HEIGHT) 878 if (y + height > current_vp->height)
786 height = LCD_HEIGHT - y; 879 height = current_vp->height - y;
787 880
788 src += stride * src_y + src_x; /* move starting point */ 881 src += stride * src_y + src_x; /* move starting point */
789 dst = LCDADDR(x, y); 882 dst = LCDADDR(current_vp->x + x, current_vp->y + y);
790 dst_end = dst + height * LCD_WIDTH; 883 dst_end = dst + height * LCD_WIDTH;
791 884
792 do 885 do
@@ -795,7 +888,7 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y,
795 for(i = 0;i < width;i++) 888 for(i = 0;i < width;i++)
796 { 889 {
797 if (src[i] == REPLACEWITHFG_COLOR) 890 if (src[i] == REPLACEWITHFG_COLOR)
798 dst[i] = fg_pattern; 891 dst[i] = current_vp->fg_pattern;
799 else if(src[i] != TRANSPARENT_COLOR) 892 else if(src[i] != TRANSPARENT_COLOR)
800 dst[i] = src[i]; 893 dst[i] = src[i];
801 } 894 }
@@ -818,11 +911,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
818{ 911{
819 unsigned short ch; 912 unsigned short ch;
820 unsigned short *ucs; 913 unsigned short *ucs;
821 struct font* pf = font_get(curfont); 914 struct font* pf = font_get(current_vp->font);
822 915
823 ucs = bidi_l2v(str, 1); 916 ucs = bidi_l2v(str, 1);
824 917
825 while ((ch = *ucs++) != 0 && x < LCD_WIDTH) 918 while ((ch = *ucs++) != 0 && x < current_vp->width)
826 { 919 {
827 int width; 920 int width;
828 const unsigned char *bits; 921 const unsigned char *bits;
@@ -875,51 +968,51 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str, int style,
875 int offset) 968 int offset)
876{ 969{
877 int xpos,ypos,w,h,xrect; 970 int xpos,ypos,w,h,xrect;
878 int lastmode = drawmode; 971 int lastmode = current_vp->drawmode;
879 int oldfgcolor = fg_pattern; 972 int oldfgcolor = current_vp->fg_pattern;
880 int oldbgcolor = bg_pattern; 973 int oldbgcolor = current_vp->bg_pattern;
881 974
882 /* make sure scrolling is turned off on the line we are updating */ 975 /* make sure scrolling is turned off on the line we are updating */
883 lcd_scroll_info.lines &= ~(1 << y); 976 lcd_scroll_stop_line(current_vp, y);
884 977
885 if(!str || !str[0]) 978 if(!str || !str[0])
886 return; 979 return;
887 980
888 lcd_getstringsize(str, &w, &h); 981 lcd_getstringsize(str, &w, &h);
889 xpos = xmargin + x*w / utf8length(str); 982 xpos = current_vp->xmargin + x*w / utf8length(str);
890 ypos = ymargin + y*h; 983 ypos = current_vp->ymargin + y*h;
891 drawmode = (style & STYLE_INVERT) ? 984 current_vp->drawmode = (style & STYLE_INVERT) ?
892 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 985 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
893 if (style & STYLE_COLORED) { 986 if (style & STYLE_COLORED) {
894 if (drawmode == DRMODE_SOLID) 987 if (current_vp->drawmode == DRMODE_SOLID)
895 fg_pattern = style & STYLE_COLOR_MASK; 988 current_vp->fg_pattern = style & STYLE_COLOR_MASK;
896 else 989 else
897 bg_pattern = style & STYLE_COLOR_MASK; 990 current_vp->bg_pattern = style & STYLE_COLOR_MASK;
898 } 991 }
899 drawmode ^= DRMODE_INVERSEVID; 992 current_vp->drawmode ^= DRMODE_INVERSEVID;
900 xrect = xpos + MAX(w - offset, 0); 993 xrect = xpos + MAX(w - offset, 0);
901 994
902 if (style & STYLE_GRADIENT) { 995 if (style & STYLE_GRADIENT) {
903 drawmode = DRMODE_FG; 996 current_vp->drawmode = DRMODE_FG;
904 if (CURLN_UNPACK(style) == 0) 997 if (CURLN_UNPACK(style) == 0)
905 lcd_gradient_rect(xpos, LCD_WIDTH, ypos, h*NUMLN_UNPACK(style)); 998 lcd_gradient_rect(xpos, current_vp->width, ypos, h*NUMLN_UNPACK(style));
906 fg_pattern = lst_pattern; 999 current_vp->fg_pattern = current_vp->lst_pattern;
907 } 1000 }
908 else if (style & STYLE_COLORBAR) { 1001 else if (style & STYLE_COLORBAR) {
909 drawmode = DRMODE_FG; 1002 current_vp->drawmode = DRMODE_FG;
910 fg_pattern = lss_pattern; 1003 current_vp->fg_pattern = current_vp->lss_pattern;
911 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h); 1004 lcd_fillrect(xpos, ypos, current_vp->width - xpos, h);
912 fg_pattern = lst_pattern; 1005 current_vp->fg_pattern = current_vp->lst_pattern;
913 } 1006 }
914 else { 1007 else {
915 lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); 1008 lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
916 drawmode = (style & STYLE_INVERT) ? 1009 current_vp->drawmode = (style & STYLE_INVERT) ?
917 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 1010 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
918 } 1011 }
919 lcd_putsxyofs(xpos, ypos, offset, str); 1012 lcd_putsxyofs(xpos, ypos, offset, str);
920 drawmode = lastmode; 1013 current_vp->drawmode = lastmode;
921 fg_pattern = oldfgcolor; 1014 current_vp->fg_pattern = oldfgcolor;
922 bg_pattern = oldbgcolor; 1015 current_vp->bg_pattern = oldbgcolor;
923} 1016}
924 1017
925/*** scrolling ***/ 1018/*** scrolling ***/
@@ -938,15 +1031,23 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, int offse
938 lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset); 1031 lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
939} 1032}
940 1033
1034/* Initialise a scrolling line at (x,y) in current viewport */
1035
941void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, 1036void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
942 int style, int offset) 1037 int style, int offset)
943{ 1038{
944 struct scrollinfo* s; 1039 struct scrollinfo* s;
945 int w, h; 1040 int w, h;
946 1041
947 if(y>=LCD_SCROLLABLE_LINES) return; 1042 if ((unsigned)y >= (unsigned)current_vp->height)
1043 return;
1044
1045 /* remove any previously scrolling line at the same location */
1046 lcd_scroll_stop_line(current_vp, y);
1047
1048 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
948 1049
949 s = &lcd_scroll_info.scroll[y]; 1050 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
950 1051
951 s->start_tick = current_tick + lcd_scroll_info.delay; 1052 s->start_tick = current_tick + lcd_scroll_info.delay;
952 s->style = style; 1053 s->style = style;
@@ -954,7 +1055,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
954 1055
955 lcd_getstringsize(string, &w, &h); 1056 lcd_getstringsize(string, &w, &h);
956 1057
957 if (LCD_WIDTH - x * 8 - xmargin < w) { 1058 if (current_vp->width - x * 8 - current_vp->xmargin < w) {
958 /* prepare scroll line */ 1059 /* prepare scroll line */
959 char *end; 1060 char *end;
960 1061
@@ -967,7 +1068,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
967 /* scroll bidirectional or forward only depending on the string 1068 /* scroll bidirectional or forward only depending on the string
968 width */ 1069 width */
969 if ( lcd_scroll_info.bidir_limit ) { 1070 if ( lcd_scroll_info.bidir_limit ) {
970 s->bidir = s->width < (LCD_WIDTH - xmargin) * 1071 s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
971 (100 + lcd_scroll_info.bidir_limit) / 100; 1072 (100 + lcd_scroll_info.bidir_limit) / 100;
972 } 1073 }
973 else 1074 else
@@ -980,17 +1081,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
980 } 1081 }
981 1082
982 end = strchr(s->line, '\0'); 1083 end = strchr(s->line, '\0');
983 strncpy(end, string, LCD_WIDTH/2); 1084 strncpy(end, string, current_vp->width/2);
984 1085
1086 s->vp = current_vp;
1087 s->y = y;
985 s->len = utf8length(string); 1088 s->len = utf8length(string);
986 s->offset = offset; 1089 s->offset = offset;
987 s->startx = xmargin + x * s->width / s->len; 1090 s->startx = current_vp->xmargin + x * s->width / s->len;
988 s->backward = false; 1091 s->backward = false;
989 lcd_scroll_info.lines |= (1<<y); 1092 lcd_scroll_info.lines++;
990 } 1093 }
991 else
992 /* force a bit switch-off since it doesn't scroll */
993 lcd_scroll_info.lines &= ~(1<<y);
994} 1094}
995 1095
996void lcd_scroll_fn(void) 1096void lcd_scroll_fn(void)
@@ -1000,28 +1100,29 @@ void lcd_scroll_fn(void)
1000 int index; 1100 int index;
1001 int xpos, ypos; 1101 int xpos, ypos;
1002 int lastmode; 1102 int lastmode;
1003 unsigned old_fgcolor = fg_pattern; 1103 unsigned old_fgcolor;
1004 unsigned old_bgcolor = bg_pattern; 1104 unsigned old_bgcolor;
1005 1105 struct viewport* old_vp = current_vp;
1006 for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) {
1007 /* really scroll? */
1008 if ((lcd_scroll_info.lines & (1 << index)) == 0)
1009 continue;
1010 1106
1107 for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
1011 s = &lcd_scroll_info.scroll[index]; 1108 s = &lcd_scroll_info.scroll[index];
1012 1109
1013 /* check pause */ 1110 /* check pause */
1014 if (TIME_BEFORE(current_tick, s->start_tick)) 1111 if (TIME_BEFORE(current_tick, s->start_tick))
1015 continue; 1112 continue;
1016 1113
1114 lcd_set_viewport(s->vp);
1115 old_fgcolor = current_vp->fg_pattern;
1116 old_bgcolor = current_vp->bg_pattern;
1117
1017 if (s->style&STYLE_COLORED) { 1118 if (s->style&STYLE_COLORED) {
1018 if (s->style&STYLE_MODE_MASK) { 1119 if (s->style&STYLE_MODE_MASK) {
1019 fg_pattern = old_fgcolor; 1120 current_vp->fg_pattern = old_fgcolor;
1020 bg_pattern = s->style&STYLE_COLOR_MASK; 1121 current_vp->bg_pattern = s->style&STYLE_COLOR_MASK;
1021 } 1122 }
1022 else { 1123 else {
1023 fg_pattern = s->style&STYLE_COLOR_MASK; 1124 current_vp->fg_pattern = s->style&STYLE_COLOR_MASK;
1024 bg_pattern = old_bgcolor; 1125 current_vp->bg_pattern = old_bgcolor;
1025 } 1126 }
1026 } 1127 }
1027 1128
@@ -1030,9 +1131,9 @@ void lcd_scroll_fn(void)
1030 else 1131 else
1031 s->offset += lcd_scroll_info.step; 1132 s->offset += lcd_scroll_info.step;
1032 1133
1033 pf = font_get(curfont); 1134 pf = font_get(current_vp->font);
1034 xpos = s->startx; 1135 xpos = s->startx;
1035 ypos = ymargin + index * pf->height; 1136 ypos = current_vp->ymargin + s->y * pf->height;
1036 1137
1037 if (s->bidir) { /* scroll bidirectional */ 1138 if (s->bidir) { /* scroll bidirectional */
1038 if (s->offset <= 0) { 1139 if (s->offset <= 0) {
@@ -1041,9 +1142,9 @@ void lcd_scroll_fn(void)
1041 s->backward = false; 1142 s->backward = false;
1042 s->start_tick = current_tick + lcd_scroll_info.delay * 2; 1143 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1043 } 1144 }
1044 if (s->offset >= s->width - (LCD_WIDTH - xpos)) { 1145 if (s->offset >= s->width - (current_vp->width - xpos)) {
1045 /* at end of line */ 1146 /* at end of line */
1046 s->offset = s->width - (LCD_WIDTH - xpos); 1147 s->offset = s->width - (current_vp->width - xpos);
1047 s->backward = true; 1148 s->backward = true;
1048 s->start_tick = current_tick + lcd_scroll_info.delay * 2; 1149 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1049 } 1150 }
@@ -1054,35 +1155,36 @@ void lcd_scroll_fn(void)
1054 s->offset %= s->width; 1155 s->offset %= s->width;
1055 } 1156 }
1056 1157
1057 lastmode = drawmode; 1158 lastmode = current_vp->drawmode;
1058 switch (s->style&STYLE_MODE_MASK) { 1159 switch (s->style&STYLE_MODE_MASK) {
1059 case STYLE_INVERT: 1160 case STYLE_INVERT:
1060 drawmode = DRMODE_SOLID|DRMODE_INVERSEVID; 1161 current_vp->drawmode = DRMODE_SOLID|DRMODE_INVERSEVID;
1061 break; 1162 break;
1062 case STYLE_COLORBAR: 1163 case STYLE_COLORBAR:
1063 /* Solid colour line selector */ 1164 /* Solid colour line selector */
1064 drawmode = DRMODE_FG; 1165 current_vp->drawmode = DRMODE_FG;
1065 fg_pattern = lss_pattern; 1166 current_vp->fg_pattern = current_vp->lss_pattern;
1066 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 1167 lcd_fillrect(xpos, ypos, current_vp->width - xpos, pf->height);
1067 fg_pattern = lst_pattern; 1168 current_vp->fg_pattern = current_vp->lst_pattern;
1068 break; 1169 break;
1069 case STYLE_GRADIENT: 1170 case STYLE_GRADIENT:
1070 /* Gradient line selector */ 1171 /* Gradient line selector */
1071 drawmode = DRMODE_FG; 1172 current_vp->drawmode = DRMODE_FG;
1072 lcd_gradient_rect_scroll(xpos, LCD_WIDTH, ypos, (signed)pf->height, 1173 lcd_gradient_rect_scroll(xpos, current_vp->width, ypos, (signed)pf->height,
1073 NUMLN_UNPACK(s->style), 1174 NUMLN_UNPACK(s->style),
1074 CURLN_UNPACK(s->style)); 1175 CURLN_UNPACK(s->style));
1075 fg_pattern = lst_pattern; 1176 current_vp->fg_pattern = current_vp->lst_pattern;
1076 break; 1177 break;
1077 default: 1178 default:
1078 drawmode = DRMODE_SOLID; 1179 current_vp->drawmode = DRMODE_SOLID;
1079 break; 1180 break;
1080 } 1181 }
1081 lcd_putsxyofs(xpos, ypos, s->offset, s->line); 1182 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
1082 drawmode = lastmode; 1183 current_vp->drawmode = lastmode;
1083 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 1184 current_vp->fg_pattern = old_fgcolor;
1185 current_vp->bg_pattern = old_bgcolor;
1186 lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height);
1084 } 1187 }
1085 1188
1086 fg_pattern = old_fgcolor; 1189 lcd_set_viewport(old_vp);
1087 bg_pattern = old_bgcolor;
1088} 1190}
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 @@
35 35
36unsigned char lcd_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH]; 36unsigned char lcd_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH];
37 37
38static int drawmode = DRMODE_SOLID; 38static struct viewport default_vp =
39static int xmargin = 0; 39{
40static int ymargin = 0; 40 .x = 0,
41static int curfont = FONT_SYSFIXED; 41 .y = 0,
42 .width = LCD_WIDTH,
43 .height = LCD_HEIGHT,
44 .font = FONT_SYSFIXED,
45 .drawmode = DRMODE_SOLID,
46 .xmargin = 0,
47 .ymargin = 0,
48};
49
50static struct viewport* current_vp = &default_vp;
51
52/*** Viewports ***/
53
54void lcd_set_viewport(struct viewport* vp)
55{
56 if (vp == NULL)
57 current_vp = &default_vp;
58 else
59 current_vp = vp;
60}
61
62void lcd_update_viewport(void)
63{
64 lcd_update_rect(current_vp->x, current_vp->y,
65 current_vp->width, current_vp->height);
66}
67
68void lcd_update_viewport_rect(int x, int y, int width, int height)
69{
70 lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
71}
42 72
43/* LCD init */ 73/* LCD init */
44void lcd_init(void) 74void lcd_init(void)
@@ -53,38 +83,48 @@ void lcd_init(void)
53 83
54void lcd_set_drawmode(int mode) 84void lcd_set_drawmode(int mode)
55{ 85{
56 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); 86 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
57} 87}
58 88
59int lcd_get_drawmode(void) 89int lcd_get_drawmode(void)
60{ 90{
61 return drawmode; 91 return current_vp->drawmode;
62} 92}
63 93
64void lcd_setmargins(int x, int y) 94void lcd_setmargins(int x, int y)
65{ 95{
66 xmargin = x; 96 current_vp->xmargin = x;
67 ymargin = y; 97 current_vp->ymargin = y;
68} 98}
69 99
70int lcd_getxmargin(void) 100int lcd_getxmargin(void)
71{ 101{
72 return xmargin; 102 return current_vp->xmargin;
73} 103}
74 104
75int lcd_getymargin(void) 105int lcd_getymargin(void)
76{ 106{
77 return ymargin; 107 return current_vp->ymargin;
108}
109
110int lcd_getwidth(void)
111{
112 return current_vp->width;
113}
114
115int lcd_getheight(void)
116{
117 return current_vp->height;
78} 118}
79 119
80void lcd_setfont(int newfont) 120void lcd_setfont(int newfont)
81{ 121{
82 curfont = newfont; 122 current_vp->font = newfont;
83} 123}
84 124
85int lcd_getstringsize(const unsigned char *str, int *w, int *h) 125int lcd_getstringsize(const unsigned char *str, int *w, int *h)
86{ 126{
87 return font_getstringsize(str, w, h, curfont); 127 return font_getstringsize(str, w, h, current_vp->font);
88} 128}
89 129
90/*** low-level drawing functions ***/ 130/*** low-level drawing functions ***/
@@ -187,17 +227,42 @@ lcd_blockfunc_type* const lcd_blockfuncs[8] = {
187/* Clear the whole display */ 227/* Clear the whole display */
188void lcd_clear_display(void) 228void lcd_clear_display(void)
189{ 229{
190 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; 230 unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
191 231
192 memset(lcd_framebuffer, bits, sizeof lcd_framebuffer); 232 memset(lcd_framebuffer, bits, sizeof lcd_framebuffer);
193 lcd_scroll_info.lines = 0; 233 lcd_scroll_info.lines = 0;
194} 234}
195 235
236void lcd_clear_viewport(void)
237{
238 int oldmode;
239
240 if (current_vp == &default_vp)
241 {
242 lcd_clear_display();
243 }
244 else
245 {
246 oldmode = current_vp->drawmode;
247
248 /* Invert the INVERSEVID bit and set basic mode to SOLID */
249 current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) |
250 DRMODE_SOLID;
251
252 lcd_fillrect(0, 0, current_vp->width, current_vp->height);
253
254 current_vp->drawmode = oldmode;
255
256 lcd_scroll_stop(current_vp);
257 }
258}
259
196/* Set a single pixel */ 260/* Set a single pixel */
197void lcd_drawpixel(int x, int y) 261void lcd_drawpixel(int x, int y)
198{ 262{
199 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) 263 if (((unsigned)x < (unsigned)current_vp->width) &&
200 lcd_pixelfuncs[drawmode](x, y); 264 ((unsigned)y < (unsigned)current_vp->height))
265 lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
201} 266}
202 267
203/* Draw a line */ 268/* Draw a line */
@@ -209,7 +274,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
209 int d, dinc1, dinc2; 274 int d, dinc1, dinc2;
210 int x, xinc1, xinc2; 275 int x, xinc1, xinc2;
211 int y, yinc1, yinc2; 276 int y, yinc1, yinc2;
212 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; 277 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
213 278
214 deltax = abs(x2 - x1); 279 deltax = abs(x2 - x1);
215 deltay = abs(y2 - y1); 280 deltay = abs(y2 - y1);
@@ -253,8 +318,9 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
253 318
254 for (i = 0; i < numpixels; i++) 319 for (i = 0; i < numpixels; i++)
255 { 320 {
256 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) 321 if (((unsigned)x < (unsigned)current_vp->width) &&
257 pfunc(x, y); 322 ((unsigned)y < (unsigned)current_vp->height))
323 pfunc(current_vp->x + x, current_vp->y + y);
258 324
259 if (d < 0) 325 if (d < 0)
260 { 326 {
@@ -288,16 +354,22 @@ void lcd_hline(int x1, int x2, int y)
288 } 354 }
289 355
290 /* nothing to draw? */ 356 /* nothing to draw? */
291 if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) 357 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
358 || (x2 < 0))
292 return; 359 return;
293 360
294 /* clipping */ 361 /* clipping */
295 if (x1 < 0) 362 if (x1 < 0)
296 x1 = 0; 363 x1 = 0;
297 if (x2 >= LCD_WIDTH) 364 if (x2 >= current_vp->width)
298 x2 = LCD_WIDTH-1; 365 x2 = current_vp->width-1;
299 366
300 bfunc = lcd_blockfuncs[drawmode]; 367 /* adjust for viewport */
368 y += current_vp->y;
369 x1 += current_vp->x;
370 x2 += current_vp->x;
371
372 bfunc = lcd_blockfuncs[current_vp->drawmode];
301 dst = &lcd_framebuffer[y>>3][x1]; 373 dst = &lcd_framebuffer[y>>3][x1];
302 mask = 1 << (y & 7); 374 mask = 1 << (y & 7);
303 375
@@ -324,16 +396,22 @@ void lcd_vline(int x, int y1, int y2)
324 } 396 }
325 397
326 /* nothing to draw? */ 398 /* nothing to draw? */
327 if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) 399 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
400 || (y2 < 0))
328 return; 401 return;
329 402
330 /* clipping */ 403 /* clipping */
331 if (y1 < 0) 404 if (y1 < 0)
332 y1 = 0; 405 y1 = 0;
333 if (y2 >= LCD_HEIGHT) 406 if (y2 >= current_vp->height)
334 y2 = LCD_HEIGHT-1; 407 y2 = current_vp->height-1;
335 408
336 bfunc = lcd_blockfuncs[drawmode]; 409 /* adjust for viewport */
410 y1 += current_vp->y;
411 y2 += current_vp->y;
412 x += current_vp->x;
413
414 bfunc = lcd_blockfuncs[current_vp->drawmode];
337 dst = &lcd_framebuffer[y1>>3][x]; 415 dst = &lcd_framebuffer[y1>>3][x];
338 ny = y2 - (y1 & ~7); 416 ny = y2 - (y1 & ~7);
339 mask = 0xFFu << (y1 & 7); 417 mask = 0xFFu << (y1 & 7);
@@ -375,8 +453,8 @@ void lcd_fillrect(int x, int y, int width, int height)
375 bool fillopt = false; 453 bool fillopt = false;
376 454
377 /* nothing to draw? */ 455 /* nothing to draw? */
378 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 456 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
379 || (x + width <= 0) || (y + height <= 0)) 457 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
380 return; 458 return;
381 459
382 /* clipping */ 460 /* clipping */
@@ -390,27 +468,31 @@ void lcd_fillrect(int x, int y, int width, int height)
390 height += y; 468 height += y;
391 y = 0; 469 y = 0;
392 } 470 }
393 if (x + width > LCD_WIDTH) 471 if (x + width > current_vp->width)
394 width = LCD_WIDTH - x; 472 width = current_vp->width - x;
395 if (y + height > LCD_HEIGHT) 473 if (y + height > current_vp->height)
396 height = LCD_HEIGHT - y; 474 height = current_vp->height - y;
397 475
398 if (drawmode & DRMODE_INVERSEVID) 476 /* adjust for viewport */
477 x += current_vp->x;
478 y += current_vp->y;
479
480 if (current_vp->drawmode & DRMODE_INVERSEVID)
399 { 481 {
400 if (drawmode & DRMODE_BG) 482 if (current_vp->drawmode & DRMODE_BG)
401 { 483 {
402 fillopt = true; 484 fillopt = true;
403 } 485 }
404 } 486 }
405 else 487 else
406 { 488 {
407 if (drawmode & DRMODE_FG) 489 if (current_vp->drawmode & DRMODE_FG)
408 { 490 {
409 fillopt = true; 491 fillopt = true;
410 bits = 0xFFu; 492 bits = 0xFFu;
411 } 493 }
412 } 494 }
413 bfunc = lcd_blockfuncs[drawmode]; 495 bfunc = lcd_blockfuncs[current_vp->drawmode];
414 dst = &lcd_framebuffer[y>>3][x]; 496 dst = &lcd_framebuffer[y>>3][x];
415 ny = height - 1 + (y & 7); 497 ny = height - 1 + (y & 7);
416 mask = 0xFFu << (y & 7); 498 mask = 0xFFu << (y & 7);
@@ -470,8 +552,8 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
470 lcd_blockfunc_type *bfunc; 552 lcd_blockfunc_type *bfunc;
471 553
472 /* nothing to draw? */ 554 /* nothing to draw? */
473 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 555 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
474 || (x + width <= 0) || (y + height <= 0)) 556 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
475 return; 557 return;
476 558
477 /* clipping */ 559 /* clipping */
@@ -487,10 +569,14 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
487 src_y -= y; 569 src_y -= y;
488 y = 0; 570 y = 0;
489 } 571 }
490 if (x + width > LCD_WIDTH) 572 if (x + width > current_vp->width)
491 width = LCD_WIDTH - x; 573 width = current_vp->width - x;
492 if (y + height > LCD_HEIGHT) 574 if (y + height > current_vp->height)
493 height = LCD_HEIGHT - y; 575 height = current_vp->height - y;
576
577 /* adjust for viewport */
578 x += current_vp->x;
579 y += current_vp->y;
494 580
495 src += stride * (src_y >> 3) + src_x; /* move starting point */ 581 src += stride * (src_y >> 3) + src_x; /* move starting point */
496 src_y &= 7; 582 src_y &= 7;
@@ -499,13 +585,13 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
499 shift = y & 7; 585 shift = y & 7;
500 ny = height - 1 + shift + src_y; 586 ny = height - 1 + shift + src_y;
501 587
502 bfunc = lcd_blockfuncs[drawmode]; 588 bfunc = lcd_blockfuncs[current_vp->drawmode];
503 mask = 0xFFu << (shift + src_y); 589 mask = 0xFFu << (shift + src_y);
504 mask_bottom = 0xFFu >> (~ny & 7); 590 mask_bottom = 0xFFu >> (~ny & 7);
505 591
506 if (shift == 0) 592 if (shift == 0)
507 { 593 {
508 bool copyopt = (drawmode == DRMODE_SOLID); 594 bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
509 595
510 for (; ny >= 8; ny -= 8) 596 for (; ny >= 8; ny -= 8)
511 { 597 {
@@ -582,11 +668,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
582{ 668{
583 unsigned short ch; 669 unsigned short ch;
584 unsigned short *ucs; 670 unsigned short *ucs;
585 struct font* pf = font_get(curfont); 671 struct font* pf = font_get(current_vp->font);
586 672
587 ucs = bidi_l2v(str, 1); 673 ucs = bidi_l2v(str, 1);
588 674
589 while ((ch = *ucs++) != 0 && x < LCD_WIDTH) 675 while ((ch = *ucs++) != 0 && x < current_vp->width)
590 { 676 {
591 int width; 677 int width;
592 const unsigned char *bits; 678 const unsigned char *bits;
@@ -639,24 +725,24 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str,
639 int style, int offset) 725 int style, int offset)
640{ 726{
641 int xpos,ypos,w,h,xrect; 727 int xpos,ypos,w,h,xrect;
642 int lastmode = drawmode; 728 int lastmode = current_vp->drawmode;
643 729
644 /* make sure scrolling is turned off on the line we are updating */ 730 /* make sure scrolling is turned off on the line we are updating */
645 lcd_scroll_info.lines &= ~(1 << y); 731 lcd_scroll_stop_line(current_vp, y);
646 732
647 if(!str || !str[0]) 733 if(!str || !str[0])
648 return; 734 return;
649 735
650 lcd_getstringsize(str, &w, &h); 736 lcd_getstringsize(str, &w, &h);
651 xpos = xmargin + x*w / utf8length(str); 737 xpos = current_vp->xmargin + x*w / utf8length(str);
652 ypos = ymargin + y*h; 738 ypos = current_vp->ymargin + y*h;
653 drawmode = (style & STYLE_INVERT) ? 739 current_vp->drawmode = (style & STYLE_INVERT) ?
654 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 740 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
655 lcd_putsxyofs(xpos, ypos, offset, str); 741 lcd_putsxyofs(xpos, ypos, offset, str);
656 drawmode ^= DRMODE_INVERSEVID; 742 current_vp->drawmode ^= DRMODE_INVERSEVID;
657 xrect = xpos + MAX(w - offset, 0); 743 xrect = xpos + MAX(w - offset, 0);
658 lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); 744 lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
659 drawmode = lastmode; 745 current_vp->drawmode = lastmode;
660} 746}
661 747
662/*** scrolling ***/ 748/*** scrolling ***/
@@ -682,9 +768,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
682 struct scrollinfo* s; 768 struct scrollinfo* s;
683 int w, h; 769 int w, h;
684 770
685 if(y>=LCD_SCROLLABLE_LINES) return; 771 if ((unsigned)y >= (unsigned)current_vp->height)
772 return;
773
774 /* remove any previously scrolling line at the same location */
775 lcd_scroll_stop_line(current_vp, y);
776
777 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
686 778
687 s = &lcd_scroll_info.scroll[y]; 779 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
688 780
689 s->start_tick = current_tick + lcd_scroll_info.delay; 781 s->start_tick = current_tick + lcd_scroll_info.delay;
690 s->style = style; 782 s->style = style;
@@ -696,7 +788,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
696 788
697 lcd_getstringsize(string, &w, &h); 789 lcd_getstringsize(string, &w, &h);
698 790
699 if (LCD_WIDTH - x * 8 - xmargin < w) { 791 if (current_vp->width - x * 8 - current_vp->xmargin < w) {
700 /* prepare scroll line */ 792 /* prepare scroll line */
701 char *end; 793 char *end;
702 794
@@ -709,7 +801,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
709 /* scroll bidirectional or forward only depending on the string 801 /* scroll bidirectional or forward only depending on the string
710 width */ 802 width */
711 if ( lcd_scroll_info.bidir_limit ) { 803 if ( lcd_scroll_info.bidir_limit ) {
712 s->bidir = s->width < (LCD_WIDTH - xmargin) * 804 s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
713 (100 + lcd_scroll_info.bidir_limit) / 100; 805 (100 + lcd_scroll_info.bidir_limit) / 100;
714 } 806 }
715 else 807 else
@@ -722,17 +814,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
722 } 814 }
723 815
724 end = strchr(s->line, '\0'); 816 end = strchr(s->line, '\0');
725 strncpy(end, string, LCD_WIDTH/2); 817 strncpy(end, string, current_vp->width/2);
726 818
819 s->vp = current_vp;
820 s->y = y;
727 s->len = utf8length(string); 821 s->len = utf8length(string);
728 s->offset = offset; 822 s->offset = offset;
729 s->startx = xmargin + x * s->width / s->len;; 823 s->startx = current_vp->xmargin + x * s->width / s->len;;
730 s->backward = false; 824 s->backward = false;
731 lcd_scroll_info.lines |= (1<<y); 825 lcd_scroll_info.lines++;
732 } 826 }
733 else
734 /* force a bit switch-off since it doesn't scroll */
735 lcd_scroll_info.lines &= ~(1<<y);
736} 827}
737 828
738void lcd_scroll_fn(void) 829void lcd_scroll_fn(void)
@@ -742,26 +833,25 @@ void lcd_scroll_fn(void)
742 int index; 833 int index;
743 int xpos, ypos; 834 int xpos, ypos;
744 int lastmode; 835 int lastmode;
836 struct viewport* old_vp = current_vp;
745 837
746 for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) { 838 for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
747 /* really scroll? */
748 if ((lcd_scroll_info.lines & (1 << index)) == 0)
749 continue;
750
751 s = &lcd_scroll_info.scroll[index]; 839 s = &lcd_scroll_info.scroll[index];
752 840
753 /* check pause */ 841 /* check pause */
754 if (TIME_BEFORE(current_tick, s->start_tick)) 842 if (TIME_BEFORE(current_tick, s->start_tick))
755 continue; 843 continue;
756 844
845 lcd_set_viewport(s->vp);
846
757 if (s->backward) 847 if (s->backward)
758 s->offset -= lcd_scroll_info.step; 848 s->offset -= lcd_scroll_info.step;
759 else 849 else
760 s->offset += lcd_scroll_info.step; 850 s->offset += lcd_scroll_info.step;
761 851
762 pf = font_get(curfont); 852 pf = font_get(current_vp->font);
763 xpos = s->startx; 853 xpos = s->startx;
764 ypos = ymargin + index * pf->height; 854 ypos = current_vp->ymargin + s->y * pf->height;
765 855
766 if (s->bidir) { /* scroll bidirectional */ 856 if (s->bidir) { /* scroll bidirectional */
767 if (s->offset <= 0) { 857 if (s->offset <= 0) {
@@ -770,9 +860,9 @@ void lcd_scroll_fn(void)
770 s->backward = false; 860 s->backward = false;
771 s->start_tick = current_tick + lcd_scroll_info.delay * 2; 861 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
772 } 862 }
773 if (s->offset >= s->width - (LCD_WIDTH - xpos)) { 863 if (s->offset >= s->width - (current_vp->width - xpos)) {
774 /* at end of line */ 864 /* at end of line */
775 s->offset = s->width - (LCD_WIDTH - xpos); 865 s->offset = s->width - (current_vp->width - xpos);
776 s->backward = true; 866 s->backward = true;
777 s->start_tick = current_tick + lcd_scroll_info.delay * 2; 867 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
778 } 868 }
@@ -783,11 +873,13 @@ void lcd_scroll_fn(void)
783 s->offset %= s->width; 873 s->offset %= s->width;
784 } 874 }
785 875
786 lastmode = drawmode; 876 lastmode = current_vp->drawmode;
787 drawmode = (s->style&STYLE_INVERT) ? 877 current_vp->drawmode = (s->style&STYLE_INVERT) ?
788 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 878 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
789 lcd_putsxyofs(xpos, ypos, s->offset, s->line); 879 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
790 drawmode = lastmode; 880 current_vp->drawmode = lastmode;
791 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 881 lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height);
792 } 882 }
883
884 lcd_set_viewport(old_vp);
793} 885}
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 = {
46static fb_data* lcd_backdrop = NULL; 46static fb_data* lcd_backdrop = NULL;
47static long lcd_backdrop_offset IDATA_ATTR = 0; 47static long lcd_backdrop_offset IDATA_ATTR = 0;
48 48
49static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ 49static struct viewport default_vp =
50static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ 50{
51static int drawmode = DRMODE_SOLID; 51 .x = 0,
52static int xmargin = 0; 52 .y = 0,
53static int ymargin = 0; 53 .width = LCD_WIDTH,
54static int curfont = FONT_SYSFIXED; 54 .height = LCD_HEIGHT,
55 .font = FONT_SYSFIXED,
56 .drawmode = DRMODE_SOLID,
57 .xmargin = 0,
58 .ymargin = 0,
59 .fg_pattern = LCD_DEFAULT_FG,
60 .bg_pattern = LCD_DEFAULT_BG
61};
62
63static struct viewport* current_vp IBSS_ATTR;
64static unsigned fg_pattern IBSS_ATTR;
65static unsigned bg_pattern IBSS_ATTR;
55 66
56/* LCD init */ 67/* LCD init */
57void lcd_init(void) 68void lcd_init(void)
58{ 69{
70 /* Initialise the viewport */
71 lcd_set_viewport(NULL);
72
59 lcd_clear_display(); 73 lcd_clear_display();
60 /* Call device specific init */ 74 /* Call device specific init */
61 lcd_init_device(); 75 lcd_init_device();
62 scroll_init(); 76 scroll_init();
63} 77}
64 78
79/*** Viewports ***/
80
81void lcd_set_viewport(struct viewport* vp)
82{
83 if (vp == NULL)
84 current_vp = &default_vp;
85 else
86 current_vp = vp;
87
88 fg_pattern = 0x55 * (~current_vp->fg_pattern & 3);
89 bg_pattern = 0x55 * (~current_vp->bg_pattern & 3);
90}
91
92void lcd_update_viewport(void)
93{
94 lcd_update_rect(current_vp->x, current_vp->y,
95 current_vp->width, current_vp->height);
96}
97
98void lcd_update_viewport_rect(int x, int y, int width, int height)
99{
100 lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
101}
102
65/*** parameter handling ***/ 103/*** parameter handling ***/
66 104
67void lcd_set_drawmode(int mode) 105void lcd_set_drawmode(int mode)
68{ 106{
69 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); 107 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
70} 108}
71 109
72int lcd_get_drawmode(void) 110int lcd_get_drawmode(void)
73{ 111{
74 return drawmode; 112 return current_vp->drawmode;
75} 113}
76 114
77void lcd_set_foreground(unsigned brightness) 115void lcd_set_foreground(unsigned brightness)
78{ 116{
117 current_vp->fg_pattern = brightness;
79 fg_pattern = 0x55 * (~brightness & 3); 118 fg_pattern = 0x55 * (~brightness & 3);
80} 119}
81 120
82unsigned lcd_get_foreground(void) 121unsigned lcd_get_foreground(void)
83{ 122{
84 return ~fg_pattern & 3; 123 return current_vp->fg_pattern;
85} 124}
86 125
87void lcd_set_background(unsigned brightness) 126void lcd_set_background(unsigned brightness)
88{ 127{
128 current_vp->bg_pattern = brightness;
89 bg_pattern = 0x55 * (~brightness & 3); 129 bg_pattern = 0x55 * (~brightness & 3);
90} 130}
91 131
92unsigned lcd_get_background(void) 132unsigned lcd_get_background(void)
93{ 133{
94 return ~bg_pattern & 3; 134 return current_vp->bg_pattern;
95} 135}
96 136
97void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness) 137void 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)
103 143
104void lcd_setmargins(int x, int y) 144void lcd_setmargins(int x, int y)
105{ 145{
106 xmargin = x; 146 current_vp->xmargin = x;
107 ymargin = y; 147 current_vp->ymargin = y;
108} 148}
109 149
110int lcd_getxmargin(void) 150int lcd_getxmargin(void)
111{ 151{
112 return xmargin; 152 return current_vp->xmargin;
113} 153}
114 154
115int lcd_getymargin(void) 155int lcd_getymargin(void)
116{ 156{
117 return ymargin; 157 return current_vp->ymargin;
158}
159
160int lcd_getwidth(void)
161{
162 return current_vp->width;
163}
164
165int lcd_getheight(void)
166{
167 return current_vp->height;
118} 168}
119 169
120void lcd_setfont(int newfont) 170void lcd_setfont(int newfont)
121{ 171{
122 curfont = newfont; 172 current_vp->font = newfont;
123} 173}
124 174
125int lcd_getstringsize(const unsigned char *str, int *w, int *h) 175int lcd_getstringsize(const unsigned char *str, int *w, int *h)
126{ 176{
127 return font_getstringsize(str, w, h, curfont); 177 return font_getstringsize(str, w, h, current_vp->font);
128} 178}
129 179
130/*** low-level drawing functions ***/ 180/*** low-level drawing functions ***/
@@ -345,7 +395,7 @@ static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
345/* Clear the whole display */ 395/* Clear the whole display */
346void lcd_clear_display(void) 396void lcd_clear_display(void)
347{ 397{
348 if (drawmode & DRMODE_INVERSEVID) 398 if (current_vp->drawmode & DRMODE_INVERSEVID)
349 { 399 {
350 memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer); 400 memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer);
351 } 401 }
@@ -360,11 +410,37 @@ void lcd_clear_display(void)
360 lcd_scroll_info.lines = 0; 410 lcd_scroll_info.lines = 0;
361} 411}
362 412
413/* Clear the current viewport */
414void lcd_clear_viewport(void)
415{
416 int lastmode;
417
418 if (current_vp == &default_vp)
419 {
420 lcd_clear_display();
421 }
422 else
423 {
424 lastmode = current_vp->drawmode;
425
426 /* Invert the INVERSEVID bit and set basic mode to SOLID */
427 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
428 DRMODE_SOLID;
429
430 lcd_fillrect(0, 0, current_vp->width, current_vp->height);
431
432 current_vp->drawmode = lastmode;
433
434 lcd_scroll_stop(current_vp);
435 }
436}
437
363/* Set a single pixel */ 438/* Set a single pixel */
364void lcd_drawpixel(int x, int y) 439void lcd_drawpixel(int x, int y)
365{ 440{
366 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) 441 if (((unsigned)x < (unsigned)current_vp->width) &&
367 lcd_pixelfuncs[drawmode](x, y); 442 ((unsigned)y < (unsigned)current_vp->height))
443 lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
368} 444}
369 445
370/* Draw a line */ 446/* Draw a line */
@@ -376,7 +452,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
376 int d, dinc1, dinc2; 452 int d, dinc1, dinc2;
377 int x, xinc1, xinc2; 453 int x, xinc1, xinc2;
378 int y, yinc1, yinc2; 454 int y, yinc1, yinc2;
379 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; 455 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
380 456
381 deltax = abs(x2 - x1); 457 deltax = abs(x2 - x1);
382 deltay = abs(y2 - y1); 458 deltay = abs(y2 - y1);
@@ -420,8 +496,9 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
420 496
421 for (i = 0; i < numpixels; i++) 497 for (i = 0; i < numpixels; i++)
422 { 498 {
423 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) 499 if (((unsigned)x < (unsigned)current_vp->width) &&
424 pfunc(x, y); 500 ((unsigned)y < (unsigned)current_vp->height))
501 pfunc(current_vp->x + x, current_vp->y + y);
425 502
426 if (d < 0) 503 if (d < 0)
427 { 504 {
@@ -455,16 +532,22 @@ void lcd_hline(int x1, int x2, int y)
455 } 532 }
456 533
457 /* nothing to draw? */ 534 /* nothing to draw? */
458 if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) 535 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
536 || (x2 < 0))
459 return; 537 return;
460 538
461 /* clipping */ 539 /* clipping */
462 if (x1 < 0) 540 if (x1 < 0)
463 x1 = 0; 541 x1 = 0;
464 if (x2 >= LCD_WIDTH) 542 if (x2 >= current_vp->width)
465 x2 = LCD_WIDTH-1; 543 x2 = current_vp->width-1;
466 544
467 bfunc = lcd_blockfuncs[drawmode]; 545 /* adjust to viewport */
546 x1 += current_vp->x;
547 x2 += current_vp->x;
548 y += current_vp->y;
549
550 bfunc = lcd_blockfuncs[current_vp->drawmode];
468 dst = &lcd_framebuffer[y][x1>>2]; 551 dst = &lcd_framebuffer[y][x1>>2];
469 nx = x2 - (x1 & ~3); 552 nx = x2 - (x1 & ~3);
470 mask = 0xFFu >> (2 * (x1 & 3)); 553 mask = 0xFFu >> (2 * (x1 & 3));
@@ -496,16 +579,22 @@ void lcd_vline(int x, int y1, int y2)
496 } 579 }
497 580
498 /* nothing to draw? */ 581 /* nothing to draw? */
499 if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) 582 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
583 || (y2 < 0))
500 return; 584 return;
501 585
502 /* clipping */ 586 /* clipping */
503 if (y1 < 0) 587 if (y1 < 0)
504 y1 = 0; 588 y1 = 0;
505 if (y2 >= LCD_HEIGHT) 589 if (y2 >= current_vp->height)
506 y2 = LCD_HEIGHT-1; 590 y2 = current_vp->height-1;
591
592 /* adjust for viewport */
593 y1 += current_vp->y;
594 y2 += current_vp->y;
595 x += current_vp->x;
507 596
508 bfunc = lcd_blockfuncs[drawmode]; 597 bfunc = lcd_blockfuncs[current_vp->drawmode];
509 dst = &lcd_framebuffer[y1][x>>2]; 598 dst = &lcd_framebuffer[y1][x>>2];
510 mask = pixmask[x & 3]; 599 mask = pixmask[x & 3];
511 600
@@ -542,7 +631,7 @@ void lcd_fillrect(int x, int y, int width, int height)
542 lcd_blockfunc_type *bfunc; 631 lcd_blockfunc_type *bfunc;
543 632
544 /* nothing to draw? */ 633 /* nothing to draw? */
545 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 634 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || (y >= current_vp->height)
546 || (x + width <= 0) || (y + height <= 0)) 635 || (x + width <= 0) || (y + height <= 0))
547 return; 636 return;
548 637
@@ -557,12 +646,16 @@ void lcd_fillrect(int x, int y, int width, int height)
557 height += y; 646 height += y;
558 y = 0; 647 y = 0;
559 } 648 }
560 if (x + width > LCD_WIDTH) 649 if (x + width > current_vp->width)
561 width = LCD_WIDTH - x; 650 width = current_vp->width - x;
562 if (y + height > LCD_HEIGHT) 651 if (y + height > current_vp->height)
563 height = LCD_HEIGHT - y; 652 height = current_vp->height - y;
653
654 /* adjust for viewport */
655 x += current_vp->x;
656 y += current_vp->y;
564 657
565 bfunc = lcd_blockfuncs[drawmode]; 658 bfunc = lcd_blockfuncs[current_vp->drawmode];
566 dst = &lcd_framebuffer[y][x>>2]; 659 dst = &lcd_framebuffer[y][x>>2];
567 nx = width - 1 + (x & 3); 660 nx = width - 1 + (x & 3);
568 mask = 0xFFu >> (2 * (x & 3)); 661 mask = 0xFFu >> (2 * (x & 3));
@@ -616,8 +709,8 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
616 lcd_pixelfunc_type* bgfunc; 709 lcd_pixelfunc_type* bgfunc;
617 710
618 /* nothing to draw? */ 711 /* nothing to draw? */
619 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 712 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
620 || (x + width <= 0) || (y + height <= 0)) 713 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
621 return; 714 return;
622 715
623 /* clipping */ 716 /* clipping */
@@ -633,17 +726,21 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
633 src_y -= y; 726 src_y -= y;
634 y = 0; 727 y = 0;
635 } 728 }
636 if (x + width > LCD_WIDTH) 729 if (x + width > current_vp->width)
637 width = LCD_WIDTH - x; 730 width = current_vp->width - x;
638 if (y + height > LCD_HEIGHT) 731 if (y + height > current_vp->height)
639 height = LCD_HEIGHT - y; 732 height = current_vp->height - y;
733
734 /* adjust for viewport */
735 x += current_vp->x;
736 y += current_vp->y;
640 737
641 src += stride * (src_y >> 3) + src_x; /* move starting point */ 738 src += stride * (src_y >> 3) + src_x; /* move starting point */
642 src_y &= 7; 739 src_y &= 7;
643 src_end = src + width; 740 src_end = src + width;
644 741
645 fgfunc = lcd_pixelfuncs[drawmode]; 742 fgfunc = lcd_pixelfuncs[current_vp->drawmode];
646 bgfunc = lcd_pixelfuncs[drawmode ^ DRMODE_INVERSEVID]; 743 bgfunc = lcd_pixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID];
647 nx = x; 744 nx = x;
648 do 745 do
649 { 746 {
@@ -704,8 +801,8 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
704 unsigned mask, mask_right; 801 unsigned mask, mask_right;
705 802
706 /* nothing to draw? */ 803 /* nothing to draw? */
707 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 804 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
708 || (x + width <= 0) || (y + height <= 0)) 805 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
709 return; 806 return;
710 807
711 /* clipping */ 808 /* clipping */
@@ -721,10 +818,14 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
721 src_y -= y; 818 src_y -= y;
722 y = 0; 819 y = 0;
723 } 820 }
724 if (x + width > LCD_WIDTH) 821 if (x + width > current_vp->width)
725 width = LCD_WIDTH - x; 822 width = current_vp->width - x;
726 if (y + height > LCD_HEIGHT) 823 if (y + height > current_vp->height)
727 height = LCD_HEIGHT - y; 824 height = current_vp->height - y;
825
826 /* adjust for viewport */
827 x += current_vp->x;
828 y += current_vp->y;
728 829
729 stride = (stride + 3) >> 2; /* convert to no. of bytes */ 830 stride = (stride + 3) >> 2; /* convert to no. of bytes */
730 831
@@ -781,11 +882,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
781{ 882{
782 unsigned short ch; 883 unsigned short ch;
783 unsigned short *ucs; 884 unsigned short *ucs;
784 struct font* pf = font_get(curfont); 885 struct font* pf = font_get(current_vp->font);
785 886
786 ucs = bidi_l2v(str, 1); 887 ucs = bidi_l2v(str, 1);
787 888
788 while ((ch = *ucs++) != 0 && x < LCD_WIDTH) 889 while ((ch = *ucs++) != 0 && x < current_vp->width)
789 { 890 {
790 int width; 891 int width;
791 const unsigned char *bits; 892 const unsigned char *bits;
@@ -839,24 +940,24 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str,
839 int style, int offset) 940 int style, int offset)
840{ 941{
841 int xpos,ypos,w,h,xrect; 942 int xpos,ypos,w,h,xrect;
842 int lastmode = drawmode; 943 int lastmode = current_vp->drawmode;
843 944
844 /* make sure scrolling is turned off on the line we are updating */ 945 /* make sure scrolling is turned off on the line we are updating */
845 lcd_scroll_info.lines &= ~(1 << y); 946 lcd_scroll_stop_line(current_vp, y);
846 947
847 if(!str || !str[0]) 948 if(!str || !str[0])
848 return; 949 return;
849 950
850 lcd_getstringsize(str, &w, &h); 951 lcd_getstringsize(str, &w, &h);
851 xpos = xmargin + x*w / utf8length((char *)str); 952 xpos = current_vp->xmargin + x*w / utf8length((char *)str);
852 ypos = ymargin + y*h; 953 ypos = current_vp->ymargin + y*h;
853 drawmode = (style & STYLE_INVERT) ? 954 current_vp->drawmode = (style & STYLE_INVERT) ?
854 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 955 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
855 lcd_putsxyofs(xpos, ypos, offset, str); 956 lcd_putsxyofs(xpos, ypos, offset, str);
856 drawmode ^= DRMODE_INVERSEVID; 957 current_vp->drawmode ^= DRMODE_INVERSEVID;
857 xrect = xpos + MAX(w - offset, 0); 958 xrect = xpos + MAX(w - offset, 0);
858 lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); 959 lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
859 drawmode = lastmode; 960 current_vp->drawmode = lastmode;
860} 961}
861 962
862/*** scrolling ***/ 963/*** scrolling ***/
@@ -881,9 +982,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
881 struct scrollinfo* s; 982 struct scrollinfo* s;
882 int w, h; 983 int w, h;
883 984
884 if(y>=LCD_SCROLLABLE_LINES) return; 985 if ((unsigned)y >= (unsigned)current_vp->height)
986 return;
987
988 /* remove any previously scrolling line at the same location */
989 lcd_scroll_stop_line(current_vp, y);
885 990
886 s = &lcd_scroll_info.scroll[y]; 991 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
992
993 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
887 994
888 s->start_tick = current_tick + lcd_scroll_info.delay; 995 s->start_tick = current_tick + lcd_scroll_info.delay;
889 s->style = style; 996 s->style = style;
@@ -895,7 +1002,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
895 1002
896 lcd_getstringsize(string, &w, &h); 1003 lcd_getstringsize(string, &w, &h);
897 1004
898 if (LCD_WIDTH - x * 8 - xmargin < w) { 1005 if (current_vp->width - x * 8 - current_vp->xmargin < w) {
899 /* prepare scroll line */ 1006 /* prepare scroll line */
900 char *end; 1007 char *end;
901 1008
@@ -908,7 +1015,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
908 /* scroll bidirectional or forward only depending on the string 1015 /* scroll bidirectional or forward only depending on the string
909 width */ 1016 width */
910 if ( lcd_scroll_info.bidir_limit ) { 1017 if ( lcd_scroll_info.bidir_limit ) {
911 s->bidir = s->width < (LCD_WIDTH - xmargin) * 1018 s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
912 (100 + lcd_scroll_info.bidir_limit) / 100; 1019 (100 + lcd_scroll_info.bidir_limit) / 100;
913 } 1020 }
914 else 1021 else
@@ -921,17 +1028,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
921 } 1028 }
922 1029
923 end = strchr(s->line, '\0'); 1030 end = strchr(s->line, '\0');
924 strncpy(end, (char *)string, LCD_WIDTH/2); 1031 strncpy(end, (char *)string, current_vp->width/2);
925 1032
1033 s->vp = current_vp;
1034 s->y = y;
926 s->len = utf8length((char *)string); 1035 s->len = utf8length((char *)string);
927 s->offset = offset; 1036 s->offset = offset;
928 s->startx = xmargin + x * s->width / s->len;; 1037 s->startx = current_vp->xmargin + x * s->width / s->len;;
929 s->backward = false; 1038 s->backward = false;
930 lcd_scroll_info.lines |= (1<<y); 1039 lcd_scroll_info.lines++;
931 } 1040 }
932 else
933 /* force a bit switch-off since it doesn't scroll */
934 lcd_scroll_info.lines &= ~(1<<y);
935} 1041}
936 1042
937void lcd_scroll_fn(void) 1043void lcd_scroll_fn(void)
@@ -941,26 +1047,25 @@ void lcd_scroll_fn(void)
941 int index; 1047 int index;
942 int xpos, ypos; 1048 int xpos, ypos;
943 int lastmode; 1049 int lastmode;
1050 struct viewport* old_vp = current_vp;
944 1051
945 for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) { 1052 for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
946 /* really scroll? */
947 if ((lcd_scroll_info.lines & (1 << index)) == 0)
948 continue;
949
950 s = &lcd_scroll_info.scroll[index]; 1053 s = &lcd_scroll_info.scroll[index];
951 1054
952 /* check pause */ 1055 /* check pause */
953 if (TIME_BEFORE(current_tick, s->start_tick)) 1056 if (TIME_BEFORE(current_tick, s->start_tick))
954 continue; 1057 continue;
955 1058
1059 lcd_set_viewport(s->vp);
1060
956 if (s->backward) 1061 if (s->backward)
957 s->offset -= lcd_scroll_info.step; 1062 s->offset -= lcd_scroll_info.step;
958 else 1063 else
959 s->offset += lcd_scroll_info.step; 1064 s->offset += lcd_scroll_info.step;
960 1065
961 pf = font_get(curfont); 1066 pf = font_get(current_vp->font);
962 xpos = s->startx; 1067 xpos = s->startx;
963 ypos = ymargin + index * pf->height; 1068 ypos = current_vp->ymargin + s->y * pf->height;
964 1069
965 if (s->bidir) { /* scroll bidirectional */ 1070 if (s->bidir) { /* scroll bidirectional */
966 if (s->offset <= 0) { 1071 if (s->offset <= 0) {
@@ -969,9 +1074,9 @@ void lcd_scroll_fn(void)
969 s->backward = false; 1074 s->backward = false;
970 s->start_tick = current_tick + lcd_scroll_info.delay * 2; 1075 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
971 } 1076 }
972 if (s->offset >= s->width - (LCD_WIDTH - xpos)) { 1077 if (s->offset >= s->width - (current_vp->width - xpos)) {
973 /* at end of line */ 1078 /* at end of line */
974 s->offset = s->width - (LCD_WIDTH - xpos); 1079 s->offset = s->width - (current_vp->width - xpos);
975 s->backward = true; 1080 s->backward = true;
976 s->start_tick = current_tick + lcd_scroll_info.delay * 2; 1081 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
977 } 1082 }
@@ -982,11 +1087,13 @@ void lcd_scroll_fn(void)
982 s->offset %= s->width; 1087 s->offset %= s->width;
983 } 1088 }
984 1089
985 lastmode = drawmode; 1090 lastmode = current_vp->drawmode;
986 drawmode = (s->style&STYLE_INVERT) ? 1091 current_vp->drawmode = (s->style&STYLE_INVERT) ?
987 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 1092 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
988 lcd_putsxyofs(xpos, ypos, s->offset, s->line); 1093 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
989 drawmode = lastmode; 1094 current_vp->drawmode = lastmode;
990 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 1095 lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height);
991 } 1096 }
1097
1098 lcd_set_viewport(old_vp);
992} 1099}
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 = {
48static fb_data* lcd_backdrop = NULL; 48static fb_data* lcd_backdrop = NULL;
49static long lcd_backdrop_offset IDATA_ATTR = 0; 49static long lcd_backdrop_offset IDATA_ATTR = 0;
50 50
51static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ 51static struct viewport default_vp =
52static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ 52{
53static int drawmode = DRMODE_SOLID; 53 .x = 0,
54static int xmargin = 0; 54 .y = 0,
55static int ymargin = 0; 55 .width = LCD_WIDTH,
56static int curfont = FONT_SYSFIXED; 56 .height = LCD_HEIGHT,
57 .font = FONT_SYSFIXED,
58 .drawmode = DRMODE_SOLID,
59 .xmargin = 0,
60 .ymargin = 0,
61 .fg_pattern = LCD_DEFAULT_FG,
62 .bg_pattern = LCD_DEFAULT_BG
63};
64
65static struct viewport* current_vp IBSS_ATTR;
66static unsigned fg_pattern IBSS_ATTR;
67static unsigned bg_pattern IBSS_ATTR;
57 68
58/* LCD init */ 69/* LCD init */
59void lcd_init(void) 70void lcd_init(void)
60{ 71{
72 /* Initialise the viewport */
73 lcd_set_viewport(NULL);
74
61 lcd_clear_display(); 75 lcd_clear_display();
62 /* Call device specific init */ 76 /* Call device specific init */
63 lcd_init_device(); 77 lcd_init_device();
64 scroll_init(); 78 scroll_init();
65} 79}
66 80
81/*** Viewports ***/
82
83void lcd_set_viewport(struct viewport* vp)
84{
85 if (vp == NULL)
86 current_vp = &default_vp;
87 else
88 current_vp = vp;
89
90 fg_pattern = 0x55 * (~current_vp->fg_pattern & 3);
91 bg_pattern = 0x55 * (~current_vp->bg_pattern & 3);
92}
93
94void lcd_update_viewport(void)
95{
96 lcd_update_rect(current_vp->x, current_vp->y,
97 current_vp->width, current_vp->height);
98}
99
100void lcd_update_viewport_rect(int x, int y, int width, int height)
101{
102 lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
103}
104
105
67/*** parameter handling ***/ 106/*** parameter handling ***/
68 107
69void lcd_set_drawmode(int mode) 108void lcd_set_drawmode(int mode)
70{ 109{
71 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); 110 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
72} 111}
73 112
74int lcd_get_drawmode(void) 113int lcd_get_drawmode(void)
75{ 114{
76 return drawmode; 115 return current_vp->drawmode;
77} 116}
78 117
79void lcd_set_foreground(unsigned brightness) 118void lcd_set_foreground(unsigned brightness)
80{ 119{
120 current_vp->fg_pattern = brightness;
81 fg_pattern = 0x55 * (~brightness & 3); 121 fg_pattern = 0x55 * (~brightness & 3);
82} 122}
83 123
84unsigned lcd_get_foreground(void) 124unsigned lcd_get_foreground(void)
85{ 125{
86 return ~fg_pattern & 3; 126 return current_vp->fg_pattern;
87} 127}
88 128
89void lcd_set_background(unsigned brightness) 129void lcd_set_background(unsigned brightness)
90{ 130{
131 current_vp->fg_pattern = brightness;
91 bg_pattern = 0x55 * (~brightness & 3); 132 bg_pattern = 0x55 * (~brightness & 3);
92} 133}
93 134
94unsigned lcd_get_background(void) 135unsigned lcd_get_background(void)
95{ 136{
96 return ~bg_pattern & 3; 137 return current_vp->bg_pattern;
97} 138}
98 139
99void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness) 140void 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)
105 146
106void lcd_setmargins(int x, int y) 147void lcd_setmargins(int x, int y)
107{ 148{
108 xmargin = x; 149 current_vp->xmargin = x;
109 ymargin = y; 150 current_vp->ymargin = y;
110} 151}
111 152
112int lcd_getxmargin(void) 153int lcd_getxmargin(void)
113{ 154{
114 return xmargin; 155 return current_vp->xmargin;
115} 156}
116 157
117int lcd_getymargin(void) 158int lcd_getymargin(void)
118{ 159{
119 return ymargin; 160 return current_vp->ymargin;
161}
162
163int lcd_getwidth(void)
164{
165 return current_vp->width;
166}
167
168int lcd_getheight(void)
169{
170 return current_vp->height;
120} 171}
121 172
122void lcd_setfont(int newfont) 173void lcd_setfont(int newfont)
123{ 174{
124 curfont = newfont; 175 current_vp->font = newfont;
125} 176}
126 177
127int lcd_getstringsize(const unsigned char *str, int *w, int *h) 178int lcd_getstringsize(const unsigned char *str, int *w, int *h)
128{ 179{
129 return font_getstringsize(str, w, h, curfont); 180 return font_getstringsize(str, w, h, current_vp->font);
130} 181}
131 182
132/*** low-level drawing functions ***/ 183/*** low-level drawing functions ***/
@@ -347,7 +398,7 @@ static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
347/* Clear the whole display */ 398/* Clear the whole display */
348void lcd_clear_display(void) 399void lcd_clear_display(void)
349{ 400{
350 if (drawmode & DRMODE_INVERSEVID) 401 if (current_vp->drawmode & DRMODE_INVERSEVID)
351 { 402 {
352 memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer); 403 memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer);
353 } 404 }
@@ -362,11 +413,37 @@ void lcd_clear_display(void)
362 lcd_scroll_info.lines = 0; 413 lcd_scroll_info.lines = 0;
363} 414}
364 415
416/* Clear the current viewport */
417void lcd_clear_viewport(void)
418{
419 int lastmode;
420
421 if (current_vp == &default_vp)
422 {
423 lcd_clear_display();
424 }
425 else
426 {
427 lastmode = current_vp->drawmode;
428
429 /* Invert the INVERSEVID bit and set basic mode to SOLID */
430 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
431 DRMODE_SOLID;
432
433 lcd_fillrect(0, 0, current_vp->width, current_vp->height);
434
435 current_vp->drawmode = lastmode;
436
437 lcd_scroll_stop(current_vp);
438 }
439}
440
365/* Set a single pixel */ 441/* Set a single pixel */
366void lcd_drawpixel(int x, int y) 442void lcd_drawpixel(int x, int y)
367{ 443{
368 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) 444 if (((unsigned)x < (unsigned)current_vp->width) &&
369 lcd_pixelfuncs[drawmode](x, y); 445 ((unsigned)y < (unsigned)current_vp->height))
446 lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
370} 447}
371 448
372/* Draw a line */ 449/* Draw a line */
@@ -378,7 +455,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
378 int d, dinc1, dinc2; 455 int d, dinc1, dinc2;
379 int x, xinc1, xinc2; 456 int x, xinc1, xinc2;
380 int y, yinc1, yinc2; 457 int y, yinc1, yinc2;
381 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; 458 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
382 459
383 deltax = abs(x2 - x1); 460 deltax = abs(x2 - x1);
384 deltay = abs(y2 - y1); 461 deltay = abs(y2 - y1);
@@ -422,8 +499,9 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
422 499
423 for (i = 0; i < numpixels; i++) 500 for (i = 0; i < numpixels; i++)
424 { 501 {
425 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) 502 if (((unsigned)x < (unsigned)current_vp->width) &&
426 pfunc(x, y); 503 ((unsigned)y < (unsigned)current_vp->height))
504 pfunc(current_vp->x + x, current_vp->y + y);
427 505
428 if (d < 0) 506 if (d < 0)
429 { 507 {
@@ -444,6 +522,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
444void lcd_hline(int x1, int x2, int y) 522void lcd_hline(int x1, int x2, int y)
445{ 523{
446 int x; 524 int x;
525 int width;
447 fb_data *dst, *dst_end; 526 fb_data *dst, *dst_end;
448 unsigned mask; 527 unsigned mask;
449 lcd_blockfunc_type *bfunc; 528 lcd_blockfunc_type *bfunc;
@@ -457,23 +536,30 @@ void lcd_hline(int x1, int x2, int y)
457 } 536 }
458 537
459 /* nothing to draw? */ 538 /* nothing to draw? */
460 if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) 539 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
540 || (x2 < 0))
461 return; 541 return;
462 542
463 /* clipping */ 543 /* clipping */
464 if (x1 < 0) 544 if (x1 < 0)
465 x1 = 0; 545 x1 = 0;
466 if (x2 >= LCD_WIDTH) 546 if (x2 >= current_vp->width)
467 x2 = LCD_WIDTH-1; 547 x2 = current_vp->width-1;
468 548
469 bfunc = lcd_blockfuncs[drawmode]; 549 width = x2 - x1 + 1;
550
551 /* adjust x1 and y to viewport */
552 x1 += current_vp->x;
553 y += current_vp->y;
554
555 bfunc = lcd_blockfuncs[current_vp->drawmode];
470 dst = &lcd_framebuffer[y>>2][x1]; 556 dst = &lcd_framebuffer[y>>2][x1];
471 mask = pixmask[y & 3]; 557 mask = pixmask[y & 3];
472 558
473 dst_end = dst + x2 - x1; 559 dst_end = dst + width;
474 do 560 do
475 bfunc(dst++, mask, 0xFFu); 561 bfunc(dst++, mask, 0xFFu);
476 while (dst <= dst_end); 562 while (dst < dst_end);
477} 563}
478 564
479/* Draw a vertical line (optimised) */ 565/* Draw a vertical line (optimised) */
@@ -493,16 +579,22 @@ void lcd_vline(int x, int y1, int y2)
493 } 579 }
494 580
495 /* nothing to draw? */ 581 /* nothing to draw? */
496 if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) 582 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
583 || (y2 < 0))
497 return; 584 return;
498 585
499 /* clipping */ 586 /* clipping */
500 if (y1 < 0) 587 if (y1 < 0)
501 y1 = 0; 588 y1 = 0;
502 if (y2 >= LCD_HEIGHT) 589 if (y2 >= current_vp->height)
503 y2 = LCD_HEIGHT-1; 590 y2 = current_vp->height-1;
504 591
505 bfunc = lcd_blockfuncs[drawmode]; 592 /* adjust for viewport */
593 y1 += current_vp->y;
594 y2 += current_vp->y;
595 x += current_vp->x;
596
597 bfunc = lcd_blockfuncs[current_vp->drawmode];
506 dst = &lcd_framebuffer[y1>>2][x]; 598 dst = &lcd_framebuffer[y1>>2][x];
507 ny = y2 - (y1 & ~3); 599 ny = y2 - (y1 & ~3);
508 mask = 0xFFu << (2 * (y1 & 3)); 600 mask = 0xFFu << (2 * (y1 & 3));
@@ -544,8 +636,8 @@ void lcd_fillrect(int x, int y, int width, int height)
544 bool fillopt = false; 636 bool fillopt = false;
545 637
546 /* nothing to draw? */ 638 /* nothing to draw? */
547 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 639 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
548 || (x + width <= 0) || (y + height <= 0)) 640 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
549 return; 641 return;
550 642
551 /* clipping */ 643 /* clipping */
@@ -559,14 +651,18 @@ void lcd_fillrect(int x, int y, int width, int height)
559 height += y; 651 height += y;
560 y = 0; 652 y = 0;
561 } 653 }
562 if (x + width > LCD_WIDTH) 654 if (x + width > current_vp->width)
563 width = LCD_WIDTH - x; 655 width = current_vp->width - x;
564 if (y + height > LCD_HEIGHT) 656 if (y + height > current_vp->height)
565 height = LCD_HEIGHT - y; 657 height = current_vp->height - y;
566 658
567 if (drawmode & DRMODE_INVERSEVID) 659 /* adjust for viewport */
660 x += current_vp->x;
661 y += current_vp->y;
662
663 if (current_vp->drawmode & DRMODE_INVERSEVID)
568 { 664 {
569 if ((drawmode & DRMODE_BG) && !lcd_backdrop) 665 if ((current_vp->drawmode & DRMODE_BG) && !lcd_backdrop)
570 { 666 {
571 fillopt = true; 667 fillopt = true;
572 bits = bg_pattern; 668 bits = bg_pattern;
@@ -574,13 +670,13 @@ void lcd_fillrect(int x, int y, int width, int height)
574 } 670 }
575 else 671 else
576 { 672 {
577 if (drawmode & DRMODE_FG) 673 if (current_vp->drawmode & DRMODE_FG)
578 { 674 {
579 fillopt = true; 675 fillopt = true;
580 bits = fg_pattern; 676 bits = fg_pattern;
581 } 677 }
582 } 678 }
583 bfunc = lcd_blockfuncs[drawmode]; 679 bfunc = lcd_blockfuncs[current_vp->drawmode];
584 dst = &lcd_framebuffer[y>>2][x]; 680 dst = &lcd_framebuffer[y>>2][x];
585 ny = height - 1 + (y & 3); 681 ny = height - 1 + (y & 3);
586 mask = 0xFFu << (2 * (y & 3)); 682 mask = 0xFFu << (2 * (y & 3));
@@ -640,8 +736,8 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
640 lcd_blockfunc_type *bfunc; 736 lcd_blockfunc_type *bfunc;
641 737
642 /* nothing to draw? */ 738 /* nothing to draw? */
643 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 739 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
644 || (x + width <= 0) || (y + height <= 0)) 740 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
645 return; 741 return;
646 742
647 /* clipping */ 743 /* clipping */
@@ -657,10 +753,14 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
657 src_y -= y; 753 src_y -= y;
658 y = 0; 754 y = 0;
659 } 755 }
660 if (x + width > LCD_WIDTH) 756 if (x + width > current_vp->width)
661 width = LCD_WIDTH - x; 757 width = current_vp->width - x;
662 if (y + height > LCD_HEIGHT) 758 if (y + height > current_vp->height)
663 height = LCD_HEIGHT - y; 759 height = current_vp->height - y;
760
761 /* adjust for viewport */
762 x += current_vp->x;
763 y += current_vp->y;
664 764
665 src += stride * (src_y >> 3) + src_x; /* move starting point */ 765 src += stride * (src_y >> 3) + src_x; /* move starting point */
666 src_y &= 7; 766 src_y &= 7;
@@ -669,7 +769,7 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
669 shift = y & 3; 769 shift = y & 3;
670 ny = height - 1 + shift + src_y; 770 ny = height - 1 + shift + src_y;
671 771
672 bfunc = lcd_blockfuncs[drawmode]; 772 bfunc = lcd_blockfuncs[current_vp->drawmode];
673 mask = 0xFFu << (shift + src_y); 773 mask = 0xFFu << (shift + src_y);
674 mask_bottom = 0xFFu >> (~ny & 7); 774 mask_bottom = 0xFFu >> (~ny & 7);
675 775
@@ -807,8 +907,8 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
807 unsigned mask, mask_bottom; 907 unsigned mask, mask_bottom;
808 908
809 /* nothing to draw? */ 909 /* nothing to draw? */
810 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 910 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
811 || (x + width <= 0) || (y + height <= 0)) 911 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
812 return; 912 return;
813 913
814 /* clipping */ 914 /* clipping */
@@ -824,10 +924,14 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
824 src_y -= y; 924 src_y -= y;
825 y = 0; 925 y = 0;
826 } 926 }
827 if (x + width > LCD_WIDTH) 927 if (x + width > current_vp->width)
828 width = LCD_WIDTH - x; 928 width = current_vp->width - x;
829 if (y + height > LCD_HEIGHT) 929 if (y + height > current_vp->height)
830 height = LCD_HEIGHT - y; 930 height = current_vp->height - y;
931
932 /* adjust for viewport */
933 x += current_vp->x;
934 y += current_vp->y;
831 935
832 src += stride * (src_y >> 2) + src_x; /* move starting point */ 936 src += stride * (src_y >> 2) + src_x; /* move starting point */
833 src_y &= 3; 937 src_y &= 3;
@@ -916,11 +1020,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
916{ 1020{
917 unsigned short ch; 1021 unsigned short ch;
918 unsigned short *ucs; 1022 unsigned short *ucs;
919 struct font* pf = font_get(curfont); 1023 struct font* pf = font_get(current_vp->font);
920 1024
921 ucs = bidi_l2v(str, 1); 1025 ucs = bidi_l2v(str, 1);
922 1026
923 while ((ch = *ucs++) != 0 && x < LCD_WIDTH) 1027 while ((ch = *ucs++) != 0 && x < current_vp->width)
924 { 1028 {
925 int width; 1029 int width;
926 const unsigned char *bits; 1030 const unsigned char *bits;
@@ -974,24 +1078,24 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str,
974 int style, int offset) 1078 int style, int offset)
975{ 1079{
976 int xpos,ypos,w,h,xrect; 1080 int xpos,ypos,w,h,xrect;
977 int lastmode = drawmode; 1081 int lastmode = current_vp->drawmode;
978 1082
979 /* make sure scrolling is turned off on the line we are updating */ 1083 /* make sure scrolling is turned off on the line we are updating */
980 lcd_scroll_info.lines &= ~(1 << y); 1084 lcd_scroll_stop_line(current_vp, y);
981 1085
982 if(!str || !str[0]) 1086 if(!str || !str[0])
983 return; 1087 return;
984 1088
985 lcd_getstringsize(str, &w, &h); 1089 lcd_getstringsize(str, &w, &h);
986 xpos = xmargin + x*w / utf8length((char *)str); 1090 xpos = current_vp->xmargin + x*w / utf8length((char *)str);
987 ypos = ymargin + y*h; 1091 ypos = current_vp->ymargin + y*h;
988 drawmode = (style & STYLE_INVERT) ? 1092 current_vp->drawmode = (style & STYLE_INVERT) ?
989 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 1093 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
990 lcd_putsxyofs(xpos, ypos, offset, str); 1094 lcd_putsxyofs(xpos, ypos, offset, str);
991 drawmode ^= DRMODE_INVERSEVID; 1095 current_vp->drawmode ^= DRMODE_INVERSEVID;
992 xrect = xpos + MAX(w - offset, 0); 1096 xrect = xpos + MAX(w - offset, 0);
993 lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); 1097 lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
994 drawmode = lastmode; 1098 current_vp->drawmode = lastmode;
995} 1099}
996 1100
997/*** scrolling ***/ 1101/*** scrolling ***/
@@ -1017,9 +1121,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
1017 struct scrollinfo* s; 1121 struct scrollinfo* s;
1018 int w, h; 1122 int w, h;
1019 1123
1020 if(y>=LCD_SCROLLABLE_LINES) return; 1124 if ((unsigned)y >= (unsigned)current_vp->height)
1125 return;
1126
1127 /* remove any previously scrolling line at the same location */
1128 lcd_scroll_stop_line(current_vp, y);
1129
1130 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
1021 1131
1022 s = &lcd_scroll_info.scroll[y]; 1132 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
1023 1133
1024 s->start_tick = current_tick + lcd_scroll_info.delay; 1134 s->start_tick = current_tick + lcd_scroll_info.delay;
1025 s->style = style; 1135 s->style = style;
@@ -1031,7 +1141,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
1031 1141
1032 lcd_getstringsize(string, &w, &h); 1142 lcd_getstringsize(string, &w, &h);
1033 1143
1034 if (LCD_WIDTH - x * 8 - xmargin < w) { 1144 if (current_vp->width - x * 8 - current_vp->xmargin < w) {
1035 /* prepare scroll line */ 1145 /* prepare scroll line */
1036 char *end; 1146 char *end;
1037 1147
@@ -1044,7 +1154,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
1044 /* scroll bidirectional or forward only depending on the string 1154 /* scroll bidirectional or forward only depending on the string
1045 width */ 1155 width */
1046 if ( lcd_scroll_info.bidir_limit ) { 1156 if ( lcd_scroll_info.bidir_limit ) {
1047 s->bidir = s->width < (LCD_WIDTH - xmargin) * 1157 s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
1048 (100 + lcd_scroll_info.bidir_limit) / 100; 1158 (100 + lcd_scroll_info.bidir_limit) / 100;
1049 } 1159 }
1050 else 1160 else
@@ -1057,17 +1167,17 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
1057 } 1167 }
1058 1168
1059 end = strchr(s->line, '\0'); 1169 end = strchr(s->line, '\0');
1060 strncpy(end, (char *)string, LCD_WIDTH/2); 1170 strncpy(end, (char *)string, current_vp->width/2);
1061 1171
1172 s->vp = current_vp;
1173 s->y = y;
1062 s->len = utf8length((char *)string); 1174 s->len = utf8length((char *)string);
1063 s->offset = offset; 1175 s->offset = offset;
1064 s->startx = xmargin + x * s->width / s->len; 1176 s->startx = current_vp->xmargin + x * s->width / s->len;
1065 s->backward = false; 1177 s->backward = false;
1066 lcd_scroll_info.lines |= (1<<y); 1178
1179 lcd_scroll_info.lines++;
1067 } 1180 }
1068 else
1069 /* force a bit switch-off since it doesn't scroll */
1070 lcd_scroll_info.lines &= ~(1<<y);
1071} 1181}
1072 1182
1073void lcd_scroll_fn(void) 1183void lcd_scroll_fn(void)
@@ -1077,26 +1187,25 @@ void lcd_scroll_fn(void)
1077 int index; 1187 int index;
1078 int xpos, ypos; 1188 int xpos, ypos;
1079 int lastmode; 1189 int lastmode;
1190 struct viewport* old_vp = current_vp;
1080 1191
1081 for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) { 1192 for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
1082 /* really scroll? */
1083 if ((lcd_scroll_info.lines & (1 << index)) == 0)
1084 continue;
1085
1086 s = &lcd_scroll_info.scroll[index]; 1193 s = &lcd_scroll_info.scroll[index];
1087 1194
1088 /* check pause */ 1195 /* check pause */
1089 if (TIME_BEFORE(current_tick, s->start_tick)) 1196 if (TIME_BEFORE(current_tick, s->start_tick))
1090 continue; 1197 continue;
1091 1198
1199 lcd_set_viewport(s->vp);
1200
1092 if (s->backward) 1201 if (s->backward)
1093 s->offset -= lcd_scroll_info.step; 1202 s->offset -= lcd_scroll_info.step;
1094 else 1203 else
1095 s->offset += lcd_scroll_info.step; 1204 s->offset += lcd_scroll_info.step;
1096 1205
1097 pf = font_get(curfont); 1206 pf = font_get(current_vp->font);
1098 xpos = s->startx; 1207 xpos = s->startx;
1099 ypos = ymargin + index * pf->height; 1208 ypos = current_vp->ymargin + s->y * pf->height;
1100 1209
1101 if (s->bidir) { /* scroll bidirectional */ 1210 if (s->bidir) { /* scroll bidirectional */
1102 if (s->offset <= 0) { 1211 if (s->offset <= 0) {
@@ -1105,9 +1214,9 @@ void lcd_scroll_fn(void)
1105 s->backward = false; 1214 s->backward = false;
1106 s->start_tick = current_tick + lcd_scroll_info.delay * 2; 1215 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1107 } 1216 }
1108 if (s->offset >= s->width - (LCD_WIDTH - xpos)) { 1217 if (s->offset >= s->width - (current_vp->width - xpos)) {
1109 /* at end of line */ 1218 /* at end of line */
1110 s->offset = s->width - (LCD_WIDTH - xpos); 1219 s->offset = s->width - (current_vp->width - xpos);
1111 s->backward = true; 1220 s->backward = true;
1112 s->start_tick = current_tick + lcd_scroll_info.delay * 2; 1221 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1113 } 1222 }
@@ -1118,11 +1227,14 @@ void lcd_scroll_fn(void)
1118 s->offset %= s->width; 1227 s->offset %= s->width;
1119 } 1228 }
1120 1229
1121 lastmode = drawmode; 1230 lastmode = current_vp->drawmode;
1122 drawmode = (s->style&STYLE_INVERT) ? 1231 current_vp->drawmode = (s->style&STYLE_INVERT) ?
1123 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 1232 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1124 lcd_putsxyofs(xpos, ypos, s->offset, s->line); 1233 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
1125 drawmode = lastmode; 1234 current_vp->drawmode = lastmode;
1126 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 1235 lcd_update_viewport_rect(xpos, ypos,
1236 current_vp->width - xpos, pf->height);
1127 } 1237 }
1238
1239 lcd_set_viewport(old_vp);
1128} 1240}
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];
52static bool xfont_variable_locked[VARIABLE_XCHARS]; 52static bool xfont_variable_locked[VARIABLE_XCHARS];
53static int xspace; /* stores xhcar id of ' ' - often needed */ 53static int xspace; /* stores xhcar id of ' ' - often needed */
54 54
55static int xmargin = 0; 55static struct viewport default_vp =
56static int ymargin = 0; 56 {
57 .x = 0,
58 .y = 0,
59 .width = LCD_WIDTH,
60 .height = LCD_HEIGHT,
61 .xmargin = 0,
62 .ymargin = 0,
63 };
64
65static struct viewport* current_vp = &default_vp;
57 66
58/* LCD init */ 67/* LCD init */
59void lcd_init (void) 68void lcd_init (void)
@@ -66,22 +75,47 @@ void lcd_init (void)
66 scroll_init(); 75 scroll_init();
67} 76}
68 77
78/* Viewports */
79
80void lcd_set_viewport(struct viewport* vp)
81{
82 if (vp == NULL)
83 current_vp = &default_vp;
84 else
85 current_vp = vp;
86}
87
88void lcd_update_viewport(void)
89{
90 lcd_update();
91}
92
69/** parameter handling **/ 93/** parameter handling **/
70 94
71void lcd_setmargins(int x, int y) 95void lcd_setmargins(int x, int y)
72{ 96{
73 xmargin = x; 97 current_vp->xmargin = x;
74 ymargin = y; 98 current_vp->ymargin = y;
75} 99}
76 100
77int lcd_getxmargin(void) 101int lcd_getxmargin(void)
78{ 102{
79 return xmargin; 103 return current_vp->xmargin;
80} 104}
81 105
82int lcd_getymargin(void) 106int lcd_getymargin(void)
83{ 107{
84 return ymargin; 108 return current_vp->ymargin;
109}
110
111int lcd_getwidth(void)
112{
113 return current_vp->width;
114}
115
116int lcd_getheight(void)
117{
118 return current_vp->height;
85} 119}
86 120
87int lcd_getstringsize(const unsigned char *str, int *w, int *h) 121int lcd_getstringsize(const unsigned char *str, int *w, int *h)
@@ -225,7 +259,13 @@ static int map_xchar(int xchar, unsigned char *substitute)
225 259
226static void lcd_putxchar(int x, int y, int xchar) 260static void lcd_putxchar(int x, int y, int xchar)
227{ 261{
228 int lcd_char = lcd_charbuffer[y][x]; 262 int lcd_char;
263
264 /* Adjust for viewport */
265 x += current_vp->x;
266 y += current_vp->y;
267
268 lcd_char = lcd_charbuffer[y][x];
229 269
230 if (lcd_char < lcd_pattern_count) /* old char was soft */ 270 if (lcd_char < lcd_pattern_count) /* old char was soft */
231 lcd_patterns[lcd_char].count--; /* decrease old reference count */ 271 lcd_patterns[lcd_char].count--; /* decrease old reference count */
@@ -283,19 +323,55 @@ void lcd_define_pattern(unsigned long ucs, const char *pattern)
283void lcd_clear_display(void) 323void lcd_clear_display(void)
284{ 324{
285 int x, y; 325 int x, y;
326 struct viewport* old_vp = current_vp;
286 327
287 lcd_stop_scroll(); 328 lcd_scroll_info.lines = 0;
288 lcd_remove_cursor(); 329 lcd_remove_cursor();
289 330
331 /* Set the default viewport - required for lcd_putxchar */
332 current_vp = &default_vp;
333
290 for (x = 0; x < LCD_WIDTH; x++) 334 for (x = 0; x < LCD_WIDTH; x++)
291 for (y = 0; y < LCD_HEIGHT; y++) 335 for (y = 0; y < LCD_HEIGHT; y++)
292 lcd_putxchar(x, y, xspace); 336 lcd_putxchar(x, y, xspace);
337
338 current_vp = old_vp;
339}
340
341/* Clear the current viewport */
342void lcd_clear_viewport(void)
343{
344 int x, y;
345
346 if (current_vp == &default_vp)
347 {
348 lcd_clear_display();
349 }
350 else
351 {
352 /* Remove the cursor if it is within the current viewport */
353 if (lcd_cursor.enabled &&
354 (lcd_cursor.x >= current_vp->x) &&
355 (lcd_cursor.x <= current_vp->x + current_vp->width) &&
356 (lcd_cursor.y >= current_vp->y) &&
357 (lcd_cursor.y <= current_vp->y + current_vp->height))
358 {
359 lcd_remove_cursor();
360 }
361
362 for (x = 0; x < current_vp->width; x++)
363 for (y = 0; y < current_vp->height; y++)
364 lcd_putxchar(x, y, xspace);
365
366 lcd_scroll_stop(current_vp);
367 }
293} 368}
294 369
295/* Put an unicode character at the given position */ 370/* Put an unicode character at the given position */
296void lcd_putc(int x, int y, unsigned long ucs) 371void lcd_putc(int x, int y, unsigned long ucs)
297{ 372{
298 if ((unsigned)x >= LCD_WIDTH || (unsigned)y >= LCD_HEIGHT) 373 if ((unsigned)x >= (unsigned)current_vp->width ||
374 (unsigned)y >= (unsigned)current_vp->height)
299 return; 375 return;
300 376
301 lcd_putxchar(x, y, find_xchar(ucs)); 377 lcd_putxchar(x, y, find_xchar(ucs));
@@ -304,15 +380,16 @@ void lcd_putc(int x, int y, unsigned long ucs)
304/* Show cursor (alternating with existing character) at the given position */ 380/* Show cursor (alternating with existing character) at the given position */
305void lcd_put_cursor(int x, int y, unsigned long cursor_ucs) 381void lcd_put_cursor(int x, int y, unsigned long cursor_ucs)
306{ 382{
307 if ((unsigned)x >= LCD_WIDTH || (unsigned)y >= LCD_HEIGHT 383 if ((unsigned)x >= (unsigned)current_vp->width ||
308 || lcd_cursor.enabled) 384 (unsigned)y >= (unsigned)current_vp->height ||
385 lcd_cursor.enabled)
309 return; 386 return;
310 387
311 lcd_cursor.enabled = true; 388 lcd_cursor.enabled = true;
312 lcd_cursor.visible = false; 389 lcd_cursor.visible = false;
313 lcd_cursor.hw_char = map_xchar(find_xchar(cursor_ucs), &lcd_cursor.subst_char); 390 lcd_cursor.hw_char = map_xchar(find_xchar(cursor_ucs), &lcd_cursor.subst_char);
314 lcd_cursor.x = x; 391 lcd_cursor.x = current_vp->x + x;
315 lcd_cursor.y = y; 392 lcd_cursor.y = current_vp->y + y;
316 lcd_cursor.downcount = 0; 393 lcd_cursor.downcount = 0;
317 lcd_cursor.divider = MAX((HZ/2) / lcd_scroll_info.ticks, 1); 394 lcd_cursor.divider = MAX((HZ/2) / lcd_scroll_info.ticks, 1);
318} 395}
@@ -335,7 +412,7 @@ static int lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
335 unsigned short ucs; 412 unsigned short ucs;
336 const unsigned char *utf8 = str; 413 const unsigned char *utf8 = str;
337 414
338 while (*utf8 && x < LCD_WIDTH) 415 while (*utf8 && x < current_vp->width)
339 { 416 {
340 utf8 = utf8decode(utf8, &ucs); 417 utf8 = utf8decode(utf8, &ucs);
341 418
@@ -352,7 +429,7 @@ static int lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
352/* Put a string at a given position */ 429/* Put a string at a given position */
353void lcd_putsxy(int x, int y, const unsigned char *str) 430void lcd_putsxy(int x, int y, const unsigned char *str)
354{ 431{
355 if ((unsigned)y >= LCD_HEIGHT) 432 if ((unsigned)y >= (unsigned)current_vp->height)
356 return; 433 return;
357 434
358 lcd_putsxyofs(x, y, 0, str); 435 lcd_putsxyofs(x, y, 0, str);
@@ -369,17 +446,14 @@ void lcd_puts(int x, int y, const unsigned char *str)
369/* Put a string at a given char position, skipping first offset chars */ 446/* Put a string at a given char position, skipping first offset chars */
370void lcd_puts_offset(int x, int y, const unsigned char *str, int offset) 447void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
371{ 448{
372 x += xmargin; 449 if ((unsigned)y >= (unsigned)current_vp->height)
373 y += ymargin;
374
375 if ((unsigned)y >= LCD_HEIGHT)
376 return; 450 return;
377 451
378 /* make sure scrolling is turned off on the line we are updating */ 452 /* make sure scrolling is turned off on the line we are updating */
379 lcd_scroll_info.lines &= ~(1 << y); 453 lcd_scroll_stop_line(current_vp, y);
380 454
381 x = lcd_putsxyofs(x, y, offset, str); 455 x = lcd_putsxyofs(x, y, offset, str);
382 while (x < LCD_WIDTH) 456 while (x < current_vp->width)
383 lcd_putxchar(x++, y, xspace); 457 lcd_putxchar(x++, y, xspace);
384} 458}
385 459
@@ -395,16 +469,22 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string,
395 struct scrollinfo* s; 469 struct scrollinfo* s;
396 int len; 470 int len;
397 471
398 if(y>=LCD_SCROLLABLE_LINES) return; 472 if ((unsigned)y >= (unsigned)current_vp->height)
473 return;
474
475 /* remove any previously scrolling line at the same location */
476 lcd_scroll_stop_line(current_vp, y);
399 477
400 s = &lcd_scroll_info.scroll[y]; 478 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
479
480 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
401 481
402 s->start_tick = current_tick + lcd_scroll_info.delay; 482 s->start_tick = current_tick + lcd_scroll_info.delay;
403 483
404 lcd_puts_offset(x, y, string, offset); 484 lcd_puts_offset(x, y, string, offset);
405 len = utf8length(string); 485 len = utf8length(string);
406 486
407 if (LCD_WIDTH - x - xmargin < len) 487 if (current_vp->width - x - current_vp->xmargin < len)
408 { 488 {
409 /* prepare scroll line */ 489 /* prepare scroll line */
410 char *end; 490 char *end;
@@ -418,7 +498,7 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string,
418 /* scroll bidirectional or forward only depending on the string width */ 498 /* scroll bidirectional or forward only depending on the string width */
419 if (lcd_scroll_info.bidir_limit) 499 if (lcd_scroll_info.bidir_limit)
420 { 500 {
421 s->bidir = s->len < (LCD_WIDTH - xmargin) * 501 s->bidir = s->len < (current_vp->width - current_vp->xmargin) *
422 (100 + lcd_scroll_info.bidir_limit) / 100; 502 (100 + lcd_scroll_info.bidir_limit) / 100;
423 } 503 }
424 else 504 else
@@ -432,16 +512,15 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string,
432 } 512 }
433 513
434 end = strchr(s->line, '\0'); 514 end = strchr(s->line, '\0');
435 strncpy(end, string, utf8seek(s->line, LCD_WIDTH)); 515 strncpy(end, string, utf8seek(s->line, current_vp->width));
436 516
517 s->vp = current_vp;
518 s->y = y;
437 s->offset = offset; 519 s->offset = offset;
438 s->startx = xmargin + x; 520 s->startx = current_vp->xmargin + x;
439 s->backward = false; 521 s->backward = false;
440 lcd_scroll_info.lines |= (1<<y); 522 lcd_scroll_info.lines++;
441 } 523 }
442 else
443 /* force a bit switch-off since it doesn't scroll */
444 lcd_scroll_info.lines &= ~(1<<y);
445} 524}
446 525
447void lcd_scroll_fn(void) 526void lcd_scroll_fn(void)
@@ -450,27 +529,25 @@ void lcd_scroll_fn(void)
450 int index; 529 int index;
451 int xpos, ypos; 530 int xpos, ypos;
452 bool update; 531 bool update;
532 struct viewport* old_vp = current_vp;
453 533
454 update = false; 534 update = false;
455 for (index = 0; index < LCD_SCROLLABLE_LINES; index++) 535 for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
456 {
457 /* really scroll? */
458 if ((lcd_scroll_info.lines & (1 << index)) == 0)
459 continue;
460
461 s = &lcd_scroll_info.scroll[index]; 536 s = &lcd_scroll_info.scroll[index];
462 537
463 /* check pause */ 538 /* check pause */
464 if (TIME_BEFORE(current_tick, s->start_tick)) 539 if (TIME_BEFORE(current_tick, s->start_tick))
465 continue; 540 continue;
466 541
542 lcd_set_viewport(s->vp);
543
467 if (s->backward) 544 if (s->backward)
468 s->offset--; 545 s->offset--;
469 else 546 else
470 s->offset++; 547 s->offset++;
471 548
472 xpos = s->startx; 549 xpos = s->startx;
473 ypos = ymargin + index; 550 ypos = current_vp->ymargin + s->y;
474 551
475 if (s->bidir) /* scroll bidirectional */ 552 if (s->bidir) /* scroll bidirectional */
476 { 553 {
@@ -480,9 +557,9 @@ void lcd_scroll_fn(void)
480 s->backward = false; 557 s->backward = false;
481 s->start_tick = current_tick + lcd_scroll_info.delay * 2; 558 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
482 } 559 }
483 if (s->offset >= s->len - (LCD_WIDTH - xpos)) { 560 if (s->offset >= s->len - (current_vp->width - xpos)) {
484 /* at end of line */ 561 /* at end of line */
485 s->offset = s->len - (LCD_WIDTH - xpos); 562 s->offset = s->len - (current_vp->width - xpos);
486 s->backward = true; 563 s->backward = true;
487 s->start_tick = current_tick + lcd_scroll_info.delay * 2; 564 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
488 } 565 }
@@ -497,6 +574,8 @@ void lcd_scroll_fn(void)
497 update = true; 574 update = true;
498 } 575 }
499 576
577 lcd_set_viewport(old_vp);
578
500 if (lcd_cursor.enabled) 579 if (lcd_cursor.enabled)
501 { 580 {
502 if (--lcd_cursor.downcount <= 0) 581 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 @@
38fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH] 38fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH]
39 IBSS_ATTR; 39 IBSS_ATTR;
40 40
41static int drawmode = DRMODE_SOLID; 41static struct viewport default_vp =
42static int xmargin = 0; 42{
43static int ymargin = 0; 43 .x = 0,
44static int curfont = FONT_SYSFIXED; 44 .y = 0,
45 .width = LCD_REMOTE_WIDTH,
46 .height = LCD_REMOTE_HEIGHT,
47 .font = FONT_SYSFIXED,
48 .drawmode = DRMODE_SOLID,
49 .xmargin = 0,
50 .ymargin = 0,
51};
52
53static struct viewport* current_vp IDATA_ATTR = &default_vp;
54
55/*** Viewports ***/
56
57void lcd_remote_set_viewport(struct viewport* vp)
58{
59 if (vp == NULL)
60 current_vp = &default_vp;
61 else
62 current_vp = vp;
63}
64
65void lcd_remote_update_viewport(void)
66{
67 lcd_remote_update_rect(current_vp->x, current_vp->y,
68 current_vp->width, current_vp->height);
69}
70
71void lcd_remote_update_viewport_rect(int x, int y, int width, int height)
72{
73 lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height);
74}
75
45 76
46/*** parameter handling ***/ 77/*** parameter handling ***/
47 78
48void lcd_remote_set_drawmode(int mode) 79void lcd_remote_set_drawmode(int mode)
49{ 80{
50 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); 81 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
51} 82}
52 83
53int lcd_remote_get_drawmode(void) 84int lcd_remote_get_drawmode(void)
54{ 85{
55 return drawmode; 86 return current_vp->drawmode;
56} 87}
57 88
58void lcd_remote_setmargins(int x, int y) 89void lcd_remote_setmargins(int x, int y)
59{ 90{
60 xmargin = x; 91 current_vp->xmargin = x;
61 ymargin = y; 92 current_vp->ymargin = y;
93}
94
95int lcd_remote_getwidth(void)
96{
97 return current_vp->width;
98}
99
100int lcd_remote_getheight(void)
101{
102 return current_vp->height;
62} 103}
63 104
64int lcd_remote_getxmargin(void) 105int lcd_remote_getxmargin(void)
65{ 106{
66 return xmargin; 107 return current_vp->xmargin;
67} 108}
68 109
69int lcd_remote_getymargin(void) 110int lcd_remote_getymargin(void)
70{ 111{
71 return ymargin; 112 return current_vp->ymargin;
72} 113}
73 114
74void lcd_remote_setfont(int newfont) 115void lcd_remote_setfont(int newfont)
75{ 116{
76 curfont = newfont; 117 current_vp->font = newfont;
77} 118}
78 119
79int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h) 120int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h)
80{ 121{
81 return font_getstringsize(str, w, h, curfont); 122 return font_getstringsize(str, w, h, current_vp->font);
82} 123}
83 124
84/*** low-level drawing functions ***/ 125/*** low-level drawing functions ***/
@@ -181,17 +222,44 @@ lcd_remote_blockfunc_type* const lcd_remote_blockfuncs[8] = {
181/* Clear the whole display */ 222/* Clear the whole display */
182void lcd_remote_clear_display(void) 223void lcd_remote_clear_display(void)
183{ 224{
184 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; 225 unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
185 226
186 memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer); 227 memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer);
228
187 lcd_remote_scroll_info.lines = 0; 229 lcd_remote_scroll_info.lines = 0;
188} 230}
189 231
232/* Clear the current viewport */
233void lcd_remote_clear_viewport(void)
234{
235 int oldmode;
236
237 if (current_vp == &default_vp)
238 {
239 lcd_remote_clear_display();
240 }
241 else
242 {
243 oldmode = current_vp->drawmode;
244
245 /* Invert the INVERSEVID bit and set basic mode to SOLID */
246 current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) |
247 DRMODE_SOLID;
248
249 lcd_remote_fillrect(0, 0, current_vp->width, current_vp->height);
250
251 current_vp->drawmode = oldmode;
252
253 lcd_remote_scroll_stop(current_vp);
254 }
255}
256
190/* Set a single pixel */ 257/* Set a single pixel */
191void lcd_remote_drawpixel(int x, int y) 258void lcd_remote_drawpixel(int x, int y)
192{ 259{
193 if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) 260 if (((unsigned)x < (unsigned)current_vp->width) &&
194 lcd_remote_pixelfuncs[drawmode](x, y); 261 ((unsigned)y < (unsigned)current_vp->height))
262 lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
195} 263}
196 264
197/* Draw a line */ 265/* Draw a line */
@@ -203,7 +271,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
203 int d, dinc1, dinc2; 271 int d, dinc1, dinc2;
204 int x, xinc1, xinc2; 272 int x, xinc1, xinc2;
205 int y, yinc1, yinc2; 273 int y, yinc1, yinc2;
206 lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[drawmode]; 274 lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode];
207 275
208 deltax = abs(x2 - x1); 276 deltax = abs(x2 - x1);
209 deltay = abs(y2 - y1); 277 deltay = abs(y2 - y1);
@@ -247,8 +315,8 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
247 315
248 for (i = 0; i < numpixels; i++) 316 for (i = 0; i < numpixels; i++)
249 { 317 {
250 if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) 318 if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height))
251 pfunc(x, y); 319 pfunc(x + current_vp->x, y + current_vp->y);
252 320
253 if (d < 0) 321 if (d < 0)
254 { 322 {
@@ -268,7 +336,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
268/* Draw a horizontal line (optimised) */ 336/* Draw a horizontal line (optimised) */
269void lcd_remote_hline(int x1, int x2, int y) 337void lcd_remote_hline(int x1, int x2, int y)
270{ 338{
271 int x; 339 int x, width;
272 fb_remote_data *dst, *dst_end; 340 fb_remote_data *dst, *dst_end;
273 unsigned mask; 341 unsigned mask;
274 lcd_remote_blockfunc_type *bfunc; 342 lcd_remote_blockfunc_type *bfunc;
@@ -282,24 +350,30 @@ void lcd_remote_hline(int x1, int x2, int y)
282 } 350 }
283 351
284 /* nothing to draw? */ 352 /* nothing to draw? */
285 if (((unsigned)y >= LCD_REMOTE_HEIGHT) || (x1 >= LCD_REMOTE_WIDTH) 353 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
286 || (x2 < 0)) 354 || (x2 < 0))
287 return; 355 return;
288 356
289 /* clipping */ 357 /* clipping */
290 if (x1 < 0) 358 if (x1 < 0)
291 x1 = 0; 359 x1 = 0;
292 if (x2 >= LCD_REMOTE_WIDTH) 360 if (x2 >= current_vp->width)
293 x2 = LCD_REMOTE_WIDTH-1; 361 x2 = current_vp->width-1;
294 362
295 bfunc = lcd_remote_blockfuncs[drawmode]; 363 width = x2 - x1 + 1;
364
365 /* Adjust x1 and y to viewport */
366 x1 += current_vp->x;
367 y += current_vp->y;
368
369 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
296 dst = &lcd_remote_framebuffer[y>>3][x1]; 370 dst = &lcd_remote_framebuffer[y>>3][x1];
297 mask = 1 << (y & 7); 371 mask = 1 << (y & 7);
298 372
299 dst_end = dst + x2 - x1; 373 dst_end = dst + width;
300 do 374 do
301 bfunc(dst++, mask, 0xFFu); 375 bfunc(dst++, mask, 0xFFu);
302 while (dst <= dst_end); 376 while (dst < dst_end);
303} 377}
304 378
305/* Draw a vertical line (optimised) */ 379/* Draw a vertical line (optimised) */
@@ -319,17 +393,22 @@ void lcd_remote_vline(int x, int y1, int y2)
319 } 393 }
320 394
321 /* nothing to draw? */ 395 /* nothing to draw? */
322 if (((unsigned)x >= LCD_REMOTE_WIDTH) || (y1 >= LCD_REMOTE_HEIGHT) 396 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
323 || (y2 < 0)) 397 || (y2 < 0))
324 return; 398 return;
325 399
326 /* clipping */ 400 /* clipping */
327 if (y1 < 0) 401 if (y1 < 0)
328 y1 = 0; 402 y1 = 0;
329 if (y2 >= LCD_REMOTE_HEIGHT) 403 if (y2 >= current_vp->height)
330 y2 = LCD_REMOTE_HEIGHT-1; 404 y2 = current_vp->height-1;
405
406 /* adjust for viewport */
407 y1 += current_vp->y;
408 y2 += current_vp->y;
409 x += current_vp->x;
331 410
332 bfunc = lcd_remote_blockfuncs[drawmode]; 411 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
333 dst = &lcd_remote_framebuffer[y1>>3][x]; 412 dst = &lcd_remote_framebuffer[y1>>3][x];
334 ny = y2 - (y1 & ~7); 413 ny = y2 - (y1 & ~7);
335 mask = 0xFFu << (y1 & 7); 414 mask = 0xFFu << (y1 & 7);
@@ -371,8 +450,8 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
371 bool fillopt = false; 450 bool fillopt = false;
372 451
373 /* nothing to draw? */ 452 /* nothing to draw? */
374 if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) 453 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
375 || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) 454 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
376 return; 455 return;
377 456
378 /* clipping */ 457 /* clipping */
@@ -386,27 +465,32 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
386 height += y; 465 height += y;
387 y = 0; 466 y = 0;
388 } 467 }
389 if (x + width > LCD_REMOTE_WIDTH) 468 if (x + width > current_vp->width)
390 width = LCD_REMOTE_WIDTH - x; 469 width = current_vp->width - x;
391 if (y + height > LCD_REMOTE_HEIGHT) 470 if (y + height > current_vp->height)
392 height = LCD_REMOTE_HEIGHT - y; 471 height = current_vp->height - y;
393 472
394 if (drawmode & DRMODE_INVERSEVID) 473 /* adjust for viewport */
474 x += current_vp->x;
475 y += current_vp->y;
476
477 if (current_vp->drawmode & DRMODE_INVERSEVID)
395 { 478 {
396 if (drawmode & DRMODE_BG) 479 if (current_vp->drawmode & DRMODE_BG)
397 { 480 {
398 fillopt = true; 481 fillopt = true;
399 } 482 }
400 } 483 }
401 else 484 else
402 { 485 {
403 if (drawmode & DRMODE_FG) 486 if (current_vp->drawmode & DRMODE_FG)
404 { 487 {
405 fillopt = true; 488 fillopt = true;
406 bits = 0xFFu; 489 bits = 0xFFu;
407 } 490 }
408 } 491 }
409 bfunc = lcd_remote_blockfuncs[drawmode]; 492
493 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
410 dst = &lcd_remote_framebuffer[y>>3][x]; 494 dst = &lcd_remote_framebuffer[y>>3][x];
411 ny = height - 1 + (y & 7); 495 ny = height - 1 + (y & 7);
412 mask = 0xFFu << (y & 7); 496 mask = 0xFFu << (y & 7);
@@ -466,8 +550,8 @@ void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
466 lcd_remote_blockfunc_type *bfunc; 550 lcd_remote_blockfunc_type *bfunc;
467 551
468 /* nothing to draw? */ 552 /* nothing to draw? */
469 if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) 553 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
470 || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) 554 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
471 return; 555 return;
472 556
473 /* clipping */ 557 /* clipping */
@@ -483,10 +567,14 @@ void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
483 src_y -= y; 567 src_y -= y;
484 y = 0; 568 y = 0;
485 } 569 }
486 if (x + width > LCD_REMOTE_WIDTH) 570 if (x + width > current_vp->width)
487 width = LCD_REMOTE_WIDTH - x; 571 width = current_vp->width - x;
488 if (y + height > LCD_REMOTE_HEIGHT) 572 if (y + height > current_vp->height)
489 height = LCD_REMOTE_HEIGHT - y; 573 height = current_vp->height - y;
574
575 /* adjust for viewports */
576 x += current_vp->x;
577 y += current_vp->y;
490 578
491 src += stride * (src_y >> 3) + src_x; /* move starting point */ 579 src += stride * (src_y >> 3) + src_x; /* move starting point */
492 src_y &= 7; 580 src_y &= 7;
@@ -495,13 +583,13 @@ void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
495 shift = y & 7; 583 shift = y & 7;
496 ny = height - 1 + shift + src_y; 584 ny = height - 1 + shift + src_y;
497 585
498 bfunc = lcd_remote_blockfuncs[drawmode]; 586 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
499 mask = 0xFFu << (shift + src_y); 587 mask = 0xFFu << (shift + src_y);
500 mask_bottom = 0xFFu >> (~ny & 7); 588 mask_bottom = 0xFFu >> (~ny & 7);
501 589
502 if (shift == 0) 590 if (shift == 0)
503 { 591 {
504 bool copyopt = (drawmode == DRMODE_SOLID); 592 bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
505 593
506 for (; ny >= 8; ny -= 8) 594 for (; ny >= 8; ny -= 8)
507 { 595 {
@@ -579,11 +667,11 @@ void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str)
579{ 667{
580 unsigned short ch; 668 unsigned short ch;
581 unsigned short *ucs; 669 unsigned short *ucs;
582 struct font* pf = font_get(curfont); 670 struct font* pf = font_get(current_vp->font);
583 671
584 ucs = bidi_l2v(str, 1); 672 ucs = bidi_l2v(str, 1);
585 673
586 while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH) 674 while ((ch = *ucs++) != 0 && x < current_vp->width)
587 { 675 {
588 int width; 676 int width;
589 const unsigned char *bits; 677 const unsigned char *bits;
@@ -637,24 +725,24 @@ void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str,
637 int style, int offset) 725 int style, int offset)
638{ 726{
639 int xpos,ypos,w,h,xrect; 727 int xpos,ypos,w,h,xrect;
640 int lastmode = drawmode; 728 int lastmode = current_vp->drawmode;
641 729
642 /* make sure scrolling is turned off on the line we are updating */ 730 /* make sure scrolling is turned off on the line we are updating */
643 lcd_remote_scroll_info.lines &= ~(1 << y); 731 lcd_remote_scroll_stop_line(current_vp, y);
644 732
645 if(!str || !str[0]) 733 if(!str || !str[0])
646 return; 734 return;
647 735
648 lcd_remote_getstringsize(str, &w, &h); 736 lcd_remote_getstringsize(str, &w, &h);
649 xpos = xmargin + x*w / utf8length((char *)str); 737 xpos = current_vp->xmargin + x*w / utf8length((char *)str);
650 ypos = ymargin + y*h; 738 ypos = current_vp->ymargin + y*h;
651 drawmode = (style & STYLE_INVERT) ? 739 current_vp->drawmode = (style & STYLE_INVERT) ?
652 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 740 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
653 lcd_remote_putsxyofs(xpos, ypos, offset, str); 741 lcd_remote_putsxyofs(xpos, ypos, offset, str);
654 drawmode ^= DRMODE_INVERSEVID; 742 current_vp->drawmode ^= DRMODE_INVERSEVID;
655 xrect = xpos + MAX(w - offset, 0); 743 xrect = xpos + MAX(w - offset, 0);
656 lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h); 744 lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h);
657 drawmode = lastmode; 745 current_vp->drawmode = lastmode;
658} 746}
659 747
660/*** scrolling ***/ 748/*** scrolling ***/
@@ -680,9 +768,15 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
680 struct scrollinfo* s; 768 struct scrollinfo* s;
681 int w, h; 769 int w, h;
682 770
683 if(y>=LCD_REMOTE_SCROLLABLE_LINES) return; 771 if ((unsigned)y >= (unsigned)current_vp->height)
772 return;
773
774 /* remove any previously scrolling line at the same location */
775 lcd_remote_scroll_stop_line(current_vp, y);
776
777 if (lcd_remote_scroll_info.lines >= LCD_REMOTE_SCROLLABLE_LINES) return;
684 778
685 s = &lcd_remote_scroll_info.scroll[y]; 779 s = &lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines];
686 780
687 s->start_tick = current_tick + lcd_remote_scroll_info.delay; 781 s->start_tick = current_tick + lcd_remote_scroll_info.delay;
688 s->style = style; 782 s->style = style;
@@ -694,7 +788,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
694 788
695 lcd_remote_getstringsize(string, &w, &h); 789 lcd_remote_getstringsize(string, &w, &h);
696 790
697 if (LCD_REMOTE_WIDTH - x * 8 - xmargin < w) { 791 if (current_vp->width - x * 8 - current_vp->xmargin < w) {
698 /* prepare scroll line */ 792 /* prepare scroll line */
699 char *end; 793 char *end;
700 794
@@ -707,7 +801,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
707 /* scroll bidirectional or forward only depending on the string 801 /* scroll bidirectional or forward only depending on the string
708 width */ 802 width */
709 if ( lcd_remote_scroll_info.bidir_limit ) { 803 if ( lcd_remote_scroll_info.bidir_limit ) {
710 s->bidir = s->width < (LCD_REMOTE_WIDTH - xmargin) * 804 s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
711 (100 + lcd_remote_scroll_info.bidir_limit) / 100; 805 (100 + lcd_remote_scroll_info.bidir_limit) / 100;
712 } 806 }
713 else 807 else
@@ -720,17 +814,17 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
720 } 814 }
721 815
722 end = strchr(s->line, '\0'); 816 end = strchr(s->line, '\0');
723 strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2); 817 strncpy(end, (char *)string, current_vp->width/2);
724 818
819 s->vp = current_vp;
820 s->y = y;
725 s->len = utf8length((char *)string); 821 s->len = utf8length((char *)string);
726 s->offset = offset; 822 s->offset = offset;
727 s->startx = xmargin + x * s->width / s->len;; 823 s->startx = current_vp->xmargin + x * s->width / s->len;
728 s->backward = false; 824 s->backward = false;
729 lcd_remote_scroll_info.lines |= (1<<y); 825
826 lcd_remote_scroll_info.lines++;
730 } 827 }
731 else
732 /* force a bit switch-off since it doesn't scroll */
733 lcd_remote_scroll_info.lines &= ~(1<<y);
734} 828}
735 829
736void lcd_remote_scroll_fn(void) 830void lcd_remote_scroll_fn(void)
@@ -740,26 +834,25 @@ void lcd_remote_scroll_fn(void)
740 int index; 834 int index;
741 int xpos, ypos; 835 int xpos, ypos;
742 int lastmode; 836 int lastmode;
837 struct viewport* old_vp = current_vp;
743 838
744 for ( index = 0; index < LCD_REMOTE_SCROLLABLE_LINES; index++ ) { 839 for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) {
745 /* really scroll? */
746 if ((lcd_remote_scroll_info.lines & (1 << index)) == 0)
747 continue;
748
749 s = &lcd_remote_scroll_info.scroll[index]; 840 s = &lcd_remote_scroll_info.scroll[index];
750 841
751 /* check pause */ 842 /* check pause */
752 if (TIME_BEFORE(current_tick, s->start_tick)) 843 if (TIME_BEFORE(current_tick, s->start_tick))
753 continue; 844 continue;
754 845
846 lcd_remote_set_viewport(s->vp);
847
755 if (s->backward) 848 if (s->backward)
756 s->offset -= lcd_remote_scroll_info.step; 849 s->offset -= lcd_remote_scroll_info.step;
757 else 850 else
758 s->offset += lcd_remote_scroll_info.step; 851 s->offset += lcd_remote_scroll_info.step;
759 852
760 pf = font_get(curfont); 853 pf = font_get(current_vp->font);
761 xpos = s->startx; 854 xpos = s->startx;
762 ypos = ymargin + index * pf->height; 855 ypos = current_vp->ymargin + s->y * pf->height;
763 856
764 if (s->bidir) { /* scroll bidirectional */ 857 if (s->bidir) { /* scroll bidirectional */
765 if (s->offset <= 0) { 858 if (s->offset <= 0) {
@@ -768,9 +861,9 @@ void lcd_remote_scroll_fn(void)
768 s->backward = false; 861 s->backward = false;
769 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; 862 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
770 } 863 }
771 if (s->offset >= s->width - (LCD_REMOTE_WIDTH - xpos)) { 864 if (s->offset >= s->width - (current_vp->width - xpos)) {
772 /* at end of line */ 865 /* at end of line */
773 s->offset = s->width - (LCD_REMOTE_WIDTH - xpos); 866 s->offset = s->width - (current_vp->width - xpos);
774 s->backward = true; 867 s->backward = true;
775 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; 868 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
776 } 869 }
@@ -781,13 +874,16 @@ void lcd_remote_scroll_fn(void)
781 s->offset %= s->width; 874 s->offset %= s->width;
782 } 875 }
783 876
784 lastmode = drawmode; 877 lastmode = current_vp->drawmode;
785 drawmode = (s->style&STYLE_INVERT) ? 878 current_vp->drawmode = (s->style&STYLE_INVERT) ?
786 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 879 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
787 lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line); 880 lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line);
788 drawmode = lastmode; 881 current_vp->drawmode = lastmode;
789 lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height); 882 lcd_remote_update_viewport_rect(xpos, ypos,
883 current_vp->width - xpos, pf->height);
790 } 884 }
885
886 lcd_remote_set_viewport(old_vp);
791} 887}
792 888
793/* LCD init */ 889/* 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};
46static fb_remote_data* remote_backdrop = NULL; 46static fb_remote_data* remote_backdrop = NULL;
47static long remote_backdrop_offset IDATA_ATTR = 0; 47static long remote_backdrop_offset IDATA_ATTR = 0;
48 48
49static unsigned fg_pattern IDATA_ATTR = 0xFFFF; /* initially black */ 49static struct viewport default_vp =
50static unsigned bg_pattern IDATA_ATTR = 0x0000; /* initially white */ 50{
51static int drawmode = DRMODE_SOLID; 51 .x = 0,
52static int xmargin = 0; 52 .y = 0,
53static int ymargin = 0; 53 .width = LCD_REMOTE_WIDTH,
54static int curfont = FONT_SYSFIXED; 54 .height = LCD_REMOTE_HEIGHT,
55 .font = FONT_SYSFIXED,
56 .drawmode = DRMODE_SOLID,
57 .xmargin = 0,
58 .ymargin = 0,
59 .fg_pattern = LCD_REMOTE_DEFAULT_FG,
60 .bg_pattern = LCD_REMOTE_DEFAULT_BG
61};
62
63static unsigned fg_pattern IBSS_ATTR;
64static unsigned bg_pattern IBSS_ATTR;
65
66static struct viewport* current_vp IBSS_ATTR;;
67
68/*** Viewports ***/
69
70void lcd_remote_set_viewport(struct viewport* vp)
71{
72 if (vp == NULL)
73 current_vp = &default_vp;
74 else
75 current_vp = vp;
76
77 fg_pattern = patterns[current_vp->fg_pattern & 3];
78 bg_pattern = patterns[current_vp->bg_pattern & 3];
79}
80
81void lcd_remote_update_viewport(void)
82{
83 lcd_remote_update_rect(current_vp->x, current_vp->y,
84 current_vp->width, current_vp->height);
85}
86
87void lcd_remote_update_viewport_rect(int x, int y, int width, int height)
88{
89 lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height);
90}
55 91
56/*** parameter handling ***/ 92/*** parameter handling ***/
57unsigned lcd_remote_color_to_native(unsigned color) 93unsigned lcd_remote_color_to_native(unsigned color)
@@ -69,32 +105,34 @@ unsigned lcd_remote_color_to_native(unsigned color)
69 105
70void lcd_remote_set_drawmode(int mode) 106void lcd_remote_set_drawmode(int mode)
71{ 107{
72 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); 108 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
73} 109}
74 110
75int lcd_remote_get_drawmode(void) 111int lcd_remote_get_drawmode(void)
76{ 112{
77 return drawmode; 113 return current_vp->drawmode;
78} 114}
79 115
80void lcd_remote_set_foreground(unsigned brightness) 116void lcd_remote_set_foreground(unsigned brightness)
81{ 117{
118 current_vp->fg_pattern = brightness;
82 fg_pattern = patterns[brightness & 3]; 119 fg_pattern = patterns[brightness & 3];
83} 120}
84 121
85unsigned lcd_remote_get_foreground(void) 122unsigned lcd_remote_get_foreground(void)
86{ 123{
87 return (~fg_pattern >> 7) & 3; 124 return current_vp->fg_pattern;
88} 125}
89 126
90void lcd_remote_set_background(unsigned brightness) 127void lcd_remote_set_background(unsigned brightness)
91{ 128{
129 current_vp->bg_pattern = brightness;
92 bg_pattern = patterns[brightness & 3]; 130 bg_pattern = patterns[brightness & 3];
93} 131}
94 132
95unsigned lcd_remote_get_background(void) 133unsigned lcd_remote_get_background(void)
96{ 134{
97 return (~bg_pattern >> 7) & 3; 135 return current_vp->bg_pattern;
98} 136}
99 137
100void lcd_remote_set_drawinfo(int mode, unsigned fg_brightness, 138void lcd_remote_set_drawinfo(int mode, unsigned fg_brightness,
@@ -105,30 +143,40 @@ void lcd_remote_set_drawinfo(int mode, unsigned fg_brightness,
105 lcd_remote_set_background(bg_brightness); 143 lcd_remote_set_background(bg_brightness);
106} 144}
107 145
146int lcd_remote_getwidth(void)
147{
148 return current_vp->width;
149}
150
151int lcd_remote_getheight(void)
152{
153 return current_vp->height;
154}
155
108void lcd_remote_setmargins(int x, int y) 156void lcd_remote_setmargins(int x, int y)
109{ 157{
110 xmargin = x; 158 current_vp->xmargin = x;
111 ymargin = y; 159 current_vp->ymargin = y;
112} 160}
113 161
114int lcd_remote_getxmargin(void) 162int lcd_remote_getxmargin(void)
115{ 163{
116 return xmargin; 164 return current_vp->xmargin;
117} 165}
118 166
119int lcd_remote_getymargin(void) 167int lcd_remote_getymargin(void)
120{ 168{
121 return ymargin; 169 return current_vp->ymargin;
122} 170}
123 171
124void lcd_remote_setfont(int newfont) 172void lcd_remote_setfont(int newfont)
125{ 173{
126 curfont = newfont; 174 current_vp->font = newfont;
127} 175}
128 176
129int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h) 177int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h)
130{ 178{
131 return font_getstringsize(str, w, h, curfont); 179 return font_getstringsize(str, w, h, current_vp->font);
132} 180}
133 181
134/*** low-level drawing functions ***/ 182/*** low-level drawing functions ***/
@@ -351,9 +399,9 @@ static inline void setblock(fb_remote_data *address, unsigned mask, unsigned bit
351/* Clear the whole display */ 399/* Clear the whole display */
352void lcd_remote_clear_display(void) 400void lcd_remote_clear_display(void)
353{ 401{
354 if (drawmode & DRMODE_INVERSEVID) 402 if (default_vp.drawmode & DRMODE_INVERSEVID)
355 { 403 {
356 memset(lcd_remote_framebuffer, fg_pattern, 404 memset(lcd_remote_framebuffer, patterns[default_vp.fg_pattern & 3],
357 sizeof lcd_remote_framebuffer); 405 sizeof lcd_remote_framebuffer);
358 } 406 }
359 else 407 else
@@ -362,18 +410,44 @@ void lcd_remote_clear_display(void)
362 memcpy(lcd_remote_framebuffer, remote_backdrop, 410 memcpy(lcd_remote_framebuffer, remote_backdrop,
363 sizeof lcd_remote_framebuffer); 411 sizeof lcd_remote_framebuffer);
364 else 412 else
365 memset(lcd_remote_framebuffer, bg_pattern, 413 memset(lcd_remote_framebuffer, patterns[default_vp.bg_pattern & 3],
366 sizeof lcd_remote_framebuffer); 414 sizeof lcd_remote_framebuffer);
367 } 415 }
368 416
369 lcd_remote_scroll_info.lines = 0; 417 lcd_remote_scroll_info.lines = 0;
370} 418}
371 419
420/* Clear the current viewport */
421void lcd_remote_clear_viewport(void)
422{
423 int lastmode;
424
425 if (current_vp == &default_vp)
426 {
427 lcd_remote_clear_display();
428 }
429 else
430 {
431 lastmode = current_vp->drawmode;
432
433 /* Invert the INVERSEVID bit and set basic mode to SOLID */
434 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
435 DRMODE_SOLID;
436
437 lcd_remote_fillrect(0, 0, current_vp->width, current_vp->height);
438
439 current_vp->drawmode = lastmode;
440
441 lcd_remote_scroll_stop(current_vp);
442 }
443}
444
372/* Set a single pixel */ 445/* Set a single pixel */
373void lcd_remote_drawpixel(int x, int y) 446void lcd_remote_drawpixel(int x, int y)
374{ 447{
375 if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) 448 if (((unsigned)x < (unsigned)current_vp->width) &&
376 lcd_remote_pixelfuncs[drawmode](x, y); 449 ((unsigned)y < (unsigned)current_vp->height))
450 lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
377} 451}
378 452
379/* Draw a line */ 453/* Draw a line */
@@ -385,7 +459,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
385 int d, dinc1, dinc2; 459 int d, dinc1, dinc2;
386 int x, xinc1, xinc2; 460 int x, xinc1, xinc2;
387 int y, yinc1, yinc2; 461 int y, yinc1, yinc2;
388 lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[drawmode]; 462 lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode];
389 463
390 deltax = abs(x2 - x1); 464 deltax = abs(x2 - x1);
391 deltay = abs(y2 - y1); 465 deltay = abs(y2 - y1);
@@ -429,8 +503,9 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
429 503
430 for (i = 0; i < numpixels; i++) 504 for (i = 0; i < numpixels; i++)
431 { 505 {
432 if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) 506 if (((unsigned)x < (unsigned)current_vp->width) &&
433 pfunc(x, y); 507 ((unsigned)y < (unsigned)current_vp->height))
508 pfunc(current_vp->x + x, current_vp->y + y);
434 509
435 if (d < 0) 510 if (d < 0)
436 { 511 {
@@ -451,6 +526,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
451void lcd_remote_hline(int x1, int x2, int y) 526void lcd_remote_hline(int x1, int x2, int y)
452{ 527{
453 int x; 528 int x;
529 int width;
454 fb_remote_data *dst, *dst_end; 530 fb_remote_data *dst, *dst_end;
455 unsigned mask; 531 unsigned mask;
456 lcd_remote_blockfunc_type *bfunc; 532 lcd_remote_blockfunc_type *bfunc;
@@ -464,24 +540,30 @@ void lcd_remote_hline(int x1, int x2, int y)
464 } 540 }
465 541
466 /* nothing to draw? */ 542 /* nothing to draw? */
467 if (((unsigned)y >= LCD_REMOTE_HEIGHT) || (x1 >= LCD_REMOTE_WIDTH) 543 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
468 || (x2 < 0)) 544 || (x2 < 0))
469 return; 545 return;
470 546
471 /* clipping */ 547 /* clipping */
472 if (x1 < 0) 548 if (x1 < 0)
473 x1 = 0; 549 x1 = 0;
474 if (x2 >= LCD_REMOTE_WIDTH) 550 if (x2 >= current_vp->width)
475 x2 = LCD_REMOTE_WIDTH-1; 551 x2 = current_vp->width-1;
476 552
477 bfunc = lcd_remote_blockfuncs[drawmode]; 553 width = x2 - x1 + 1;
554
555 /* adjust x1 and y to viewport */
556 x1 += current_vp->x;
557 y += current_vp->y;
558
559 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
478 dst = &lcd_remote_framebuffer[y>>3][x1]; 560 dst = &lcd_remote_framebuffer[y>>3][x1];
479 mask = 0x0101 << (y & 7); 561 mask = 0x0101 << (y & 7);
480 562
481 dst_end = dst + x2 - x1; 563 dst_end = dst + width;
482 do 564 do
483 bfunc(dst++, mask, 0xFFFFu); 565 bfunc(dst++, mask, 0xFFFFu);
484 while (dst <= dst_end); 566 while (dst < dst_end);
485} 567}
486 568
487/* Draw a vertical line (optimised) */ 569/* Draw a vertical line (optimised) */
@@ -501,17 +583,22 @@ void lcd_remote_vline(int x, int y1, int y2)
501 } 583 }
502 584
503 /* nothing to draw? */ 585 /* nothing to draw? */
504 if (((unsigned)x >= LCD_REMOTE_WIDTH) || (y1 >= LCD_REMOTE_HEIGHT) 586 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
505 || (y2 < 0)) 587 || (y2 < 0))
506 return; 588 return;
507 589
508 /* clipping */ 590 /* clipping */
509 if (y1 < 0) 591 if (y1 < 0)
510 y1 = 0; 592 y1 = 0;
511 if (y2 >= LCD_REMOTE_HEIGHT) 593 if (y2 >= current_vp->height)
512 y2 = LCD_REMOTE_HEIGHT-1; 594 y2 = current_vp->height-1;
595
596 /* adjust for viewport */
597 y1 += current_vp->y;
598 y2 += current_vp->y;
599 x += current_vp->x;
513 600
514 bfunc = lcd_remote_blockfuncs[drawmode]; 601 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
515 dst = &lcd_remote_framebuffer[y1>>3][x]; 602 dst = &lcd_remote_framebuffer[y1>>3][x];
516 ny = y2 - (y1 & ~7); 603 ny = y2 - (y1 & ~7);
517 mask = (0xFFu << (y1 & 7)) & 0xFFu; 604 mask = (0xFFu << (y1 & 7)) & 0xFFu;
@@ -555,8 +642,8 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
555 bool fillopt = false; 642 bool fillopt = false;
556 643
557 /* nothing to draw? */ 644 /* nothing to draw? */
558 if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) 645 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
559 || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) 646 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
560 return; 647 return;
561 648
562 /* clipping */ 649 /* clipping */
@@ -570,14 +657,18 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
570 height += y; 657 height += y;
571 y = 0; 658 y = 0;
572 } 659 }
573 if (x + width > LCD_REMOTE_WIDTH) 660 if (x + width > current_vp->width)
574 width = LCD_REMOTE_WIDTH - x; 661 width = current_vp->width - x;
575 if (y + height > LCD_REMOTE_HEIGHT) 662 if (y + height > current_vp->height)
576 height = LCD_REMOTE_HEIGHT - y; 663 height = current_vp->height - y;
577 664
578 if (drawmode & DRMODE_INVERSEVID) 665 /* adjust for viewport */
666 x += current_vp->x;
667 y += current_vp->y;
668
669 if (current_vp->drawmode & DRMODE_INVERSEVID)
579 { 670 {
580 if ((drawmode & DRMODE_BG) && !remote_backdrop) 671 if ((current_vp->drawmode & DRMODE_BG) && !remote_backdrop)
581 { 672 {
582 fillopt = true; 673 fillopt = true;
583 bits = bg_pattern; 674 bits = bg_pattern;
@@ -585,13 +676,13 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
585 } 676 }
586 else 677 else
587 { 678 {
588 if (drawmode & DRMODE_FG) 679 if (current_vp->drawmode & DRMODE_FG)
589 { 680 {
590 fillopt = true; 681 fillopt = true;
591 bits = fg_pattern; 682 bits = fg_pattern;
592 } 683 }
593 } 684 }
594 bfunc = lcd_remote_blockfuncs[drawmode]; 685 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
595 dst = &lcd_remote_framebuffer[y>>3][x]; 686 dst = &lcd_remote_framebuffer[y>>3][x];
596 ny = height - 1 + (y & 7); 687 ny = height - 1 + (y & 7);
597 mask = (0xFFu << (y & 7)) & 0xFFu; 688 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,
653 lcd_remote_blockfunc_type *bfunc; 744 lcd_remote_blockfunc_type *bfunc;
654 745
655 /* nothing to draw? */ 746 /* nothing to draw? */
656 if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) 747 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
657 || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) 748 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
658 return; 749 return;
659 750
660 /* clipping */ 751 /* clipping */
@@ -670,10 +761,14 @@ void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
670 src_y -= y; 761 src_y -= y;
671 y = 0; 762 y = 0;
672 } 763 }
673 if (x + width > LCD_REMOTE_WIDTH) 764 if (x + width > current_vp->width)
674 width = LCD_REMOTE_WIDTH - x; 765 width = current_vp->width - x;
675 if (y + height > LCD_REMOTE_HEIGHT) 766 if (y + height > current_vp->height)
676 height = LCD_REMOTE_HEIGHT - y; 767 height = current_vp->height - y;
768
769 /* adjust for viewport */
770 x += current_vp->x;
771 y += current_vp->y;
677 772
678 src += stride * (src_y >> 3) + src_x; /* move starting point */ 773 src += stride * (src_y >> 3) + src_x; /* move starting point */
679 src_y &= 7; 774 src_y &= 7;
@@ -682,7 +777,7 @@ void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
682 shift = y & 7; 777 shift = y & 7;
683 ny = height - 1 + shift + src_y; 778 ny = height - 1 + shift + src_y;
684 779
685 bfunc = lcd_remote_blockfuncs[drawmode]; 780 bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
686 mask = 0xFFu << (shift + src_y); 781 mask = 0xFFu << (shift + src_y);
687 /* not byte-doubled here because shift+src_y can be > 7 */ 782 /* not byte-doubled here because shift+src_y can be > 7 */
688 mask_bottom = 0xFFu >> (~ny & 7); 783 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,
793 unsigned mask, mask_bottom; 888 unsigned mask, mask_bottom;
794 889
795 /* nothing to draw? */ 890 /* nothing to draw? */
796 if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) 891 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
797 || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) 892 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
798 return; 893 return;
799 894
800 /* clipping */ 895 /* clipping */
@@ -810,10 +905,14 @@ void lcd_remote_bitmap_part(const fb_remote_data *src, int src_x, int src_y,
810 src_y -= y; 905 src_y -= y;
811 y = 0; 906 y = 0;
812 } 907 }
813 if (x + width > LCD_REMOTE_WIDTH) 908 if (x + width > current_vp->width)
814 width = LCD_REMOTE_WIDTH - x; 909 width = current_vp->width - x;
815 if (y + height > LCD_REMOTE_HEIGHT) 910 if (y + height > current_vp->height)
816 height = LCD_REMOTE_HEIGHT - y; 911 height = current_vp->height - y;
912
913 /* adjust for viewport */
914 x += current_vp->x;
915 y += current_vp->y;
817 916
818 src += stride * (src_y >> 3) + src_x; /* move starting point */ 917 src += stride * (src_y >> 3) + src_x; /* move starting point */
819 src_y &= 7; 918 src_y &= 7;
@@ -917,11 +1016,11 @@ void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str)
917{ 1016{
918 unsigned short ch; 1017 unsigned short ch;
919 unsigned short *ucs; 1018 unsigned short *ucs;
920 struct font* pf = font_get(curfont); 1019 struct font* pf = font_get(current_vp->font);
921 1020
922 ucs = bidi_l2v(str, 1); 1021 ucs = bidi_l2v(str, 1);
923 1022
924 while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH) 1023 while ((ch = *ucs++) != 0 && x < current_vp->width)
925 { 1024 {
926 int width; 1025 int width;
927 const unsigned char *bits; 1026 const unsigned char *bits;
@@ -975,24 +1074,24 @@ void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str,
975 int style, int offset) 1074 int style, int offset)
976{ 1075{
977 int xpos,ypos,w,h,xrect; 1076 int xpos,ypos,w,h,xrect;
978 int lastmode = drawmode; 1077 int lastmode = current_vp->drawmode;
979 1078
980 /* make sure scrolling is turned off on the line we are updating */ 1079 /* make sure scrolling is turned off on the line we are updating */
981 lcd_remote_scroll_info.lines &= ~(1 << y); 1080 lcd_remote_scroll_stop_line(current_vp, y);
982 1081
983 if(!str || !str[0]) 1082 if(!str || !str[0])
984 return; 1083 return;
985 1084
986 lcd_remote_getstringsize(str, &w, &h); 1085 lcd_remote_getstringsize(str, &w, &h);
987 xpos = xmargin + x*w / utf8length((char *)str); 1086 xpos = current_vp->xmargin + x*w / utf8length((char *)str);
988 ypos = ymargin + y*h; 1087 ypos = current_vp->ymargin + y*h;
989 drawmode = (style & STYLE_INVERT) ? 1088 current_vp->drawmode = (style & STYLE_INVERT) ?
990 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 1089 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
991 lcd_remote_putsxyofs(xpos, ypos, offset, str); 1090 lcd_remote_putsxyofs(xpos, ypos, offset, str);
992 drawmode ^= DRMODE_INVERSEVID; 1091 current_vp->drawmode ^= DRMODE_INVERSEVID;
993 xrect = xpos + MAX(w - offset, 0); 1092 xrect = xpos + MAX(w - offset, 0);
994 lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h); 1093 lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h);
995 drawmode = lastmode; 1094 current_vp->drawmode = lastmode;
996} 1095}
997 1096
998/*** scrolling ***/ 1097/*** scrolling ***/
@@ -1017,9 +1116,15 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
1017 struct scrollinfo* s; 1116 struct scrollinfo* s;
1018 int w, h; 1117 int w, h;
1019 1118
1020 if(y>=LCD_REMOTE_SCROLLABLE_LINES) return; 1119 if ((unsigned)y >= (unsigned)current_vp->height)
1120 return;
1021 1121
1022 s = &lcd_remote_scroll_info.scroll[y]; 1122 /* remove any previously scrolling line at the same location */
1123 lcd_remote_scroll_stop_line(current_vp, y);
1124
1125 if (lcd_remote_scroll_info.lines >= LCD_REMOTE_SCROLLABLE_LINES) return;
1126
1127 s = &lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines];
1023 1128
1024 s->start_tick = current_tick + lcd_remote_scroll_info.delay; 1129 s->start_tick = current_tick + lcd_remote_scroll_info.delay;
1025 s->style = style; 1130 s->style = style;
@@ -1031,7 +1136,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
1031 1136
1032 lcd_remote_getstringsize(string, &w, &h); 1137 lcd_remote_getstringsize(string, &w, &h);
1033 1138
1034 if (LCD_REMOTE_WIDTH - x * 8 - xmargin < w) { 1139 if (current_vp->width - x * 8 - current_vp->xmargin < w) {
1035 /* prepare scroll line */ 1140 /* prepare scroll line */
1036 char *end; 1141 char *end;
1037 1142
@@ -1044,7 +1149,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
1044 /* scroll bidirectional or forward only depending on the string 1149 /* scroll bidirectional or forward only depending on the string
1045 width */ 1150 width */
1046 if ( lcd_remote_scroll_info.bidir_limit ) { 1151 if ( lcd_remote_scroll_info.bidir_limit ) {
1047 s->bidir = s->width < (LCD_REMOTE_WIDTH - xmargin) * 1152 s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
1048 (100 + lcd_remote_scroll_info.bidir_limit) / 100; 1153 (100 + lcd_remote_scroll_info.bidir_limit) / 100;
1049 } 1154 }
1050 else 1155 else
@@ -1057,17 +1162,17 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
1057 } 1162 }
1058 1163
1059 end = strchr(s->line, '\0'); 1164 end = strchr(s->line, '\0');
1060 strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2); 1165 strncpy(end, (char *)string, current_vp->width/2);
1061 1166
1167 s->vp = current_vp;
1168 s->y = y;
1062 s->len = utf8length((char *)string); 1169 s->len = utf8length((char *)string);
1063 s->offset = offset; 1170 s->offset = offset;
1064 s->startx = xmargin + x * s->width / s->len;; 1171 s->startx = current_vp->xmargin + x * s->width / s->len;
1065 s->backward = false; 1172 s->backward = false;
1066 lcd_remote_scroll_info.lines |= (1<<y); 1173
1174 lcd_remote_scroll_info.lines++;
1067 } 1175 }
1068 else
1069 /* force a bit switch-off since it doesn't scroll */
1070 lcd_remote_scroll_info.lines &= ~(1<<y);
1071} 1176}
1072 1177
1073void lcd_remote_scroll_fn(void) 1178void lcd_remote_scroll_fn(void)
@@ -1077,26 +1182,25 @@ void lcd_remote_scroll_fn(void)
1077 int index; 1182 int index;
1078 int xpos, ypos; 1183 int xpos, ypos;
1079 int lastmode; 1184 int lastmode;
1185 struct viewport* old_vp = current_vp;
1080 1186
1081 for ( index = 0; index < LCD_REMOTE_SCROLLABLE_LINES; index++ ) { 1187 for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) {
1082 /* really scroll? */
1083 if ((lcd_remote_scroll_info.lines & (1 << index)) == 0)
1084 continue;
1085
1086 s = &lcd_remote_scroll_info.scroll[index]; 1188 s = &lcd_remote_scroll_info.scroll[index];
1087 1189
1088 /* check pause */ 1190 /* check pause */
1089 if (TIME_BEFORE(current_tick, s->start_tick)) 1191 if (TIME_BEFORE(current_tick, s->start_tick))
1090 continue; 1192 continue;
1091 1193
1194 lcd_remote_set_viewport(s->vp);
1195
1092 if (s->backward) 1196 if (s->backward)
1093 s->offset -= lcd_remote_scroll_info.step; 1197 s->offset -= lcd_remote_scroll_info.step;
1094 else 1198 else
1095 s->offset += lcd_remote_scroll_info.step; 1199 s->offset += lcd_remote_scroll_info.step;
1096 1200
1097 pf = font_get(curfont); 1201 pf = font_get(current_vp->font);
1098 xpos = s->startx; 1202 xpos = s->startx;
1099 ypos = ymargin + index * pf->height; 1203 ypos = current_vp->ymargin + s->y * pf->height;
1100 1204
1101 if (s->bidir) { /* scroll bidirectional */ 1205 if (s->bidir) { /* scroll bidirectional */
1102 if (s->offset <= 0) { 1206 if (s->offset <= 0) {
@@ -1105,9 +1209,9 @@ void lcd_remote_scroll_fn(void)
1105 s->backward = false; 1209 s->backward = false;
1106 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; 1210 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
1107 } 1211 }
1108 if (s->offset >= s->width - (LCD_REMOTE_WIDTH - xpos)) { 1212 if (s->offset >= s->width - (current_vp->width - xpos)) {
1109 /* at end of line */ 1213 /* at end of line */
1110 s->offset = s->width - (LCD_REMOTE_WIDTH - xpos); 1214 s->offset = s->width - (current_vp->width - xpos);
1111 s->backward = true; 1215 s->backward = true;
1112 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; 1216 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
1113 } 1217 }
@@ -1118,18 +1222,24 @@ void lcd_remote_scroll_fn(void)
1118 s->offset %= s->width; 1222 s->offset %= s->width;
1119 } 1223 }
1120 1224
1121 lastmode = drawmode; 1225 lastmode = current_vp->drawmode;
1122 drawmode = (s->style&STYLE_INVERT) ? 1226 current_vp->drawmode = (s->style&STYLE_INVERT) ?
1123 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; 1227 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1124 lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line); 1228 lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line);
1125 drawmode = lastmode; 1229 current_vp->drawmode = lastmode;
1126 lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height); 1230 lcd_remote_update_viewport_rect(xpos, ypos,
1231 current_vp->width - xpos, pf->height);
1127 } 1232 }
1233
1234 lcd_remote_set_viewport(old_vp);
1128} 1235}
1129 1236
1130/* LCD init */ 1237/* LCD init */
1131void lcd_remote_init(void) 1238void lcd_remote_init(void)
1132{ 1239{
1240 /* Initialise the viewport */
1241 lcd_remote_set_viewport(NULL);
1242
1133#ifndef SIMULATOR 1243#ifndef SIMULATOR
1134 /* Call device specific init */ 1244 /* Call device specific init */
1135 lcd_remote_init_device(); 1245 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 @@
24#include "cpu.h" 24#include "cpu.h"
25#include "config.h" 25#include "config.h"
26#include "adc.h" 26#include "adc.h"
27#include "lcd.h"
27 28
28#ifdef HAVE_REMOTE_LCD 29#ifdef HAVE_REMOTE_LCD
29 30
@@ -109,7 +110,9 @@ extern void lcd_remote_init(void);
109extern int lcd_remote_default_contrast(void); 110extern int lcd_remote_default_contrast(void);
110extern void lcd_remote_set_contrast(int val); 111extern void lcd_remote_set_contrast(int val);
111 112
113extern void lcd_remote_set_viewport(struct viewport* vp);
112extern void lcd_remote_clear_display(void); 114extern void lcd_remote_clear_display(void);
115extern void lcd_remote_clear_viewport(void);
113extern void lcd_remote_puts(int x, int y, const unsigned char *str); 116extern void lcd_remote_puts(int x, int y, const unsigned char *str);
114extern void lcd_remote_puts_style(int x, int y, const unsigned char *str, 117extern void lcd_remote_puts_style(int x, int y, const unsigned char *str,
115 int style); 118 int style);
@@ -132,6 +135,8 @@ extern void lcd_remote_puts_scroll_style_offset(int x, int y,
132 135
133extern void lcd_remote_update(void); 136extern void lcd_remote_update(void);
134extern void lcd_remote_update_rect(int x, int y, int width, int height); 137extern void lcd_remote_update_rect(int x, int y, int width, int height);
138extern void lcd_remote_update_viewport(void);
139extern void lcd_remote_update_viewport_rect(int x, int y, int width, int height);
135 140
136extern void lcd_remote_set_invert_display(bool yesno); 141extern void lcd_remote_set_invert_display(bool yesno);
137extern void lcd_remote_set_flip(bool yesno); 142extern void lcd_remote_set_flip(bool yesno);
@@ -141,6 +146,8 @@ extern int lcd_remote_get_drawmode(void);
141extern void lcd_remote_setmargins(int xmargin, int ymargin); 146extern void lcd_remote_setmargins(int xmargin, int ymargin);
142extern int lcd_remote_getxmargin(void); 147extern int lcd_remote_getxmargin(void);
143extern int lcd_remote_getymargin(void); 148extern int lcd_remote_getymargin(void);
149extern int lcd_remote_getwidth(void);
150extern int lcd_remote_getheight(void);
144extern void lcd_remote_setfont(int font); 151extern void lcd_remote_setfont(int font);
145extern int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h); 152extern int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h);
146 153
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 @@
24#include "cpu.h" 24#include "cpu.h"
25#include "config.h" 25#include "config.h"
26 26
27struct viewport {
28 int x;
29 int y;
30 int width;
31 int height;
32#ifdef HAVE_LCD_BITMAP
33 int font;
34 int drawmode;
35#endif
36 int xmargin; /* During the transition only - to be removed */
37 int ymargin; /* During the transition only - to be removed */
38#if LCD_DEPTH > 1
39 unsigned fg_pattern;
40 unsigned bg_pattern;
41#ifdef HAVE_LCD_COLOR
42 unsigned lss_pattern;
43 unsigned lse_pattern;
44 unsigned lst_pattern;
45#endif
46#endif
47};
48
27#define STYLE_DEFAULT 0x00000000 49#define STYLE_DEFAULT 0x00000000
28#define STYLE_COLORED 0x10000000 50#define STYLE_COLORED 0x10000000
29#define STYLE_INVERT 0x20000000 51#define STYLE_INVERT 0x20000000
@@ -76,9 +98,14 @@ extern void lcd_set_contrast(int val);
76extern void lcd_setmargins(int xmargin, int ymargin); 98extern void lcd_setmargins(int xmargin, int ymargin);
77extern int lcd_getxmargin(void); 99extern int lcd_getxmargin(void);
78extern int lcd_getymargin(void); 100extern int lcd_getymargin(void);
101extern int lcd_getwidth(void);
102extern int lcd_getheight(void);
79extern int lcd_getstringsize(const unsigned char *str, int *w, int *h); 103extern int lcd_getstringsize(const unsigned char *str, int *w, int *h);
80 104
105extern void lcd_set_viewport(struct viewport* vp);
81extern void lcd_update(void); 106extern void lcd_update(void);
107extern void lcd_update_viewport(void);
108extern void lcd_clear_viewport(void);
82extern void lcd_clear_display(void); 109extern void lcd_clear_display(void);
83extern void lcd_putsxy(int x, int y, const unsigned char *string); 110extern void lcd_putsxy(int x, int y, const unsigned char *string);
84extern void lcd_puts(int x, int y, const unsigned char *string); 111extern 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,
119 146
120/* update a fraction of the screen */ 147/* update a fraction of the screen */
121extern void lcd_update_rect(int x, int y, int width, int height); 148extern void lcd_update_rect(int x, int y, int width, int height);
149extern void lcd_update_viewport_rect(int x, int y, int width, int height);
122 150
123#ifdef HAVE_REMOTE_LCD 151#ifdef HAVE_REMOTE_LCD
124extern void lcd_remote_update(void); 152extern 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 @@
23#ifndef __SCROLL_ENGINE_H__ 23#ifndef __SCROLL_ENGINE_H__
24#define __SCROLL_ENGINE_H__ 24#define __SCROLL_ENGINE_H__
25 25
26#include <lcd.h>
27
26void scroll_init(void); 28void scroll_init(void);
29void lcd_scroll_stop(struct viewport* vp);
30void lcd_scroll_stop_line(struct viewport* vp, int y);
27void lcd_scroll_fn(void); 31void lcd_scroll_fn(void);
32#ifdef HAVE_REMOTE_LCD
28void lcd_remote_scroll_fn(void); 33void lcd_remote_scroll_fn(void);
34void lcd_remote_scroll_stop(struct viewport* vp);
35void lcd_remote_scroll_stop_line(struct viewport* vp, int y);
36#endif
29 37
30/* internal usage, but in multiple drivers */ 38/* internal usage, but in multiple drivers */
31#define SCROLL_SPACING 3 39#define SCROLL_SPACING 3
@@ -37,8 +45,10 @@ void lcd_remote_scroll_fn(void);
37 45
38struct scrollinfo 46struct scrollinfo
39{ 47{
48 struct viewport* vp;
40 char line[SCROLL_LINE_SIZE]; 49 char line[SCROLL_LINE_SIZE];
41 int len; /* length of line in chars */ 50 int len; /* length of line in chars */
51 int y; /* Position of the line on the screen (char co-ordinates) */
42 int offset; 52 int offset;
43 int startx; 53 int startx;
44#ifdef HAVE_LCD_BITMAP 54#ifdef HAVE_LCD_BITMAP
@@ -54,7 +64,7 @@ struct scroll_screen_info
54{ 64{
55 struct scrollinfo * const scroll; 65 struct scrollinfo * const scroll;
56 const int num_scroll; /* number of scrollable lines (also number of scroll structs) */ 66 const int num_scroll; /* number of scrollable lines (also number of scroll structs) */
57 int lines; /* Bitpattern of which lines are scrolling */ 67 int lines; /* Number of currently scrolling lines */
58 long ticks; /* # of ticks between updates*/ 68 long ticks; /* # of ticks between updates*/
59 long delay; /* ticks delay before start */ 69 long delay; /* ticks delay before start */
60 int bidir_limit; /* percent */ 70 int bidir_limit; /* percent */
@@ -74,7 +84,7 @@ struct scroll_screen_info
74#ifdef HAVE_LCD_BITMAP 84#ifdef HAVE_LCD_BITMAP
75#define LCD_SCROLLABLE_LINES ((LCD_HEIGHT+4)/5 < 32 ? (LCD_HEIGHT+4)/5 : 32) 85#define LCD_SCROLLABLE_LINES ((LCD_HEIGHT+4)/5 < 32 ? (LCD_HEIGHT+4)/5 : 32)
76#else 86#else
77#define LCD_SCROLLABLE_LINES LCD_HEIGHT 87#define LCD_SCROLLABLE_LINES LCD_HEIGHT * 2
78#endif 88#endif
79 89
80extern struct scroll_screen_info lcd_scroll_info; 90extern 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)
82 lcd_scroll_info.lines = 0; 82 lcd_scroll_info.lines = 0;
83} 83}
84 84
85/* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
86void lcd_scroll_stop_line(struct viewport* current_vp, int y)
87{
88 int i = 0;
89
90 while (i < lcd_scroll_info.lines)
91 {
92 if ((lcd_scroll_info.scroll[i].vp == current_vp) &&
93 ((y < 0) || (lcd_scroll_info.scroll[i].y == y)))
94 {
95 /* If i is not the last active line in the array, then move
96 the last item to position i */
97 if ((i + 1) != lcd_scroll_info.lines)
98 {
99 lcd_scroll_info.scroll[i] = lcd_scroll_info.scroll[lcd_scroll_info.lines-1];
100 }
101 lcd_scroll_info.lines--;
102
103 /* A line can only appear once, so we're done. */
104 return ;
105 }
106 else
107 {
108 i++;
109 }
110 }
111}
112
113/* Stop all scrolling lines in the specified viewport */
114void lcd_scroll_stop(struct viewport* vp)
115{
116 lcd_scroll_stop_line(vp, -1);
117}
118
85void lcd_scroll_speed(int speed) 119void lcd_scroll_speed(int speed)
86{ 120{
87 lcd_scroll_info.ticks = scroll_tick_table[speed]; 121 lcd_scroll_info.ticks = scroll_tick_table[speed];
@@ -122,6 +156,40 @@ void lcd_remote_stop_scroll(void)
122 lcd_remote_scroll_info.lines = 0; 156 lcd_remote_scroll_info.lines = 0;
123} 157}
124 158
159/* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
160void lcd_remote_scroll_stop_line(struct viewport* current_vp, int y)
161{
162 int i = 0;
163
164 while (i < lcd_remote_scroll_info.lines)
165 {
166 if ((lcd_remote_scroll_info.scroll[i].vp == current_vp) &&
167 ((y < 0) || (lcd_remote_scroll_info.scroll[i].y == y)))
168 {
169 /* If i is not the last active line in the array, then move
170 the last item to position i */
171 if ((i + 1) != lcd_remote_scroll_info.lines)
172 {
173 lcd_remote_scroll_info.scroll[i] = lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines-1];
174 }
175 lcd_remote_scroll_info.lines--;
176
177 /* A line can only appear once, so we're done. */
178 return ;
179 }
180 else
181 {
182 i++;
183 }
184 }
185}
186
187/* Stop all scrolling lines in the specified viewport */
188void lcd_remote_scroll_stop(struct viewport* vp)
189{
190 lcd_remote_scroll_stop_line(vp, -1);
191}
192
125void lcd_remote_scroll_speed(int speed) 193void lcd_remote_scroll_speed(int speed)
126{ 194{
127 lcd_remote_scroll_info.ticks = scroll_tick_table[speed]; 195 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;
11volatile bool lcd_poweroff = false; 11volatile bool lcd_poweroff = false;
12static unsigned lcd_yuv_options = 0; 12static unsigned lcd_yuv_options = 0;
13/* 13/*
14** These are imported from lcd-16bit.c 14** This is imported from lcd-16bit.c
15*/ 15*/
16extern unsigned fg_pattern; 16extern struct viewport* current_vp;
17extern unsigned bg_pattern;
18 17
19/* Copies a rectangle from one framebuffer to another. Can be used in 18/* Copies a rectangle from one framebuffer to another. Can be used in
20 single transfer mode with width = num pixels, and height = 1 which 19 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,
245 [dstp]"r"(LCD_WIDTH - width), 244 [dstp]"r"(LCD_WIDTH - width),
246 [transcolor]"r"(TRANSPARENT_COLOR), 245 [transcolor]"r"(TRANSPARENT_COLOR),
247 [fgcolor]"r"(REPLACEWITHFG_COLOR), 246 [fgcolor]"r"(REPLACEWITHFG_COLOR),
248 [fgpat]"r"(fg_pattern) 247 [fgpat]"r"(current_vp->fg_pattern)
249 ); 248 );
250} 249}
251 250