Index: apps/screen_access.c =================================================================== --- apps/screen_access.c (revision 15983) +++ apps/screen_access.c (working copy) @@ -50,7 +50,10 @@ #elif defined(HAVE_REMOTE_LCD) .has_disk_led=true, #endif + .set_viewport=&lcd_set_viewport, .setmargins=&lcd_setmargins, + .getwidth=&lcd_getwidth, + .getheight=&lcd_getheight, .getymargin=&lcd_getymargin, .getxmargin=&lcd_getxmargin, .getstringsize=&lcd_getstringsize, @@ -84,6 +87,7 @@ #endif #endif /* LCD_DEPTH > 1 */ .update_rect=&lcd_update_rect, + .update_viewport_rect=&lcd_update_viewport_rect, .fillrect=&lcd_fillrect, .drawrect=&lcd_drawrect, .drawpixel=&lcd_drawpixel, @@ -114,7 +118,9 @@ .scroll_delay=&lcd_scroll_delay, .stop_scroll=&lcd_stop_scroll, .clear_display=&lcd_clear_display, + .clear_viewport=&lcd_clear_viewport, .update=&lcd_update, + .update_viewport=&lcd_update_viewport, .backlight_on=&backlight_on, .backlight_off=&backlight_off, .is_backlight_on=&is_backlight_on, @@ -132,7 +138,10 @@ .is_color=false,/* No color remotes yet */ .pixel_format=LCD_REMOTE_PIXELFORMAT, .has_disk_led=false, + .set_viewport=&lcd_remote_set_viewport, .setmargins=&lcd_remote_setmargins, + .getwidth=&lcd_remote_getwidth, + .getheight=&lcd_remote_getheight, .getymargin=&lcd_remote_getymargin, .getxmargin=&lcd_remote_getxmargin, .getstringsize=&lcd_remote_getstringsize, @@ -159,6 +168,7 @@ .set_foreground=&lcd_remote_set_foreground, #endif /* LCD_REMOTE_DEPTH > 1 */ .update_rect=&lcd_remote_update_rect, + .update_viewport_rect=&lcd_remote_update_viewport_rect, .fillrect=&lcd_remote_fillrect, .drawrect=&lcd_remote_drawrect, .drawpixel=&lcd_remote_drawpixel, @@ -187,7 +197,9 @@ .scroll_delay=&lcd_remote_scroll_delay, .stop_scroll=&lcd_remote_stop_scroll, .clear_display=&lcd_remote_clear_display, + .clear_viewport=&lcd_remote_clear_viewport, .update=&lcd_remote_update, + .update_viewport=&lcd_remote_update_viewport, .backlight_on=&remote_backlight_on, .backlight_off=&remote_backlight_off, .is_backlight_on=&is_remote_backlight_on, Index: apps/screen_access.h =================================================================== --- apps/screen_access.h (revision 15983) +++ apps/screen_access.h (working copy) @@ -71,7 +71,10 @@ #ifdef HAS_BUTTONBAR bool has_buttonbar; #endif + void (*set_viewport)(struct viewport* vp); void (*setmargins)(int x, int y); + int (*getwidth)(void); + int (*getheight)(void); int (*getxmargin)(void); int (*getymargin)(void); int (*getstringsize)(const unsigned char *str, int *w, int *h); @@ -113,6 +116,7 @@ void (*set_selector_text)(unsigned selector_text); #endif void (*update_rect)(int x, int y, int width, int height); + void (*update_viewport_rect)(int x, int y, int width, int height); void (*fillrect)(int x, int y, int width, int height); void (*drawrect)(int x, int y, int width, int height); void (*drawpixel)(int x, int y); @@ -139,7 +143,9 @@ void (*scroll_delay)(int ms); void (*stop_scroll)(void); void (*clear_display)(void); + void (*clear_viewport)(void); void (*update)(void); + void (*update_viewport)(void); void (*backlight_on)(void); void (*backlight_off)(void); bool (*is_backlight_on)(void); Index: apps/recorder/peakmeter.c =================================================================== --- apps/recorder/peakmeter.c (revision 15983) +++ apps/recorder/peakmeter.c (working copy) @@ -919,14 +919,14 @@ void peak_meter_screen(struct screen *display, int x, int y, int height) { peak_meter_draw(display, &scales[display->screen_type], x, y, - display->width - x, height); + display->getwidth() - x, height); } /** * Draws a peak meter in the specified size at the specified position. * @param int x - The x coordinate. - * Make sure that 0 <= x and x + width < display->width + * Make sure that 0 <= x and x + width < display->getwidth() * @param int y - The y coordinate. - * Make sure that 0 <= y and y + height < display->height + * Make sure that 0 <= y and y + height < display->getheight() * @param int width - The width of the peak meter. Note that for display * of clips a 3 pixel wide area is used -> * width > 3 @@ -1105,7 +1105,7 @@ start_trigx = x+peak_meter_scale_value(trig_strt_threshold,meterwidth); display->vline(start_trigx, ycenter - 2, ycenter); start_trigx ++; - if (start_trigx < display->width ) display->drawpixel(start_trigx, ycenter - 1); + if (start_trigx < display->getwidth() ) display->drawpixel(start_trigx, ycenter - 1); stop_trigx = x + peak_meter_scale_value(trig_stp_threshold,meterwidth); display->vline(stop_trigx, ycenter - 2, ycenter); Index: apps/settings.c =================================================================== --- apps/settings.c (revision 15983) +++ apps/settings.c (working copy) @@ -808,7 +808,7 @@ global_settings.wps_file[0] != 0xff ) { snprintf(buf, sizeof buf, WPS_DIR "/%s.wps", global_settings.wps_file); - wps_data_load(gui_wps[0].data, buf, true); + wps_data_load(gui_wps[0].data, &screens[0], buf, true); } else { @@ -845,7 +845,7 @@ if ( global_settings.rwps_file[0]) { snprintf(buf, sizeof buf, WPS_DIR "/%s.rwps", global_settings.rwps_file); - wps_data_load(gui_wps[1].data, buf, true); + wps_data_load(gui_wps[1].data, &screens[1], buf, true); } else { Index: apps/plugins/test_viewports.c =================================================================== --- apps/plugins/test_viewports.c (revision 0) +++ apps/plugins/test_viewports.c (revision 0) @@ -0,0 +1,230 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: helloworld.c 12807 2007-03-16 21:56:08Z amiconn $ + * + * Copyright (C) 2007 Dave Chapman + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "plugin.h" + +PLUGIN_HEADER + +static struct plugin_api* rb; + +static struct viewport vp0 = +{ + .x = 0, + .y = 0, + .width = LCD_WIDTH, + .height = 20, + .font = FONT_UI, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, +#if LCD_DEPTH > 1 + .fg_pattern = LCD_DEFAULT_FG, + .bg_pattern = LCD_RGBPACK(255,255,0), +#ifdef HAVE_LCD_COLOR + .lss_pattern = LCD_DEFAULT_BG, + .lse_pattern = LCD_DEFAULT_BG, + .lst_pattern = LCD_DEFAULT_BG, +#endif +#endif +}; + +static struct viewport vp1 = +{ + .x = LCD_WIDTH / 10, + .y = 20, + .width = LCD_WIDTH / 3, + .height = LCD_HEIGHT / 2, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, +#if LCD_DEPTH > 1 + .fg_pattern = LCD_DEFAULT_FG, + .bg_pattern = LCD_DEFAULT_BG, +#ifdef HAVE_LCD_COLOR + .lss_pattern = LCD_DEFAULT_BG, + .lse_pattern = LCD_DEFAULT_BG, + .lst_pattern = LCD_DEFAULT_BG, +#endif +#endif +}; + +static struct viewport vp2 = +{ + .x = LCD_WIDTH / 2, + .y = 40, + .width = LCD_WIDTH / 3, + .height = (LCD_HEIGHT / 2), + .font = FONT_UI, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, +#if LCD_DEPTH > 1 + .fg_pattern = LCD_RGBPACK(0,0,255), + .bg_pattern = LCD_RGBPACK(0,255,0), +#ifdef HAVE_LCD_COLOR + .lss_pattern = LCD_DEFAULT_BG, + .lse_pattern = LCD_DEFAULT_BG, + .lst_pattern = LCD_DEFAULT_BG, +#endif +#endif +}; + + +static struct viewport vp3 = +{ + .x = LCD_WIDTH / 4, + .y = (5 * LCD_HEIGHT) / 8, + .width = LCD_WIDTH / 2, + .height = (LCD_HEIGHT / 4), + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, +#if LCD_DEPTH > 1 + .fg_pattern = LCD_BLACK, + .bg_pattern = LCD_RGBPACK(255,0,0), +#ifdef HAVE_LCD_COLOR + .lss_pattern = LCD_DEFAULT_BG, + .lse_pattern = LCD_DEFAULT_BG, + .lst_pattern = LCD_DEFAULT_BG, +#endif +#endif +}; + + +#ifdef HAVE_REMOTE_LCD +static struct viewport rvp0 = +{ + .x = 0, + .y = 10, + .width = LCD_REMOTE_WIDTH / 3, + .height = LCD_REMOTE_HEIGHT - 10, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, +#if LCD_REMOTE_DEPTH > 1 + .fg_pattern = LCD_REMOTE_WHITE, + .bg_pattern = LCD_REMOTE_DARKGRAY +#endif +}; + +static struct viewport rvp1 = +{ + .x = LCD_REMOTE_WIDTH / 2, + .y = 0, + .width = LCD_REMOTE_WIDTH / 3, + .height = LCD_REMOTE_HEIGHT - 10, + .font = FONT_UI, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, +#if LCD_REMOTE_DEPTH > 1 + .fg_pattern = LCD_REMOTE_BLACK, + .bg_pattern = LCD_REMOTE_WHITE +#endif +}; + +#endif + + +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + (void)parameter; + char buf[80]; + int i,y; + + rb = api; + + rb->lcd_set_viewport(&vp0); + rb->lcd_clear_viewport(); + rb->lcd_puts_scroll(0,0,"Viewport testing plugin - this is a scrolling title"); + + rb->lcd_set_viewport(&vp1); + rb->lcd_clear_viewport(); + + for (i = 0 ; i < 3; i++) + { + rb->snprintf(buf,sizeof(buf),"Left text, scrolling_line %d",i); + rb->lcd_puts_scroll(0,i,buf); + } + + rb->lcd_set_viewport(&vp2); + rb->lcd_clear_viewport(); + for (i = 1 ; i < 3; i++) + { + rb->snprintf(buf,sizeof(buf),"Right text, scrolling line %d",i); + rb->lcd_puts_scroll(1,i,buf); + } + + y = -10; + for (i = -10; i < vp2.width + 10; i += 5) + { + rb->lcd_drawline(i, y, i, vp2.height - y); + } + + rb->lcd_set_viewport(&vp3); + rb->lcd_clear_viewport(); + for (i = 1 ; i < 2; i++) + { + rb->snprintf(buf,sizeof(buf),"Bottom text, a scrolling line %d",i); + rb->lcd_puts_scroll(2,i,buf); + } + rb->lcd_puts_scroll(4,i,"Short line"); + rb->lcd_update(); + + +#ifdef HAVE_REMOTE_LCD + rb->lcd_remote_set_viewport(&rvp0); + rb->lcd_remote_clear_viewport(); + + for (i = 0 ; i < 5; i++) + { + rb->snprintf(buf,sizeof(buf),"Left text, scrolling_line %d",i); + rb->lcd_remote_puts_scroll(0,i,buf); + } + + rb->lcd_remote_set_viewport(&rvp1); + rb->lcd_remote_clear_viewport(); + for (i = 1 ; i < 3; i++) + { + rb->snprintf(buf,sizeof(buf),"Right text, scrolling line %d",i); + rb->lcd_remote_puts_scroll(1,i,buf); + } + + y = -10; + for (i = -10; i < rvp1.width + 10; i += 5) + { + rb->lcd_remote_drawline(i, y, i, rvp1.height - y); + } + + rb->lcd_remote_update(); +#endif + + rb->button_get(true); + + /* Restore the default viewport */ + rb->lcd_set_viewport(NULL); +#ifdef HAVE_REMOTE_LCD + rb->lcd_remote_set_viewport(NULL); +#endif + + return PLUGIN_OK; +} Index: apps/plugins/CATEGORIES =================================================================== --- apps/plugins/CATEGORIES (revision 15983) +++ apps/plugins/CATEGORIES (working copy) @@ -81,6 +81,7 @@ test_fps,apps test_sampr,apps test_scanrate,apps +test_viewports,apps text_editor,apps vbrfix,viewers video,viewers Index: apps/plugins/SOURCES =================================================================== --- apps/plugins/SOURCES (revision 15983) +++ apps/plugins/SOURCES (working copy) @@ -1,4 +1,5 @@ /* plugins common to all models */ +test_viewports.c battery_bench.c chessclock.c credits.c Index: apps/gui/gwps-common.c =================================================================== --- apps/gui/gwps-common.c (revision 15983) +++ apps/gui/gwps-common.c (working copy) @@ -282,6 +282,7 @@ bool gui_wps_display(void) { int i; + if (!wps_state.id3 && !(audio_status() & AUDIO_STATUS_PLAY)) { global_status.resume_index = -1; @@ -295,6 +296,12 @@ { FOR_NB_SCREENS(i) { + /* Update the ymargin in the first (default) viewport - in case the user + has modified the statusbar setting */ +#ifdef HAVE_LCD_BITMAP + gui_wps[i].data->viewports[0].vp.ymargin = gui_wps[i].display->getymargin(); +#endif + gui_wps[i].display->clear_display(); if (!gui_wps[i].data->wps_loaded) { if ( !gui_wps[i].data->num_tokens ) { @@ -306,6 +313,7 @@ unload_wps_backdrop(); #endif wps_data_load(gui_wps[i].data, + gui_wps[i].display, "%s%?it<%?in<%in. |>%it|%fn>\n" "%s%?ia<%ia|%?d2<%d2|(root)>>\n" "%s%?id<%id|%?d1<%d1|(root)>> %?iy<(%iy)|>\n" @@ -316,6 +324,7 @@ "%pm\n", false); #else wps_data_load(gui_wps[i].data, + gui_wps[i].display, "%s%pp/%pe: %?it<%it|%fn> - %?ia<%ia|%d2> - %?id<%id|%d1>\n" "%pc%?ps<*|/>%pt\n", false); #endif @@ -328,6 +337,7 @@ unload_remote_wps_backdrop(); #endif wps_data_load(gui_wps[i].data, + gui_wps[i].display, "%s%?ia<%ia|%?d2<%d2|(root)>>\n" "%s%?it<%?in<%in. |>%it|%fn>\n" "%al%pc/%pt%ar[%pp:%pe]\n" @@ -459,7 +469,7 @@ sb_y = data->progress_top; if (!data->progress_end) - data->progress_end=display->width; + data->progress_end=display->getwidth(); if (gwps->data->progressbar.have_bitmap_pb) gui_bitmap_scrollbar_draw(display, data->progressbar.bm, @@ -1449,7 +1459,7 @@ The return value indicates whether the line needs to be updated. */ static bool get_line(struct gui_wps *gwps, - int line, int subline, + int v, int line, int subline, struct align_pos *align, char *linebuf, int linebuf_size) @@ -1477,8 +1487,8 @@ #endif /* Process all tokens of the desired subline */ - last_token_idx = wps_last_token_index(data, line, subline); - for (i = wps_first_token_index(data, line, subline); + last_token_idx = wps_last_token_index(data, v, line, subline); + for (i = wps_first_token_index(data, v, line, subline); i <= last_token_idx; i++) { switch(data->tokens[i].type) @@ -1577,16 +1587,16 @@ return update; } -static void get_subline_timeout(struct gui_wps *gwps, int line, int subline) +static void get_subline_timeout(struct gui_wps *gwps, int v, int line, int subline) { struct wps_data *data = gwps->data; int i; - int subline_idx = wps_subline_index(data, line, subline); - int last_token_idx = wps_last_token_index(data, line, subline); + int subline_idx = wps_subline_index(data, v, line, subline); + int last_token_idx = wps_last_token_index(data, v, line, subline); data->sublines[subline_idx].time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER; - for (i = wps_first_token_index(data, line, subline); + for (i = wps_first_token_index(data, v, line, subline); i <= last_token_idx; i++) { switch(data->tokens[i].type) @@ -1614,7 +1624,7 @@ /* Calculates which subline should be displayed for the specified line Returns true iff the subline must be refreshed */ -static bool update_curr_subline(struct gui_wps *gwps, int line) +static bool update_curr_subline(struct gui_wps *gwps, int v, int line) { struct wps_data *data = gwps->data; @@ -1623,13 +1633,13 @@ bool new_subline_refresh; bool only_one_subline; - num_sublines = data->lines[line].num_sublines; - reset_subline = (data->lines[line].curr_subline == SUBLINE_RESET); + num_sublines = data->viewports[v].lines[line].num_sublines; + reset_subline = (data->viewports[v].lines[line].curr_subline == SUBLINE_RESET); new_subline_refresh = false; only_one_subline = false; /* if time to advance to next sub-line */ - if (TIME_AFTER(current_tick, data->lines[line].subline_expire_time - 1) || + if (TIME_AFTER(current_tick, data->viewports[v].lines[line].subline_expire_time - 1) || reset_subline) { /* search all sublines until the next subline with time > 0 @@ -1637,46 +1647,46 @@ if (reset_subline) search_start = 0; else - search_start = data->lines[line].curr_subline; + search_start = data->viewports[v].lines[line].curr_subline; for (search = 0; search < num_sublines; search++) { - data->lines[line].curr_subline++; + data->viewports[v].lines[line].curr_subline++; /* wrap around if beyond last defined subline or WPS_MAX_SUBLINES */ - if (data->lines[line].curr_subline == num_sublines) + if (data->viewports[v].lines[line].curr_subline == num_sublines) { - if (data->lines[line].curr_subline == 1) + if (data->viewports[v].lines[line].curr_subline == 1) only_one_subline = true; - data->lines[line].curr_subline = 0; + data->viewports[v].lines[line].curr_subline = 0; } /* if back where we started after search or only one subline is defined on the line */ if (((search > 0) && - (data->lines[line].curr_subline == search_start)) || + (data->viewports[v].lines[line].curr_subline == search_start)) || only_one_subline) { /* no other subline with a time > 0 exists */ - data->lines[line].subline_expire_time = (reset_subline ? + data->viewports[v].lines[line].subline_expire_time = (reset_subline ? current_tick : - data->lines[line].subline_expire_time) + 100 * HZ; + data->viewports[v].lines[line].subline_expire_time) + 100 * HZ; break; } else { /* get initial time multiplier for this subline */ - get_subline_timeout(gwps, line, data->lines[line].curr_subline); + get_subline_timeout(gwps, v, line, data->viewports[v].lines[line].curr_subline); - int subline_idx = wps_subline_index(data, line, - data->lines[line].curr_subline); + int subline_idx = wps_subline_index(data, v, line, + data->viewports[v].lines[line].curr_subline); /* only use this subline if subline time > 0 */ if (data->sublines[subline_idx].time_mult > 0) { new_subline_refresh = true; - data->lines[line].subline_expire_time = (reset_subline ? - current_tick : data->lines[line].subline_expire_time) + + data->viewports[v].lines[line].subline_expire_time = (reset_subline ? + current_tick : data->viewports[v].lines[line].subline_expire_time) + BASE_SUBLINE_TIME*data->sublines[subline_idx].time_mult; break; } @@ -1697,7 +1707,6 @@ int line, bool scroll) { - int left_width = 0, left_xpos; int center_width = 0, center_xpos; int right_width = 0, right_xpos; @@ -1724,10 +1733,10 @@ } left_xpos = display->getxmargin(); - right_xpos = (display->width - right_width); - center_xpos = (display->width + left_xpos - center_width) / 2; + right_xpos = (display->getwidth() - right_width); + center_xpos = (display->getwidth() + left_xpos - center_width) / 2; - scroll_width = display->width - left_xpos; + scroll_width = display->getwidth() - left_xpos; /* Checks for overlapping strings. If needed the overlapping strings will be merged, separated by a @@ -1767,7 +1776,7 @@ format_align->right = format_align->center; /* calculate the new width and position of the merged string */ right_width = center_width + space_width + right_width; - right_xpos = (display->width - right_width); + right_xpos = (display->getwidth() - right_width); /* there is no centered string anymore */ center_width = 0; } @@ -1778,7 +1787,7 @@ format_align->right = format_align->center; /* calculate the new width and position of the string */ right_width = center_width; - right_xpos = (display->width - right_width); + right_xpos = (display->getwidth() - right_width); /* there is no centered string anymore */ center_width = 0; } @@ -1823,7 +1832,7 @@ #ifdef HAVE_LCD_BITMAP /* clear the line first */ display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); - display->fillrect(left_xpos, ypos, display->width, string_height); + display->fillrect(left_xpos, ypos, display->getwidth(), string_height); display->set_drawmode(DRMODE_SOLID); #endif @@ -1862,7 +1871,7 @@ if(!gwps || !data || !state || !display) return false; - int line, i, subline_idx; + int v, line, i, subline_idx; unsigned char flags; char linebuf[MAX_PATH]; @@ -1895,9 +1904,14 @@ /* reset to first subline if refresh all flag is set */ if (refresh_mode == WPS_REFRESH_ALL) { - for (i = 0; i < data->num_lines; i++) + display->clear_display(); + + for (v = 0; v < data->num_viewports; v++) { - data->lines[i].curr_subline = SUBLINE_RESET; + for (i = 0; i < data->viewports[v].num_lines; i++) + { + data->viewports[v].lines[i].curr_subline = SUBLINE_RESET; + } } } @@ -1917,83 +1931,91 @@ state->ff_rewind_count = ffwd_offset; - for (line = 0; line < data->num_lines; line++) + for (v = 0; v < data->num_viewports; v++) { - memset(linebuf, 0, sizeof(linebuf)); - update_line = false; + display->set_viewport(&data->viewports[v].vp); - /* get current subline for the line */ - new_subline_refresh = update_curr_subline(gwps, line); + for (line = 0; line < data->viewports[v].num_lines; line++) + { + memset(linebuf, 0, sizeof(linebuf)); + update_line = false; - subline_idx = wps_subline_index(data, line, - data->lines[line].curr_subline); - flags = data->sublines[subline_idx].line_type; + /* get current subline for the line */ + new_subline_refresh = update_curr_subline(gwps, v, line); - if (refresh_mode == WPS_REFRESH_ALL || (flags & refresh_mode) - || new_subline_refresh) - { - /* get_line tells us if we need to update the line */ - update_line = get_line(gwps, line, data->lines[line].curr_subline, - &align, linebuf, sizeof(linebuf)); - } + subline_idx = wps_subline_index(data, v, line, + data->viewports[v].lines[line].curr_subline); + flags = data->sublines[subline_idx].line_type; + if (refresh_mode == WPS_REFRESH_ALL || (flags & refresh_mode) + || new_subline_refresh) + { + /* get_line tells us if we need to update the line */ + update_line = get_line(gwps, v, line, data->viewports[v].lines[line].curr_subline, + &align, linebuf, sizeof(linebuf)); + } + #ifdef HAVE_LCD_BITMAP - /* progressbar */ - if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) - { - /* the progressbar should be alone on its line */ - update_line = false; - draw_progressbar(gwps, line); - } + /* progressbar */ + if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) + { + /* the progressbar should be alone on its line */ + update_line = false; + draw_progressbar(gwps, line); + } - /* peakmeter */ - if (flags & refresh_mode & WPS_REFRESH_PEAK_METER) - { - /* the peakmeter should be alone on its line */ - update_line = false; + /* peakmeter */ + if (flags & refresh_mode & WPS_REFRESH_PEAK_METER) + { + /* the peakmeter should be alone on its line */ + update_line = false; - int h = font_get(FONT_UI)->height; - int peak_meter_y = display->getymargin() + line * h; + int h = font_get(FONT_UI)->height; + int peak_meter_y = display->getymargin() + line * h; - /* The user might decide to have the peak meter in the last - line so that it is only displayed if no status bar is - visible. If so we neither want do draw nor enable the - peak meter. */ - if (peak_meter_y + h <= display->height) { - /* found a line with a peak meter -> remember that we must - enable it later */ - enable_pm = true; - peak_meter_screen(gwps->display, 0, peak_meter_y, - MIN(h, display->height - peak_meter_y)); + /* The user might decide to have the peak meter in the last + line so that it is only displayed if no status bar is + visible. If so we neither want do draw nor enable the + peak meter. */ + if (peak_meter_y + h <= display->getheight()) { + /* found a line with a peak meter -> remember that we must + enable it later */ + enable_pm = true; + peak_meter_screen(gwps->display, 0, peak_meter_y, + MIN(h, display->getheight() - peak_meter_y)); + } } - } #else /* HAVE_LCD_CHARCELL */ - /* progressbar */ - if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) - { - if (data->full_line_progressbar) - draw_player_fullbar(gwps, linebuf, sizeof(linebuf)); - else - draw_player_progress(gwps); - } + /* progressbar */ + if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) + { + if (data->full_line_progressbar) + draw_player_fullbar(gwps, linebuf, sizeof(linebuf)); + else + draw_player_progress(gwps); + } #endif - if (update_line) - { - if (flags & WPS_REFRESH_SCROLL) + if (update_line) { - /* if the line is a scrolling one we don't want to update - too often, so that it has the time to scroll */ - if ((refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh) - write_line(display, &align, line, true); + if (flags & WPS_REFRESH_SCROLL) + { + /* if the line is a scrolling one we don't want to update + too often, so that it has the time to scroll */ + if ((refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh) + write_line(display, &align, line, true); + } + else + write_line(display, &align, line, false); } - else - write_line(display, &align, line, false); } } + /* Restore the default viewport for the images */ + display->set_viewport(NULL); + #ifdef HAVE_LCD_BITMAP data->peak_meter_enabled = enable_pm; wps_display_images(gwps); Index: apps/gui/wps_debug.c =================================================================== --- apps/gui/wps_debug.c (revision 15983) +++ apps/gui/wps_debug.c (working copy) @@ -492,40 +492,51 @@ static void print_line_info(struct wps_data *data) { - int i, j; + int i, j, v; struct wps_line *line; struct wps_subline *subline; if (wps_verbose_level > 0) { - DEBUGF("Number of lines : %d\n", data->num_lines); - DEBUGF("Number of sublines: %d\n", data->num_sublines); - DEBUGF("Number of tokens : %d\n", data->num_tokens); + DEBUGF("Number of viewports : %d\n", data->num_viewports); + for (v = 0; v < data->num_viewports; v++) + { + DEBUGF("vp %d: Number of lines: %d\n", v, data->viewports[v].num_lines); + } + DEBUGF("Number of sublines : %d\n", data->num_sublines); + DEBUGF("Number of tokens : %d\n", data->num_tokens); DEBUGF("\n"); } if (wps_verbose_level > 1) { - for (i = 0, line = data->lines; i < data->num_lines; i++,line++) + for (v = 0; v < data->num_viewports; v++) { - DEBUGF("Line %2d (num_sublines=%d, first_subline=%d)\n", - i, line->num_sublines, line->first_subline_idx); - - for (j = 0, subline = data->sublines + line->first_subline_idx; - j < line->num_sublines; j++, subline++) + DEBUGF("Viewport %d - +%d+%d (%dx%d)\n",v,data->viewports[v].vp.x, + data->viewports[v].vp.y, + data->viewports[v].vp.width, + data->viewports[v].vp.height); + for (i = 0, line = data->viewports[v].lines; i < data->viewports[v].num_lines; i++,line++) { - DEBUGF(" Subline %d: first_token=%3d, last_token=%3d", - j, subline->first_token_idx, - wps_last_token_index(data, i, j)); + DEBUGF("Line %2d (num_sublines=%d, first_subline=%d)\n", + i, line->num_sublines, line->first_subline_idx); - if (subline->line_type & WPS_REFRESH_SCROLL) - DEBUGF(", scrolled"); - else if (subline->line_type & WPS_REFRESH_PLAYER_PROGRESS) - DEBUGF(", progressbar"); - else if (subline->line_type & WPS_REFRESH_PEAK_METER) - DEBUGF(", peakmeter"); + for (j = 0, subline = data->sublines + line->first_subline_idx; + j < line->num_sublines; j++, subline++) + { + DEBUGF(" Subline %d: first_token=%3d, last_token=%3d", + j, subline->first_token_idx, + wps_last_token_index(data, v, i, j)); - DEBUGF("\n"); + if (subline->line_type & WPS_REFRESH_SCROLL) + DEBUGF(", scrolled"); + else if (subline->line_type & WPS_REFRESH_PLAYER_PROGRESS) + DEBUGF(", progressbar"); + else if (subline->line_type & WPS_REFRESH_PEAK_METER) + DEBUGF(", peakmeter"); + + DEBUGF("\n"); + } } } Index: apps/gui/gwps.h =================================================================== --- apps/gui/gwps.h (revision 15983) +++ apps/gui/gwps.h (working copy) @@ -86,6 +86,7 @@ #define IMG_BUFSIZE ((LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \ + (2*LCD_HEIGHT*LCD_WIDTH/8)) +#define WPS_MAX_VIEWPORTS 16 #define WPS_MAX_LINES (LCD_HEIGHT/5+1) #define WPS_MAX_SUBLINES (WPS_MAX_LINES*3) #define WPS_MAX_TOKENS 1024 @@ -95,6 +96,7 @@ #else +#define WPS_MAX_VIEWPORTS 2 #define WPS_MAX_LINES 2 #define WPS_MAX_SUBLINES 12 #define WPS_MAX_TOKENS 64 @@ -315,7 +317,15 @@ long subline_expire_time; }; +struct wps_viewport { + struct viewport vp; /* The LCD viewport struct */ + /* Number of lines in this viewport. During WPS parsing, this is + the index of the line being parsed. */ + int num_lines; + struct wps_line lines[WPS_MAX_LINES]; +}; + /* wps_data this struct holds all necessary data which describes the viewable content of a wps */ @@ -360,10 +370,9 @@ bool remote_wps; #endif - /* Number of lines in the WPS. During WPS parsing, this is - the index of the line being parsed. */ - int num_lines; - struct wps_line lines[WPS_MAX_LINES]; + /* Number of viewports in the WPS */ + int num_viewports; + struct wps_viewport viewports[WPS_MAX_VIEWPORTS]; /* Total number of sublines in the WPS. During WPS parsing, this is the index of the subline where the parsed tokens are added to. */ @@ -388,26 +397,30 @@ /* to setup up the wps-data from a format-buffer (isfile = false) from a (wps-)file (isfile = true)*/ bool wps_data_load(struct wps_data *wps_data, + struct screen *display, const char *buf, bool isfile); /* Returns the index of the subline in the subline array + v - 0-based viewport number line - 0-based line number subline - 0-based subline number within the line */ -int wps_subline_index(struct wps_data *wps_data, int line, int subline); +int wps_subline_index(struct wps_data *wps_data, int v, int line, int subline); /* Returns the index of the first subline's token in the token array + v - 0-based viewport number line - 0-based line number subline - 0-based subline number within the line */ -int wps_first_token_index(struct wps_data *data, int line, int subline); +int wps_first_token_index(struct wps_data *data, int v, int line, int subline); /* Returns the index of the last subline's token in the token array. + v - 0-based viewport number line - 0-based line number subline - 0-based subline number within the line */ -int wps_last_token_index(struct wps_data *data, int line, int subline); +int wps_last_token_index(struct wps_data *data, int v, int line, int subline); /* wps_data end */ Index: apps/gui/wps_parser.c =================================================================== --- apps/gui/wps_parser.c (revision 15983) +++ apps/gui/wps_parser.c (working copy) @@ -116,6 +116,8 @@ struct wps_token *token, struct wps_data *wps_data); static int parse_dir_level(const char *wps_bufptr, struct wps_token *token, struct wps_data *wps_data); +static int parse_viewport(const char *wps_bufptr, + struct wps_token *token, struct wps_data *wps_data); #ifdef HAVE_LCD_BITMAP static int parse_leftmargin(const char *wps_bufptr, @@ -131,7 +133,6 @@ static int parse_image_load(const char *wps_bufptr, struct wps_token *token, struct wps_data *wps_data); #endif /*HAVE_LCD_BITMAP */ - #ifdef HAVE_ALBUMART static int parse_albumart_load(const char *wps_bufptr, struct wps_token *token, struct wps_data *wps_data); @@ -311,6 +312,9 @@ { WPS_TOKEN_ALBUMART_DISPLAY, "C", WPS_REFRESH_STATIC, parse_albumart_conditional }, #endif + + { WPS_NO_TOKEN, "V", 0, parse_viewport }, + #if (LCD_DEPTH > 1) || (defined(HAVE_LCD_REMOTE) && (LCD_REMOTE_DEPTH > 1)) { WPS_TOKEN_IMAGE_BACKDROP, "X", 0, parse_image_special }, #endif @@ -334,9 +338,11 @@ /* Starts a new subline in the current line during parsing */ static void wps_start_new_subline(struct wps_data *data) { + struct wps_viewport* vp = &data->viewports[data->num_viewports]; + data->num_sublines++; data->sublines[data->num_sublines].first_token_idx = data->num_tokens; - data->lines[data->num_lines].num_sublines++; + vp->lines[vp->num_lines].num_sublines++; } #ifdef HAVE_LCD_BITMAP @@ -506,6 +512,105 @@ return skip_end_of_line(wps_bufptr); } +static int parse_viewport(const char *wps_bufptr, + struct wps_token *token, + struct wps_data *wps_data) +{ + const char *ptr = wps_bufptr; + const char *pos = NULL; + const char *newline; + struct viewport* vp; + char hexbuf[7]; + + (void)token; /* Kill warnings */ + + /* format: %V|x|y|width|height|fg_pattern|bg_pattern| */ + + if (wps_data->num_viewports >= WPS_MAX_VIEWPORTS) + return WPS_ERROR_INVALID_PARAM; + + wps_data->num_viewports++; + vp = &wps_data->viewports[wps_data->num_viewports].vp; + + /* Set the defaults for fields not user-specified */ + vp->font = FONT_UI; + vp->drawmode = DRMODE_SOLID; + vp->xmargin = 0; + vp->ymargin = 0; + + ptr = strchr(ptr, '|') + 1; + pos = strchr(ptr, '|'); + newline = strchr(ptr, '\n'); + + if (!pos || pos > newline) + return 0; + + /* get x-position */ + pos = strchr(ptr, '|'); + if (pos && pos < newline) + vp->x = atoi(ptr); + else + return WPS_ERROR_INVALID_PARAM; + + /* get y-position */ + ptr = pos + 1; + pos = strchr(ptr, '|'); + if (pos && pos < newline) + vp->y = atoi(ptr); + else + return WPS_ERROR_INVALID_PARAM; + + /* get width */ + ptr = pos + 1; + pos = strchr(ptr, '|'); + if (pos && pos < newline) + vp->width = atoi(ptr); + else + return WPS_ERROR_INVALID_PARAM; + + /* get height */ + ptr = pos + 1; + pos = strchr(ptr, '|'); + if (pos && pos < newline) + vp->height = atoi(ptr); + else + return WPS_ERROR_INVALID_PARAM; + + /* get fg_pattern */ + ptr = pos + 1; + pos = strchr(ptr, '|'); + if (pos && pos < newline) + { snprintf(hexbuf,7,"%s",ptr); + vp->fg_pattern = hex_to_rgb(hexbuf); + } + else + return WPS_ERROR_INVALID_PARAM; + + /* get bg_pattern */ + ptr = pos + 1; + pos = strchr(ptr, '|'); + if (pos && pos < newline) + { snprintf(hexbuf,7,"%s",ptr); + vp->bg_pattern = hex_to_rgb(hexbuf); + } + else + return WPS_ERROR_INVALID_PARAM; + + wps_data->viewports[wps_data->num_viewports].num_lines = 0; + + if (wps_data->num_sublines < WPS_MAX_SUBLINES) + { + wps_data->viewports[wps_data->num_viewports].lines[0].first_subline_idx = + wps_data->num_sublines; + + wps_data->sublines[wps_data->num_sublines].first_token_idx = + wps_data->num_tokens; + } + + /* Skip the rest of the line */ + return skip_end_of_line(wps_bufptr); +} + static int parse_image_special(const char *wps_bufptr, struct wps_token *token, struct wps_data *wps_data) @@ -975,7 +1080,8 @@ level = -1; while(*wps_bufptr && !fail && data->num_tokens < WPS_MAX_TOKENS - 1 - && data->num_lines < WPS_MAX_LINES) + && data->num_viewports < WPS_MAX_VIEWPORTS + && data->viewports[data->num_viewports].num_lines < WPS_MAX_LINES) { switch(*wps_bufptr++) { @@ -1083,12 +1189,12 @@ line++; wps_start_new_subline(data); - data->num_lines++; /* Start a new line */ + data->viewports[data->num_viewports].num_lines++; /* Start a new line */ - if ((data->num_lines < WPS_MAX_LINES) && + if ((data->viewports[data->num_viewports].num_lines < WPS_MAX_LINES) && (data->num_sublines < WPS_MAX_SUBLINES)) { - data->lines[data->num_lines].first_subline_idx = + data->viewports[data->num_viewports].lines[data->viewports[data->num_viewports].num_lines].first_subline_idx = data->num_sublines; data->sublines[data->num_sublines].first_token_idx = @@ -1165,6 +1271,9 @@ if (!fail && level >= 0) /* there are unclosed conditionals */ fail = PARSE_FAIL_UNCLOSED_COND; + /* We have finished with the last viewport, so increment count */ + data->num_viewports++; + #ifdef DEBUG print_debug_info(data, fail, line); #endif @@ -1308,6 +1417,7 @@ /* to setup up the wps-data from a format-buffer (isfile = false) from a (wps-)file (isfile = true)*/ bool wps_data_load(struct wps_data *wps_data, + struct screen *display, const char *buf, bool isfile) { @@ -1316,6 +1426,22 @@ wps_reset(wps_data); + /* Initialise the first (default) viewport */ + wps_data->viewports[0].vp.x = 0; + wps_data->viewports[0].vp.y = 0; + wps_data->viewports[0].vp.width = display->width; + wps_data->viewports[0].vp.height = display->height; + wps_data->viewports[0].vp.font = FONT_UI; + wps_data->viewports[0].vp.drawmode = DRMODE_SOLID; + wps_data->viewports[0].vp.xmargin = display->getxmargin(); + wps_data->viewports[0].vp.ymargin = display->getymargin(); + + if (display->depth > 1) + { + wps_data->viewports[0].vp.fg_pattern = display->get_foreground(); + wps_data->viewports[0].vp.bg_pattern = display->get_background(); + } + if (!isfile) { return wps_parse(wps_data, buf); @@ -1402,20 +1528,20 @@ } } -int wps_subline_index(struct wps_data *data, int line, int subline) +int wps_subline_index(struct wps_data *data, int v, int line, int subline) { - return data->lines[line].first_subline_idx + subline; + return data->viewports[v].lines[line].first_subline_idx + subline; } -int wps_first_token_index(struct wps_data *data, int line, int subline) +int wps_first_token_index(struct wps_data *data, int v, int line, int subline) { - int first_subline_idx = data->lines[line].first_subline_idx; + int first_subline_idx = data->viewports[v].lines[line].first_subline_idx; return data->sublines[first_subline_idx + subline].first_token_idx; } -int wps_last_token_index(struct wps_data *data, int line, int subline) +int wps_last_token_index(struct wps_data *data, int v, int line, int subline) { - int first_subline_idx = data->lines[line].first_subline_idx; + int first_subline_idx = data->viewports[v].lines[line].first_subline_idx; int idx = first_subline_idx + subline; if (idx < data->num_sublines - 1) { Index: apps/filetree.c =================================================================== --- apps/filetree.c (revision 15983) +++ apps/filetree.c (working copy) @@ -478,7 +478,7 @@ #if LCD_DEPTH > 1 unload_wps_backdrop(); #endif - wps_data_load(gui_wps[0].data, buf, true); + wps_data_load(gui_wps[0].data, &screens[0], buf, true); set_file(buf, (char *)global_settings.wps_file, MAX_FILENAME); break; @@ -490,7 +490,7 @@ #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 unload_remote_wps_backdrop(); #endif - wps_data_load(gui_wps[1].data, buf, true); + wps_data_load(gui_wps[1].data, &screens[1], buf, true); set_file(buf, (char *)global_settings.rwps_file, MAX_FILENAME); break; Index: apps/plugin.c =================================================================== --- apps/plugin.c (revision 15983) +++ apps/plugin.c (working copy) @@ -581,6 +581,13 @@ cancel_cpu_boost, #endif #endif /* CONFIG_CODEC == SWCODEC */ + + lcd_set_viewport, + lcd_clear_viewport, +#ifdef HAVE_REMOTE_LCD + lcd_remote_set_viewport, + lcd_remote_clear_viewport, +#endif }; int plugin_load(const char* plugin, void* parameter) Index: apps/plugin.h =================================================================== --- apps/plugin.h (revision 15983) +++ apps/plugin.h (working copy) @@ -716,6 +716,13 @@ void (*cancel_cpu_boost)(void); #endif #endif /* CONFIG_CODEC == SWCODEC */ + + void (*lcd_set_viewport)(struct viewport* vp); + void (*lcd_clear_viewport)(void); +#ifdef HAVE_REMOTE_LCD + void (*lcd_remote_set_viewport)(struct viewport* vp); + void (*lcd_remote_clear_viewport)(void); +#endif }; /* plugin header */ Index: firmware/export/scroll_engine.h =================================================================== --- firmware/export/scroll_engine.h (revision 15983) +++ firmware/export/scroll_engine.h (working copy) @@ -23,9 +23,17 @@ #ifndef __SCROLL_ENGINE_H__ #define __SCROLL_ENGINE_H__ +#include + void scroll_init(void); +void lcd_scroll_stop(struct viewport* vp); +void lcd_scroll_stop_line(struct viewport* vp, int y); void lcd_scroll_fn(void); +#ifdef HAVE_REMOTE_LCD void lcd_remote_scroll_fn(void); +void lcd_remote_scroll_stop(struct viewport* vp); +void lcd_remote_scroll_stop_line(struct viewport* vp, int y); +#endif /* internal usage, but in multiple drivers */ #define SCROLL_SPACING 3 @@ -37,8 +45,10 @@ struct scrollinfo { + struct viewport* vp; char line[SCROLL_LINE_SIZE]; int len; /* length of line in chars */ + int y; /* Position of the line on the screen (char co-ordinates) */ int offset; int startx; #ifdef HAVE_LCD_BITMAP @@ -54,7 +64,8 @@ { struct scrollinfo * const scroll; const int num_scroll; /* number of scrollable lines (also number of scroll structs) */ - int lines; /* Bitpattern of which lines are scrolling */ + int lines; /* OLD USAGE: Bitpattern of which lines are scrolling + NEW USAGE (Viewports): Number of currently scrolling lines */ long ticks; /* # of ticks between updates*/ long delay; /* ticks delay before start */ int bidir_limit; /* percent */ Index: firmware/export/lcd.h =================================================================== --- firmware/export/lcd.h (revision 15983) +++ firmware/export/lcd.h (working copy) @@ -24,6 +24,26 @@ #include "cpu.h" #include "config.h" +struct viewport { + int x; + int y; + int width; + int height; + int font; + int drawmode; + int xmargin; /* During the transition only - to be removed */ + int ymargin; /* During the transition only - to be removed */ +#if LCD_DEPTH > 1 + unsigned fg_pattern; + unsigned bg_pattern; +#ifdef HAVE_LCD_COLOR + unsigned lss_pattern; + unsigned lse_pattern; + unsigned lst_pattern; +#endif +#endif +}; + #define STYLE_DEFAULT 0x00000000 #define STYLE_COLORED 0x10000000 #define STYLE_INVERT 0x20000000 @@ -76,9 +96,14 @@ extern void lcd_setmargins(int xmargin, int ymargin); extern int lcd_getxmargin(void); extern int lcd_getymargin(void); +extern int lcd_getwidth(void); +extern int lcd_getheight(void); extern int lcd_getstringsize(const unsigned char *str, int *w, int *h); +extern void lcd_set_viewport(struct viewport* vp); extern void lcd_update(void); +extern void lcd_update_viewport(void); +extern void lcd_clear_viewport(void); extern void lcd_clear_display(void); extern void lcd_putsxy(int x, int y, const unsigned char *string); extern void lcd_puts(int x, int y, const unsigned char *string); @@ -110,6 +135,7 @@ /* update a fraction of the screen */ extern void lcd_update_rect(int x, int y, int width, int height); +extern void lcd_update_viewport_rect(int x, int y, int width, int height); #ifdef HAVE_REMOTE_LCD extern void lcd_remote_update(void); Index: firmware/export/lcd-remote.h =================================================================== --- firmware/export/lcd-remote.h (revision 15983) +++ firmware/export/lcd-remote.h (working copy) @@ -24,6 +24,7 @@ #include "cpu.h" #include "config.h" #include "adc.h" +#include "lcd.h" #ifdef HAVE_REMOTE_LCD @@ -109,7 +110,9 @@ extern int lcd_remote_default_contrast(void); extern void lcd_remote_set_contrast(int val); +extern void lcd_remote_set_viewport(struct viewport* vp); extern void lcd_remote_clear_display(void); +extern void lcd_remote_clear_viewport(void); extern void lcd_remote_puts(int x, int y, const unsigned char *str); extern void lcd_remote_puts_style(int x, int y, const unsigned char *str, int style); @@ -132,6 +135,8 @@ extern void lcd_remote_update(void); extern void lcd_remote_update_rect(int x, int y, int width, int height); +extern void lcd_remote_update_viewport(void); +extern void lcd_remote_update_viewport_rect(int x, int y, int width, int height); extern void lcd_remote_set_invert_display(bool yesno); extern void lcd_remote_set_flip(bool yesno); @@ -141,6 +146,8 @@ extern void lcd_remote_setmargins(int xmargin, int ymargin); extern int lcd_remote_getxmargin(void); extern int lcd_remote_getymargin(void); +extern int lcd_remote_getwidth(void); +extern int lcd_remote_getheight(void); extern void lcd_remote_setfont(int font); extern int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h); Index: firmware/scroll_engine.c =================================================================== --- firmware/scroll_engine.c (revision 15983) +++ firmware/scroll_engine.c (working copy) @@ -82,6 +82,40 @@ lcd_scroll_info.lines = 0; } +/* Stop scrolling line y in the specified viewport, or all lines if y < 0 */ +void lcd_scroll_stop_line(struct viewport* current_vp, int y) +{ + int i = 0; + + while (i < lcd_scroll_info.lines) + { + if ((lcd_scroll_info.scroll[i].vp == current_vp) && + ((y < 0) || (lcd_scroll_info.scroll[i].y == y))) + { + /* If i is not the last active line in the array, then move + the last item to position i */ + if ((i + 1) != lcd_scroll_info.lines) + { + lcd_scroll_info.scroll[i] = lcd_scroll_info.scroll[lcd_scroll_info.lines-1]; + } + lcd_scroll_info.lines--; + + /* A line can only appear once, so we're done. */ + return ; + } + else + { + i++; + } + } +} + +/* Stop all scrolling lines in the specified viewport */ +void lcd_scroll_stop(struct viewport* vp) +{ + lcd_scroll_stop_line(vp, -1); +} + void lcd_scroll_speed(int speed) { lcd_scroll_info.ticks = scroll_tick_table[speed]; @@ -122,6 +156,40 @@ lcd_remote_scroll_info.lines = 0; } +/* Stop scrolling line y in the specified viewport, or all lines if y < 0 */ +void lcd_remote_scroll_stop_line(struct viewport* current_vp, int y) +{ + int i = 0; + + while (i < lcd_remote_scroll_info.lines) + { + if ((lcd_remote_scroll_info.scroll[i].vp == current_vp) && + ((y < 0) || (lcd_remote_scroll_info.scroll[i].y == y))) + { + /* If i is not the last active line in the array, then move + the last item to position i */ + if ((i + 1) != lcd_remote_scroll_info.lines) + { + lcd_remote_scroll_info.scroll[i] = lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines-1]; + } + lcd_remote_scroll_info.lines--; + + /* A line can only appear once, so we're done. */ + return ; + } + else + { + i++; + } + } +} + +/* Stop all scrolling lines in the specified viewport */ +void lcd_remote_scroll_stop(struct viewport* vp) +{ + lcd_remote_scroll_stop_line(vp, -1); +} + void lcd_remote_scroll_speed(int speed) { lcd_remote_scroll_info.ticks = scroll_tick_table[speed]; Index: firmware/mp3data.c =================================================================== --- firmware/mp3data.c (revision 15983) +++ firmware/mp3data.c (working copy) @@ -38,7 +38,7 @@ #include "file.h" #include "buffer.h" -#define DEBUG_VERBOSE +//#define DEBUG_VERBOSE #define SYNC_MASK (0x7ffL << 21) #define VERSION_MASK (3L << 19) Index: firmware/drivers/lcd-remote-2bit-vi.c =================================================================== --- firmware/drivers/lcd-remote-2bit-vi.c (revision 15983) +++ firmware/drivers/lcd-remote-2bit-vi.c (working copy) @@ -46,13 +46,43 @@ static fb_remote_data* remote_backdrop = NULL; static long remote_backdrop_offset IDATA_ATTR = 0; -static unsigned fg_pattern IDATA_ATTR = 0xFFFF; /* initially black */ -static unsigned bg_pattern IDATA_ATTR = 0x0000; /* initially white */ -static int drawmode = DRMODE_SOLID; -static int xmargin = 0; -static int ymargin = 0; -static int curfont = FONT_SYSFIXED; +static struct viewport default_vp = + { + .x = 0, + .y = 0, + .width = LCD_REMOTE_WIDTH, + .height = LCD_REMOTE_HEIGHT, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, + .fg_pattern = 0xFFFF; /* initially black */ + .bg_pattern = 0x0000; /* initially white */ + }; +static struct viewport* current_vp IDATA_ATTR = &default_vp; + +/*** Viewports ***/ + +void lcd_remote_set_viewport(struct viewport* vp) +{ + if (vp == NULL) + current_vp = &default_vp; + else + current_vp = vp; +} + +void lcd_remote_update_viewport(void) +{ + lcd_remote_update_rect(current_vp->x, current_vp->y, + current_vp->width, current_vp->height); +} + +void lcd_remote_update_viewport_rect(int x, int y, int width, int height) +{ + lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height); +} + /*** parameter handling ***/ unsigned lcd_remote_color_to_native(unsigned color) { @@ -69,12 +99,12 @@ void lcd_remote_set_drawmode(int mode) { - drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); + current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } int lcd_remote_get_drawmode(void) { - return drawmode; + return current_vp->drawmode; } void lcd_remote_set_foreground(unsigned brightness) @@ -107,28 +137,28 @@ void lcd_remote_setmargins(int x, int y) { - xmargin = x; - ymargin = y; + current_vp->xmargin = x; + current_vp->ymargin = y; } int lcd_remote_getxmargin(void) { - return xmargin; + return current_vp->xmargin; } int lcd_remote_getymargin(void) { - return ymargin; + return current_vp->ymargin; } void lcd_remote_setfont(int newfont) { - curfont = newfont; + current_vp->font = newfont; } int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h) { - return font_getstringsize(str, w, h, curfont); + return font_getstringsize(str, w, h, current_vp->font); } /*** low-level drawing functions ***/ @@ -348,10 +378,10 @@ /*** drawing functions ***/ -/* Clear the whole display */ -void lcd_remote_clear_display(void) +/* Clear the current viewport */ +void lcd_remote_clear_viewport(void) { - if (drawmode & DRMODE_INVERSEVID) + if (current_vp->drawmode & DRMODE_INVERSEVID) { memset(lcd_remote_framebuffer, fg_pattern, sizeof lcd_remote_framebuffer); @@ -366,14 +396,30 @@ sizeof lcd_remote_framebuffer); } - lcd_remote_scroll_info.lines = 0; + if (current_vp == &default_vp) + lcd_remote_scroll_info.lines = 0; + else + lcd_remote_scroll_stop(current_vp); } +/* Clear the whole display */ +void lcd_remote_clear_display(void) +{ + struct viewport* oldvp = current_vp; + + current_vp = &default_vp; + + lcd_remote_clear_viewport(); + + current_vp = oldvp; +} + /* Set a single pixel */ void lcd_remote_drawpixel(int x, int y) { - if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) - lcd_remote_pixelfuncs[drawmode](x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y); } /* Draw a line */ @@ -385,7 +431,7 @@ int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; - lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[drawmode]; + lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode]; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -429,7 +475,8 @@ for (i = 0; i < numpixels; i++) { - if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) + if (((unsigned)x < (unsigned)current_vp->width && + ((unsigned)y < (unsigned)current_vp->height)) pfunc(x, y); if (d < 0) @@ -464,7 +511,7 @@ } /* nothing to draw? */ - if (((unsigned)y >= LCD_REMOTE_HEIGHT) || (x1 >= LCD_REMOTE_WIDTH) + if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= LCD_REMOTE_WIDTH) || (x2 < 0)) return; @@ -474,7 +521,7 @@ if (x2 >= LCD_REMOTE_WIDTH) x2 = LCD_REMOTE_WIDTH-1; - bfunc = lcd_remote_blockfuncs[drawmode]; + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y>>3][x1]; mask = 0x0101 << (y & 7); @@ -511,7 +558,7 @@ if (y2 >= LCD_REMOTE_HEIGHT) y2 = LCD_REMOTE_HEIGHT-1; - bfunc = lcd_remote_blockfuncs[drawmode]; + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y1>>3][x]; ny = y2 - (y1 & ~7); mask = (0xFFu << (y1 & 7)) & 0xFFu; @@ -575,9 +622,9 @@ if (y + height > LCD_REMOTE_HEIGHT) height = LCD_REMOTE_HEIGHT - y; - if (drawmode & DRMODE_INVERSEVID) + if (current_vp->drawmode & DRMODE_INVERSEVID) { - if ((drawmode & DRMODE_BG) && !remote_backdrop) + if ((current_vp->drawmode & DRMODE_BG) && !remote_backdrop) { fillopt = true; bits = bg_pattern; @@ -585,13 +632,13 @@ } else { - if (drawmode & DRMODE_FG) + if (current_vp->drawmode & DRMODE_FG) { fillopt = true; bits = fg_pattern; } } - bfunc = lcd_remote_blockfuncs[drawmode]; + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y>>3][x]; ny = height - 1 + (y & 7); mask = (0xFFu << (y & 7)) & 0xFFu; @@ -682,7 +729,7 @@ shift = y & 7; ny = height - 1 + shift + src_y; - bfunc = lcd_remote_blockfuncs[drawmode]; + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; mask = 0xFFu << (shift + src_y); /* not byte-doubled here because shift+src_y can be > 7 */ mask_bottom = 0xFFu >> (~ny & 7); @@ -917,7 +964,7 @@ { unsigned short ch; unsigned short *ucs; - struct font* pf = font_get(curfont); + struct font* pf = font_get(current_vp->font); ucs = bidi_l2v(str, 1); @@ -975,7 +1022,7 @@ int style, int offset) { int xpos,ypos,w,h,xrect; - int lastmode = drawmode; + int lastmode = current_vp->drawmode; /* make sure scrolling is turned off on the line we are updating */ lcd_remote_scroll_info.lines &= ~(1 << y); @@ -984,15 +1031,15 @@ return; lcd_remote_getstringsize(str, &w, &h); - xpos = xmargin + x*w / utf8length((char *)str); - ypos = ymargin + y*h; - drawmode = (style & STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + xpos = current_vp->xmargin + x*w / utf8length((char *)str); + ypos = current_vp->ymargin + y*h; + current_vp->drawmode = (style & STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_remote_putsxyofs(xpos, ypos, offset, str); - drawmode ^= DRMODE_INVERSEVID; + current_vp->drawmode ^= DRMODE_INVERSEVID; xrect = xpos + MAX(w - offset, 0); lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h); - drawmode = lastmode; + current_vp->drawmode = lastmode; } /*** scrolling ***/ @@ -1031,7 +1078,7 @@ lcd_remote_getstringsize(string, &w, &h); - if (LCD_REMOTE_WIDTH - x * 8 - xmargin < w) { + if (LCD_REMOTE_WIDTH - x * 8 - current_vp->xmargin < w) { /* prepare scroll line */ char *end; @@ -1044,7 +1091,7 @@ /* scroll bidirectional or forward only depending on the string width */ if ( lcd_remote_scroll_info.bidir_limit ) { - s->bidir = s->width < (LCD_REMOTE_WIDTH - xmargin) * + s->bidir = s->width < (LCD_REMOTE_WIDTH - current_vp->xmargin) * (100 + lcd_remote_scroll_info.bidir_limit) / 100; } else @@ -1061,7 +1108,7 @@ s->len = utf8length((char *)string); s->offset = offset; - s->startx = xmargin + x * s->width / s->len;; + s->startx = current_vp->xmargin + x * s->width / s->len;; s->backward = false; lcd_remote_scroll_info.lines |= (1<offset += lcd_remote_scroll_info.step; - pf = font_get(curfont); + pf = font_get(current_vp->font); xpos = s->startx; - ypos = ymargin + index * pf->height; + ypos = current_vp->ymargin + index * pf->height; if (s->bidir) { /* scroll bidirectional */ if (s->offset <= 0) { @@ -1118,12 +1165,12 @@ s->offset %= s->width; } - lastmode = drawmode; - drawmode = (s->style&STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + lastmode = current_vp->drawmode; + current_vp->drawmode = (s->style&STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line); - drawmode = lastmode; - lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height); + current_vp->drawmode = lastmode; + lcd_remote_update_viewport_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height); } } Index: firmware/drivers/lcd-16bit.c =================================================================== --- firmware/drivers/lcd-16bit.c (revision 15983) +++ firmware/drivers/lcd-16bit.c (working copy) @@ -49,24 +49,24 @@ static fb_data* lcd_backdrop = NULL; static long lcd_backdrop_offset IDATA_ATTR = 0; -#if !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) -static unsigned fg_pattern IDATA_ATTR = LCD_DEFAULT_FG; -static unsigned bg_pattern IDATA_ATTR = LCD_DEFAULT_BG; -static unsigned lss_pattern IDATA_ATTR = LCD_DEFAULT_LS; -static unsigned lse_pattern IDATA_ATTR = LCD_DEFAULT_BG; -static unsigned lst_pattern IDATA_ATTR = LCD_DEFAULT_FG; -#else -unsigned fg_pattern IDATA_ATTR = LCD_DEFAULT_FG; -unsigned bg_pattern IDATA_ATTR = LCD_DEFAULT_BG; -unsigned lss_pattern IDATA_ATTR = LCD_DEFAULT_LS; -unsigned lse_pattern IDATA_ATTR = LCD_DEFAULT_BG; -unsigned lst_pattern IDATA_ATTR = LCD_DEFAULT_FG; -#endif +static struct viewport default_vp = +{ + .x = 0, + .y = 0, + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, + .fg_pattern = LCD_DEFAULT_FG, + .bg_pattern = LCD_DEFAULT_BG, + .lss_pattern = LCD_DEFAULT_BG, + .lse_pattern = LCD_DEFAULT_BG, + .lst_pattern = LCD_DEFAULT_BG, +}; -static int drawmode = DRMODE_SOLID; -static int xmargin = 0; -static int ymargin = 0; -static int curfont = FONT_SYSFIXED; +static struct viewport* current_vp IDATA_ATTR = &default_vp; /* LCD init */ void lcd_init(void) @@ -78,84 +78,115 @@ scroll_init(); } +/*** Viewports ***/ + +void lcd_set_viewport(struct viewport* vp) +{ + if (vp == NULL) + current_vp = &default_vp; + else + current_vp = vp; +} + +void lcd_update_viewport(void) +{ + lcd_update_rect(current_vp->x, current_vp->y, + current_vp->width, current_vp->height); +} + +void lcd_update_viewport_rect(int x, int y, int width, int height) +{ + lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height); +} + /*** parameter handling ***/ void lcd_set_drawmode(int mode) { - drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); + current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } int lcd_get_drawmode(void) { - return drawmode; + return current_vp->drawmode; } void lcd_set_foreground(unsigned color) { - fg_pattern = color; + current_vp->fg_pattern = color; } unsigned lcd_get_foreground(void) { - return fg_pattern; + return current_vp->fg_pattern; } void lcd_set_background(unsigned color) { - bg_pattern = color; + current_vp->bg_pattern = color; } unsigned lcd_get_background(void) { - return bg_pattern; + return current_vp->bg_pattern; } void lcd_set_selector_start(unsigned color) { - lss_pattern = color; + current_vp->lss_pattern = color; } void lcd_set_selector_end(unsigned color) { - lse_pattern = color; + current_vp->lse_pattern = color; } void lcd_set_selector_text(unsigned color) { - lst_pattern = color; + current_vp->lst_pattern = color; } void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color) { lcd_set_drawmode(mode); - fg_pattern = fg_color; - bg_pattern = bg_color; + current_vp->fg_pattern = fg_color; + current_vp->bg_pattern = bg_color; } void lcd_setmargins(int x, int y) { - xmargin = x; - ymargin = y; + current_vp->xmargin = x; + current_vp->ymargin = y; } +int lcd_getwidth(void) +{ + return current_vp->width; +} + +int lcd_getheight(void) +{ + return current_vp->height; +} + int lcd_getxmargin(void) { - return xmargin; + return current_vp->xmargin; } int lcd_getymargin(void) { - return ymargin; + return current_vp->ymargin; } void lcd_setfont(int newfont) { - curfont = newfont; + current_vp->font = newfont; } int lcd_getstringsize(const unsigned char *str, int *w, int *h) { - return font_getstringsize(str, w, h, curfont); + return font_getstringsize(str, w, h, current_vp->font); } /*** low-level drawing functions ***/ @@ -165,13 +196,13 @@ static void setpixel(fb_data *address) ICODE_ATTR; static void setpixel(fb_data *address) { - *address = fg_pattern; + *address = current_vp->fg_pattern; } static void clearpixel(fb_data *address) ICODE_ATTR; static void clearpixel(fb_data *address) { - *address = bg_pattern; + *address = current_vp->bg_pattern; } static void clearimgpixel(fb_data *address) ICODE_ATTR; @@ -226,31 +257,74 @@ /*** drawing functions ***/ -/* Clear the whole display */ -void lcd_clear_display(void) +/* Clear the current viewport */ +void lcd_clear_viewport(void) { - fb_data *dst = LCDADDR(0, 0); + fb_data *dst, *dst_end; - if (drawmode & DRMODE_INVERSEVID) + dst = LCDADDR(current_vp->x, current_vp->y); + dst_end = dst + current_vp->height * LCD_WIDTH; + + if (current_vp->drawmode & DRMODE_INVERSEVID) { - memset16(dst, fg_pattern, LCD_WIDTH*LCD_HEIGHT); + do + { + memset16(dst, current_vp->fg_pattern, current_vp->width); + dst += LCD_WIDTH; + } + while (dst < dst_end); } else { if (!lcd_backdrop) - memset16(dst, bg_pattern, LCD_WIDTH*LCD_HEIGHT); + { + do + { + memset16(dst, current_vp->bg_pattern, current_vp->width); + dst += LCD_WIDTH; + } + while (dst < dst_end); + } else - memcpy(dst, lcd_backdrop, sizeof(lcd_framebuffer)); + { + do + { + memcpy(dst, (void *)((long)dst + lcd_backdrop_offset), + current_vp->width * sizeof(fb_data)); + dst += LCD_WIDTH; + } + while (dst < dst_end); + } } - lcd_scroll_info.lines = 0; + if (current_vp == &default_vp) + { + lcd_scroll_info.lines = 0; + } + else + { + lcd_scroll_stop(current_vp); + } } +/* Clear the whole display */ +void lcd_clear_display(void) +{ + struct viewport* old_vp = current_vp; + + current_vp = &default_vp; + + lcd_clear_viewport(); + + current_vp = old_vp; +} + /* Set a single pixel */ void lcd_drawpixel(int x, int y) { - if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) - lcd_fastpixelfuncs[drawmode](LCDADDR(x, y)); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + lcd_fastpixelfuncs[current_vp->drawmode](LCDADDR(current_vp->x+x, current_vp->y+y)); } /* Draw a line */ @@ -262,7 +336,7 @@ int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; - lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -306,8 +380,8 @@ for (i = 0; i < numpixels; i++) { - if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) - pfunc(LCDADDR(x, y)); + if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height)) + pfunc(LCDADDR(x + current_vp->x, y + current_vp->y)); if (d < 0) { @@ -331,7 +405,7 @@ unsigned bits = 0; enum fill_opt fillopt = OPT_NONE; fb_data *dst, *dst_end; - lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; /* direction flip */ if (x2 < x1) @@ -342,23 +416,31 @@ } /* nothing to draw? */ - if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) + if (((unsigned)y >= (unsigned)current_vp->height) || + (x1 >= current_vp->width) || + (x2 < 0)) return; /* clipping */ if (x1 < 0) x1 = 0; - if (x2 >= LCD_WIDTH) - x2 = LCD_WIDTH-1; + if (x2 >= current_vp->width) + x2 = current_vp->width-1; - if (drawmode & DRMODE_INVERSEVID) + width = x2 - x1 + 1; + + /* Adjust x1 and y to viewport */ + x1 += current_vp->x; + y += current_vp->y; + + if (current_vp->drawmode & DRMODE_INVERSEVID) { - if (drawmode & DRMODE_BG) + if (current_vp->drawmode & DRMODE_BG) { if (!lcd_backdrop) { fillopt = OPT_SET; - bits = bg_pattern; + bits = current_vp->bg_pattern; } else fillopt = OPT_COPY; @@ -366,14 +448,13 @@ } else { - if (drawmode & DRMODE_FG) + if (current_vp->drawmode & DRMODE_FG) { fillopt = OPT_SET; - bits = fg_pattern; + bits = current_vp->fg_pattern; } } dst = LCDADDR(x1, y); - width = x2 - x1 + 1; switch (fillopt) { @@ -400,7 +481,7 @@ { int y; fb_data *dst, *dst_end; - lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; /* direction flip */ if (y2 < y1) @@ -411,16 +492,18 @@ } /* nothing to draw? */ - if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) + if ((x >= current_vp->width) || + (y1 >= current_vp->height) || + (y2 < 0)) return; /* clipping */ if (y1 < 0) y1 = 0; - if (y2 >= LCD_HEIGHT) - y2 = LCD_HEIGHT-1; + if (y2 >= current_vp->height) + y2 = current_vp->height-1; - dst = LCDADDR(x, y1); + dst = LCDADDR(x + current_vp->x, y1 + current_vp->y); dst_end = dst + (y2 - y1) * LCD_WIDTH; do @@ -452,11 +535,11 @@ unsigned bits = 0; enum fill_opt fillopt = OPT_NONE; fb_data *dst, *dst_end; - lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode]; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -470,19 +553,19 @@ height += y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; - if (drawmode & DRMODE_INVERSEVID) + if (current_vp->drawmode & DRMODE_INVERSEVID) { - if (drawmode & DRMODE_BG) + if (current_vp->drawmode & DRMODE_BG) { if (!lcd_backdrop) { fillopt = OPT_SET; - bits = bg_pattern; + bits = current_vp->bg_pattern; } else fillopt = OPT_COPY; @@ -490,13 +573,13 @@ } else { - if (drawmode & DRMODE_FG) + if (current_vp->drawmode & DRMODE_FG) { fillopt = OPT_SET; - bits = fg_pattern; + bits = current_vp->fg_pattern; } } - dst = LCDADDR(x, y); + dst = LCDADDR(current_vp->x + x, current_vp->y + y); dst_end = dst + height * LCD_WIDTH; do @@ -530,24 +613,28 @@ /* Fill a rectangle with a gradient */ void lcd_gradient_rect(int x1, int x2, int y, int h) { + int old_pattern = current_vp->fg_pattern; + if (h == 0) return; - int h_r = RGB_UNPACK_RED(lss_pattern) << 16; - int h_b = RGB_UNPACK_BLUE(lss_pattern) << 16; - int h_g = RGB_UNPACK_GREEN(lss_pattern) << 16; - int rstep = (h_r - ((signed)RGB_UNPACK_RED(lse_pattern) << 16)) / h; - int gstep = (h_g - ((signed)RGB_UNPACK_GREEN(lse_pattern) << 16)) / h; - int bstep = (h_b - ((signed)RGB_UNPACK_BLUE(lse_pattern) << 16)) / h; + int h_r = RGB_UNPACK_RED(current_vp->lss_pattern) << 16; + int h_b = RGB_UNPACK_BLUE(current_vp->lss_pattern) << 16; + int h_g = RGB_UNPACK_GREEN(current_vp->lss_pattern) << 16; + int rstep = (h_r - ((signed)RGB_UNPACK_RED(current_vp->lse_pattern) << 16)) / h; + int gstep = (h_g - ((signed)RGB_UNPACK_GREEN(current_vp->lse_pattern) << 16)) / h; + int bstep = (h_b - ((signed)RGB_UNPACK_BLUE(current_vp->lse_pattern) << 16)) / h; int count; - fg_pattern = lss_pattern; + current_vp->fg_pattern = current_vp->lss_pattern; for(count = 0; count < h; count++) { lcd_hline(x1, x2, y + count); h_r -= rstep; h_g -= gstep; h_b -= bstep; - fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16); + current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16); } + + current_vp->fg_pattern = old_pattern; } #define H_COLOR(lss, lse, cur_line, max_line) \ @@ -562,14 +649,14 @@ { if (h == 0 || num_lines == 0) return; - unsigned tmp_lss = lss_pattern; - unsigned tmp_lse = lse_pattern; - int lss_r = (signed)RGB_UNPACK_RED(lss_pattern); - int lss_b = (signed)RGB_UNPACK_BLUE(lss_pattern); - int lss_g = (signed)RGB_UNPACK_GREEN(lss_pattern); - int lse_r = (signed)RGB_UNPACK_RED(lse_pattern); - int lse_b = (signed)RGB_UNPACK_BLUE(lse_pattern); - int lse_g = (signed)RGB_UNPACK_GREEN(lse_pattern); + unsigned tmp_lss = current_vp->lss_pattern; + unsigned tmp_lse = current_vp->lse_pattern; + int lss_r = (signed)RGB_UNPACK_RED(current_vp->lss_pattern); + int lss_b = (signed)RGB_UNPACK_BLUE(current_vp->lss_pattern); + int lss_g = (signed)RGB_UNPACK_GREEN(current_vp->lss_pattern); + int lse_r = (signed)RGB_UNPACK_RED(current_vp->lse_pattern); + int lse_b = (signed)RGB_UNPACK_BLUE(current_vp->lse_pattern); + int lse_g = (signed)RGB_UNPACK_GREEN(current_vp->lse_pattern); int h_r = H_COLOR(lss_r, lse_r, cur_line, num_lines); int h_g = H_COLOR(lss_g, lse_g, cur_line, num_lines); @@ -583,8 +670,8 @@ lcd_gradient_rect(x1, x2, y, h); - lcd_set_selector_start(tmp_lss); - lcd_set_selector_end(tmp_lse); + current_vp->lss_pattern = tmp_lss; + current_vp->lse_pattern = tmp_lse; } /* About Rockbox' internal monochrome bitmap format: @@ -613,8 +700,8 @@ lcd_fastpixelfunc_type *fgfunc, *bgfunc; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -630,20 +717,20 @@ src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; src += stride * (src_y >> 3) + src_x; /* move starting point */ src_y &= 7; src_end = src + width; - dst = LCDADDR(x, y); + dst = LCDADDR(current_vp->x + x, current_vp->y + y); has_backdrop = (lcd_backdrop != NULL); - backdrop = lcd_backdrop + y * LCD_WIDTH + x; - fgfunc = lcd_fastpixelfuncs[drawmode]; - bgfunc = lcd_fastpixelfuncs[drawmode ^ DRMODE_INVERSEVID]; + backdrop = lcd_backdrop + (current_vp->y + y) * LCD_WIDTH + current_vp->x + x; + fgfunc = lcd_fastpixelfuncs[current_vp->drawmode]; + bgfunc = lcd_fastpixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID]; do { const unsigned char *src_col = src++; @@ -654,23 +741,23 @@ dst_end = dst_col + height * LCD_WIDTH; do { - switch (drawmode) + switch (current_vp->drawmode) { case DRMODE_SOLID: if (data & 0x01) - *dst_col = fg_pattern; + *dst_col = current_vp->fg_pattern; else - *dst_col = has_backdrop ? *backdrop_col : bg_pattern; + *dst_col = has_backdrop ? *backdrop_col : current_vp->bg_pattern; break; case DRMODE_FG: if (data & 0x01) - *dst_col = fg_pattern; + *dst_col = current_vp->fg_pattern; break; case (DRMODE_SOLID|DRMODE_INVERSEVID): if (data & 0x01) - *dst_col = has_backdrop ? *backdrop_col : bg_pattern; + *dst_col = has_backdrop ? *backdrop_col : current_vp->bg_pattern; else - *dst_col = fg_pattern; + *dst_col = current_vp->fg_pattern; break; default: if (data & 0x01) @@ -709,8 +796,8 @@ fb_data *dst, *dst_end; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -726,13 +813,13 @@ src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; src += stride * src_y + src_x; /* move starting point */ - dst = LCDADDR(x, y); + dst = LCDADDR(current_vp->x + x, current_vp->y + y); dst_end = dst + height * LCD_WIDTH; do @@ -763,8 +850,8 @@ fb_data *dst, *dst_end; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) - || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || + (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -780,13 +867,13 @@ src_y -= y; y = 0; } - if (x + width > LCD_WIDTH) - width = LCD_WIDTH - x; - if (y + height > LCD_HEIGHT) - height = LCD_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; src += stride * src_y + src_x; /* move starting point */ - dst = LCDADDR(x, y); + dst = LCDADDR(current_vp->x + x, current_vp->y + y); dst_end = dst + height * LCD_WIDTH; do @@ -795,7 +882,7 @@ for(i = 0;i < width;i++) { if (src[i] == REPLACEWITHFG_COLOR) - dst[i] = fg_pattern; + dst[i] = current_vp->fg_pattern; else if(src[i] != TRANSPARENT_COLOR) dst[i] = src[i]; } @@ -818,11 +905,11 @@ { unsigned short ch; unsigned short *ucs; - struct font* pf = font_get(curfont); + struct font* pf = font_get(current_vp->font); ucs = bidi_l2v(str, 1); - while ((ch = *ucs++) != 0 && x < LCD_WIDTH) + while ((ch = *ucs++) != 0 && x < current_vp->width) { int width; const unsigned char *bits; @@ -875,51 +962,51 @@ int offset) { int xpos,ypos,w,h,xrect; - int lastmode = drawmode; - int oldfgcolor = fg_pattern; - int oldbgcolor = bg_pattern; + int lastmode = current_vp->drawmode; + int oldfgcolor = current_vp->fg_pattern; + int oldbgcolor = current_vp->bg_pattern; /* make sure scrolling is turned off on the line we are updating */ - lcd_scroll_info.lines &= ~(1 << y); + lcd_scroll_stop_line(current_vp, y); if(!str || !str[0]) return; lcd_getstringsize(str, &w, &h); - xpos = xmargin + x*w / utf8length(str); - ypos = ymargin + y*h; - drawmode = (style & STYLE_INVERT) ? + xpos = current_vp->xmargin + x*w / utf8length(str); + ypos = current_vp->ymargin + y*h; + current_vp->drawmode = (style & STYLE_INVERT) ? (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; if (style & STYLE_COLORED) { - if (drawmode == DRMODE_SOLID) - fg_pattern = style & STYLE_COLOR_MASK; + if (current_vp->drawmode == DRMODE_SOLID) + current_vp->fg_pattern = style & STYLE_COLOR_MASK; else - bg_pattern = style & STYLE_COLOR_MASK; + current_vp->bg_pattern = style & STYLE_COLOR_MASK; } - drawmode ^= DRMODE_INVERSEVID; + current_vp->drawmode ^= DRMODE_INVERSEVID; xrect = xpos + MAX(w - offset, 0); if (style & STYLE_GRADIENT) { - drawmode = DRMODE_FG; + current_vp->drawmode = DRMODE_FG; if (CURLN_UNPACK(style) == 0) - lcd_gradient_rect(xpos, LCD_WIDTH, ypos, h*NUMLN_UNPACK(style)); - fg_pattern = lst_pattern; + lcd_gradient_rect(xpos, current_vp->width, ypos, h*NUMLN_UNPACK(style)); + current_vp->fg_pattern = current_vp->lst_pattern; } else if (style & STYLE_COLORBAR) { - drawmode = DRMODE_FG; - fg_pattern = lss_pattern; - lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h); - fg_pattern = lst_pattern; + current_vp->drawmode = DRMODE_FG; + current_vp->fg_pattern = current_vp->lss_pattern; + lcd_fillrect(xpos, ypos, current_vp->width - xpos, h); + current_vp->fg_pattern = current_vp->lst_pattern; } else { - lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); - drawmode = (style & STYLE_INVERT) ? + lcd_fillrect(xrect, ypos, current_vp->width - xrect, h); + current_vp->drawmode = (style & STYLE_INVERT) ? (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; } lcd_putsxyofs(xpos, ypos, offset, str); - drawmode = lastmode; - fg_pattern = oldfgcolor; - bg_pattern = oldbgcolor; + current_vp->drawmode = lastmode; + current_vp->fg_pattern = oldfgcolor; + current_vp->bg_pattern = oldbgcolor; } /*** scrolling ***/ @@ -938,23 +1025,28 @@ lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset); } +/* Initialise a scrolling line at (x,y) in current viewport */ + void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, int style, int offset) { struct scrollinfo* s; int w, h; - if(y>=LCD_SCROLLABLE_LINES) return; + /* remove any previously scrolling line at the same location */ + lcd_scroll_stop_line(current_vp, y); - s = &lcd_scroll_info.scroll[y]; + if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return; + s = &lcd_scroll_info.scroll[lcd_scroll_info.lines]; + s->start_tick = current_tick + lcd_scroll_info.delay; s->style = style; lcd_puts_style_offset(x,y,string,style,offset); lcd_getstringsize(string, &w, &h); - if (LCD_WIDTH - x * 8 - xmargin < w) { + if (current_vp->width - x * 8 - current_vp->xmargin < w) { /* prepare scroll line */ char *end; @@ -967,7 +1059,7 @@ /* scroll bidirectional or forward only depending on the string width */ if ( lcd_scroll_info.bidir_limit ) { - s->bidir = s->width < (LCD_WIDTH - xmargin) * + s->bidir = s->width < (current_vp->width - current_vp->xmargin) * (100 + lcd_scroll_info.bidir_limit) / 100; } else @@ -980,17 +1072,16 @@ } end = strchr(s->line, '\0'); - strncpy(end, string, LCD_WIDTH/2); + strncpy(end, string, current_vp->width/2); + s->vp = current_vp; + s->y = y; s->len = utf8length(string); s->offset = offset; - s->startx = xmargin + x * s->width / s->len; + s->startx = current_vp->xmargin + x * s->width / s->len; s->backward = false; - lcd_scroll_info.lines |= (1<start_tick)) continue; + current_vp = s->vp; + old_fgcolor = current_vp->fg_pattern; + old_bgcolor = current_vp->bg_pattern; + if (s->style&STYLE_COLORED) { if (s->style&STYLE_MODE_MASK) { - fg_pattern = old_fgcolor; - bg_pattern = s->style&STYLE_COLOR_MASK; + current_vp->fg_pattern = old_fgcolor; + current_vp->bg_pattern = s->style&STYLE_COLOR_MASK; } else { - fg_pattern = s->style&STYLE_COLOR_MASK; - bg_pattern = old_bgcolor; + current_vp->fg_pattern = s->style&STYLE_COLOR_MASK; + current_vp->bg_pattern = old_bgcolor; } } @@ -1030,9 +1122,9 @@ else s->offset += lcd_scroll_info.step; - pf = font_get(curfont); + pf = font_get(current_vp->font); xpos = s->startx; - ypos = ymargin + index * pf->height; + ypos = current_vp->ymargin + s->y * pf->height; if (s->bidir) { /* scroll bidirectional */ if (s->offset <= 0) { @@ -1041,9 +1133,9 @@ s->backward = false; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } - if (s->offset >= s->width - (LCD_WIDTH - xpos)) { + if (s->offset >= s->width - (current_vp->width - xpos)) { /* at end of line */ - s->offset = s->width - (LCD_WIDTH - xpos); + s->offset = s->width - (current_vp->width - xpos); s->backward = true; s->start_tick = current_tick + lcd_scroll_info.delay * 2; } @@ -1054,35 +1146,36 @@ s->offset %= s->width; } - lastmode = drawmode; + lastmode = current_vp->drawmode; switch (s->style&STYLE_MODE_MASK) { case STYLE_INVERT: - drawmode = DRMODE_SOLID|DRMODE_INVERSEVID; + current_vp->drawmode = DRMODE_SOLID|DRMODE_INVERSEVID; break; case STYLE_COLORBAR: /* Solid colour line selector */ - drawmode = DRMODE_FG; - fg_pattern = lss_pattern; - lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); - fg_pattern = lst_pattern; + current_vp->drawmode = DRMODE_FG; + current_vp->fg_pattern = current_vp->lss_pattern; + lcd_fillrect(xpos, ypos, current_vp->width - xpos, pf->height); + current_vp->fg_pattern = current_vp->lst_pattern; break; case STYLE_GRADIENT: /* Gradient line selector */ - drawmode = DRMODE_FG; - lcd_gradient_rect_scroll(xpos, LCD_WIDTH, ypos, (signed)pf->height, + current_vp->drawmode = DRMODE_FG; + lcd_gradient_rect_scroll(xpos, current_vp->width, ypos, (signed)pf->height, NUMLN_UNPACK(s->style), CURLN_UNPACK(s->style)); - fg_pattern = lst_pattern; + current_vp->fg_pattern = current_vp->lst_pattern; break; default: - drawmode = DRMODE_SOLID; + current_vp->drawmode = DRMODE_SOLID; break; } lcd_putsxyofs(xpos, ypos, s->offset, s->line); - drawmode = lastmode; - lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); + current_vp->drawmode = lastmode; + current_vp->fg_pattern = old_fgcolor; + current_vp->bg_pattern = old_bgcolor; + lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height); } - fg_pattern = old_fgcolor; - bg_pattern = old_bgcolor; + current_vp = old_vp; } Index: firmware/drivers/lcd-remote-1bit-v.c =================================================================== --- firmware/drivers/lcd-remote-1bit-v.c (revision 15983) +++ firmware/drivers/lcd-remote-1bit-v.c (working copy) @@ -38,47 +38,88 @@ fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH] IBSS_ATTR; -static int drawmode = DRMODE_SOLID; -static int xmargin = 0; -static int ymargin = 0; -static int curfont = FONT_SYSFIXED; +static struct viewport default_vp = +{ + .x = 0, + .y = 0, + .width = LCD_REMOTE_WIDTH, + .height = LCD_REMOTE_HEIGHT, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .xmargin = 0, + .ymargin = 0, +}; +static struct viewport* current_vp IDATA_ATTR = &default_vp; + +/*** Viewports ***/ + +void lcd_remote_set_viewport(struct viewport* vp) +{ + if (vp == NULL) + current_vp = &default_vp; + else + current_vp = vp; +} + +void lcd_remote_update_viewport(void) +{ + lcd_remote_update_rect(current_vp->x, current_vp->y, + current_vp->width, current_vp->height); +} + +void lcd_remote_update_viewport_rect(int x, int y, int width, int height) +{ + lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height); +} + + /*** parameter handling ***/ void lcd_remote_set_drawmode(int mode) { - drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); + current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } int lcd_remote_get_drawmode(void) { - return drawmode; + return current_vp->drawmode; } void lcd_remote_setmargins(int x, int y) { - xmargin = x; - ymargin = y; + current_vp->xmargin = x; + current_vp->ymargin = y; } +int lcd_remote_getwidth(void) +{ + return current_vp->width; +} + +int lcd_remote_getheight(void) +{ + return current_vp->height; +} + int lcd_remote_getxmargin(void) { - return xmargin; + return current_vp->xmargin; } int lcd_remote_getymargin(void) { - return ymargin; + return current_vp->ymargin; } void lcd_remote_setfont(int newfont) { - curfont = newfont; + current_vp->font = newfont; } int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h) { - return font_getstringsize(str, w, h, curfont); + return font_getstringsize(str, w, h, current_vp->font); } /*** low-level drawing functions ***/ @@ -178,20 +219,37 @@ /*** drawing functions ***/ +/* Clear the current viewport */ +void lcd_remote_clear_viewport(void) +{ + unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; + + memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer); + + if (current_vp == &default_vp) + lcd_remote_scroll_info.lines = 0; + else + lcd_remote_scroll_stop(current_vp); +} + /* Clear the whole display */ void lcd_remote_clear_display(void) { - unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; + struct viewport* oldvp = current_vp; - memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer); - lcd_remote_scroll_info.lines = 0; + current_vp = &default_vp; + + lcd_remote_clear_viewport(); + + current_vp = oldvp; } /* Set a single pixel */ void lcd_remote_drawpixel(int x, int y) { - if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) - lcd_remote_pixelfuncs[drawmode](x, y); + if (((unsigned)x < (unsigned)current_vp->width) && + ((unsigned)y < (unsigned)current_vp->height)) + lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y); } /* Draw a line */ @@ -203,7 +261,7 @@ int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; - lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[drawmode]; + lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode]; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -247,8 +305,8 @@ for (i = 0; i < numpixels; i++) { - if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) - pfunc(x, y); + if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height)) + pfunc(x + current_vp->x, y + current_vp->y); if (d < 0) { @@ -268,7 +326,7 @@ /* Draw a horizontal line (optimised) */ void lcd_remote_hline(int x1, int x2, int y) { - int x; + int x, width; fb_remote_data *dst, *dst_end; unsigned mask; lcd_remote_blockfunc_type *bfunc; @@ -282,24 +340,30 @@ } /* nothing to draw? */ - if (((unsigned)y >= LCD_REMOTE_HEIGHT) || (x1 >= LCD_REMOTE_WIDTH) + if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) || (x2 < 0)) return; /* clipping */ if (x1 < 0) x1 = 0; - if (x2 >= LCD_REMOTE_WIDTH) - x2 = LCD_REMOTE_WIDTH-1; + if (x2 >= current_vp->width) + x2 = current_vp->width-1; - bfunc = lcd_remote_blockfuncs[drawmode]; + width = x2 - x1 + 1; + + /* Adjust x1 and y to viewport */ + x1 += current_vp->x; + y += current_vp->y; + + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y>>3][x1]; mask = 1 << (y & 7); - dst_end = dst + x2 - x1; + dst_end = dst + width; do bfunc(dst++, mask, 0xFFu); - while (dst <= dst_end); + while (dst < dst_end); } /* Draw a vertical line (optimised) */ @@ -319,17 +383,22 @@ } /* nothing to draw? */ - if (((unsigned)x >= LCD_REMOTE_WIDTH) || (y1 >= LCD_REMOTE_HEIGHT) + if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) || (y2 < 0)) return; /* clipping */ if (y1 < 0) y1 = 0; - if (y2 >= LCD_REMOTE_HEIGHT) - y2 = LCD_REMOTE_HEIGHT-1; + if (y2 >= current_vp->height) + y2 = current_vp->height-1; - bfunc = lcd_remote_blockfuncs[drawmode]; + /* adjust for viewport */ + y1 += current_vp->y; + y2 += current_vp->y; + x += current_vp->x; + + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y1>>3][x]; ny = y2 - (y1 & ~7); mask = 0xFFu << (y1 & 7); @@ -371,8 +440,8 @@ bool fillopt = false; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) - || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) + || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -386,27 +455,32 @@ height += y; y = 0; } - if (x + width > LCD_REMOTE_WIDTH) - width = LCD_REMOTE_WIDTH - x; - if (y + height > LCD_REMOTE_HEIGHT) - height = LCD_REMOTE_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; - if (drawmode & DRMODE_INVERSEVID) + /* adjust for viewport */ + x += current_vp->x; + y += current_vp->y; + + if (current_vp->drawmode & DRMODE_INVERSEVID) { - if (drawmode & DRMODE_BG) + if (current_vp->drawmode & DRMODE_BG) { fillopt = true; } } else { - if (drawmode & DRMODE_FG) + if (current_vp->drawmode & DRMODE_FG) { fillopt = true; bits = 0xFFu; } } - bfunc = lcd_remote_blockfuncs[drawmode]; + + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; dst = &lcd_remote_framebuffer[y>>3][x]; ny = height - 1 + (y & 7); mask = 0xFFu << (y & 7); @@ -466,8 +540,8 @@ lcd_remote_blockfunc_type *bfunc; /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) - || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) + if ((width <= 0) || (height <= 0) || (x >= current_vp->width) + || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) return; /* clipping */ @@ -483,11 +557,15 @@ src_y -= y; y = 0; } - if (x + width > LCD_REMOTE_WIDTH) - width = LCD_REMOTE_WIDTH - x; - if (y + height > LCD_REMOTE_HEIGHT) - height = LCD_REMOTE_HEIGHT - y; + if (x + width > current_vp->width) + width = current_vp->width - x; + if (y + height > current_vp->height) + height = current_vp->height - y; + /* adjust for viewports */ + x += current_vp->x; + y += current_vp->y; + src += stride * (src_y >> 3) + src_x; /* move starting point */ src_y &= 7; y -= src_y; @@ -495,13 +573,13 @@ shift = y & 7; ny = height - 1 + shift + src_y; - bfunc = lcd_remote_blockfuncs[drawmode]; + bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; mask = 0xFFu << (shift + src_y); mask_bottom = 0xFFu >> (~ny & 7); if (shift == 0) { - bool copyopt = (drawmode == DRMODE_SOLID); + bool copyopt = (current_vp->drawmode == DRMODE_SOLID); for (; ny >= 8; ny -= 8) { @@ -579,11 +657,11 @@ { unsigned short ch; unsigned short *ucs; - struct font* pf = font_get(curfont); + struct font* pf = font_get(current_vp->font); ucs = bidi_l2v(str, 1); - while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH) + while ((ch = *ucs++) != 0 && x < current_vp->width) { int width; const unsigned char *bits; @@ -637,24 +715,24 @@ int style, int offset) { int xpos,ypos,w,h,xrect; - int lastmode = drawmode; + int lastmode = current_vp->drawmode; /* make sure scrolling is turned off on the line we are updating */ - lcd_remote_scroll_info.lines &= ~(1 << y); + lcd_remote_scroll_stop_line(current_vp, y); if(!str || !str[0]) return; lcd_remote_getstringsize(str, &w, &h); - xpos = xmargin + x*w / utf8length((char *)str); - ypos = ymargin + y*h; - drawmode = (style & STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + xpos = current_vp->xmargin + x*w / utf8length((char *)str); + ypos = current_vp->ymargin + y*h; + current_vp->drawmode = (style & STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_remote_putsxyofs(xpos, ypos, offset, str); - drawmode ^= DRMODE_INVERSEVID; + current_vp->drawmode ^= DRMODE_INVERSEVID; xrect = xpos + MAX(w - offset, 0); - lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h); - drawmode = lastmode; + lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h); + current_vp->drawmode = lastmode; } /*** scrolling ***/ @@ -680,10 +758,13 @@ struct scrollinfo* s; int w, h; - if(y>=LCD_REMOTE_SCROLLABLE_LINES) return; + /* remove any previously scrolling line at the same location */ + lcd_remote_scroll_stop_line(current_vp, y); - s = &lcd_remote_scroll_info.scroll[y]; + if (lcd_remote_scroll_info.lines >= LCD_REMOTE_SCROLLABLE_LINES) return; + s = &lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines]; + s->start_tick = current_tick + lcd_remote_scroll_info.delay; s->style = style; if (style & STYLE_INVERT) { @@ -694,7 +775,7 @@ lcd_remote_getstringsize(string, &w, &h); - if (LCD_REMOTE_WIDTH - x * 8 - xmargin < w) { + if (current_vp->width - x * 8 - current_vp->xmargin < w) { /* prepare scroll line */ char *end; @@ -707,7 +788,7 @@ /* scroll bidirectional or forward only depending on the string width */ if ( lcd_remote_scroll_info.bidir_limit ) { - s->bidir = s->width < (LCD_REMOTE_WIDTH - xmargin) * + s->bidir = s->width < (current_vp->width - current_vp->xmargin) * (100 + lcd_remote_scroll_info.bidir_limit) / 100; } else @@ -720,17 +801,17 @@ } end = strchr(s->line, '\0'); - strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2); + strncpy(end, (char *)string, current_vp->width/2); + s->vp = current_vp; + s->y = y;; s->len = utf8length((char *)string); s->offset = offset; - s->startx = xmargin + x * s->width / s->len;; + s->startx = current_vp->xmargin + x * s->width / s->len;; s->backward = false; - lcd_remote_scroll_info.lines |= (1<start_tick)) continue; + current_vp = s->vp; + if (s->backward) s->offset -= lcd_remote_scroll_info.step; else s->offset += lcd_remote_scroll_info.step; - pf = font_get(curfont); + pf = font_get(current_vp->font); xpos = s->startx; - ypos = ymargin + index * pf->height; + ypos = current_vp->ymargin + s->y * pf->height; if (s->bidir) { /* scroll bidirectional */ if (s->offset <= 0) { @@ -768,9 +848,9 @@ s->backward = false; s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; } - if (s->offset >= s->width - (LCD_REMOTE_WIDTH - xpos)) { + if (s->offset >= s->width - (current_vp->width - xpos)) { /* at end of line */ - s->offset = s->width - (LCD_REMOTE_WIDTH - xpos); + s->offset = s->width - (current_vp->width - xpos); s->backward = true; s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; } @@ -781,13 +861,16 @@ s->offset %= s->width; } - lastmode = drawmode; - drawmode = (s->style&STYLE_INVERT) ? - (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; + lastmode = current_vp->drawmode; + current_vp->drawmode = (s->style&STYLE_INVERT) ? + (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line); - drawmode = lastmode; - lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height); + current_vp->drawmode = lastmode; + lcd_remote_update_viewport_rect(xpos, ypos, + current_vp->width - xpos, pf->height); } + + current_vp = old_vp; } /* LCD init */