summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-bitmap-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-bitmap-common.c')
-rw-r--r--firmware/drivers/lcd-bitmap-common.c180
1 files changed, 64 insertions, 116 deletions
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c
index c04f57ef22..f3e700a4a1 100644
--- a/firmware/drivers/lcd-bitmap-common.c
+++ b/firmware/drivers/lcd-bitmap-common.c
@@ -412,12 +412,10 @@ static void LCDFN(putsxyofs_style)(int xpos, int ypos,
/*** Line oriented text output ***/
-/* put a string at a given char position */
void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str,
int style, int x_offset, int y_offset)
{
int xpos, ypos, h;
- LCDFN(scroll_stop_viewport_line)(current_vp, y);
if(!str)
return;
@@ -425,14 +423,15 @@ void LCDFN(puts_style_xyoffset)(int x, int y, const unsigned char *str,
if ((style&STYLE_XY_PIXELS) == 0)
{
xpos = x * LCDFN(getstringsize)(" ", NULL, NULL);
- ypos = y * h + y_offset;
+ ypos = y * h;
}
else
{
xpos = x;
- ypos = y + y_offset;
+ ypos = y;
}
- LCDFN(putsxyofs_style)(xpos, ypos, str, style, h, x_offset);
+ LCDFN(scroll_stop_viewport_rect)(current_vp, x, y, current_vp->width - x, h);
+ LCDFN(putsxyofs_style)(xpos, ypos+y_offset, str, style, h, x_offset);
}
void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str,
@@ -469,7 +468,7 @@ void LCDFN(puts_offset)(int x, int y, const unsigned char *str, int offset)
/*** scrolling ***/
-static struct scrollinfo* find_scrolling_line(int line)
+static struct scrollinfo* find_scrolling_line(int x, int y)
{
struct scrollinfo* s = NULL;
int i;
@@ -477,93 +476,101 @@ static struct scrollinfo* find_scrolling_line(int line)
for(i=0; i<LCDFN(scroll_info).lines; i++)
{
s = &LCDFN(scroll_info).scroll[i];
- if (s->y == line && s->vp == current_vp)
+ if (s->x == x && s->y == y && s->vp == current_vp)
return s;
}
return NULL;
}
-void LCDFN(puts_scroll_style_xyoffset)(int x, int y, const unsigned char *string,
- int style, int x_offset, int y_offset)
+void LCDFN(scroll_fn)(struct scrollinfo* s)
+{
+ LCDFN(putsxyofs_style)(s->x, s->y, s->line, s->style, s->height, s->offset);
+}
+
+static void LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string,
+ int style, int x_offset, int y_offset,
+ bool linebased,
+ void (*scroll_func)(struct scrollinfo *),
+ void *data)
{
struct scrollinfo* s;
- char *end;
- int w, h;
- int len;
- bool restart = false;
- int space_width;
+ int width, height;
+ int w, h, cwidth, margin;
+ bool restart;
- if (!string || ((unsigned)y >= (unsigned)current_vp->height))
+ if (!string)
return;
- s = find_scrolling_line(y);
- if (!s)
- restart = true;
+ /* prepare rectangle for scrolling. x and y must be calculated early
+ * for find_scrolling_line() to work */
+ cwidth = font_get(current_vp->font)->maxwidth;
+ height = current_vp->line_height ?: (int)font_get(current_vp->font)->height;
+ y = y * (linebased ? height : 1) + y_offset;
+ x = x * (linebased ? cwidth : 1);
+ width = current_vp->width - x;
- if (restart)
- {
+ if (y >= current_vp->height)
+ return;
+
+ s = find_scrolling_line(x, y);
+ restart = !s;
+
+ if (restart) {
/* remove any previously scrolling line at the same location */
- LCDFN(scroll_stop_viewport_line)(current_vp, y);
+ LCDFN(scroll_stop_viewport_rect)(current_vp, x, y, width, height);
+ LCDFN(putsxyofs_style)(x, y, string, style, height, x_offset);
- if (LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES)) return;
- LCDFN(puts_style_xyoffset)(x, y, string, style, x_offset, y_offset);
+ if (LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES))
+ return;
}
+ /* get width (pixeks) of the string */
LCDFN(getstringsize)(string, &w, &h);
- if (current_vp->width - x * 8 >= w)
+ /* check if scrolling is actually necessary (consider the actual start
+ * of the line) */
+ margin = x * linebased ? cwidth : 1;
+ if (current_vp->width >= margin+w)
return;
- if (restart)
- {
+ if (restart) {
/* prepare scroll line */
s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines];
s->start_tick = current_tick + LCDFN(scroll_info).delay;
}
- strlcpy(s->line, string, sizeof s->line);
- space_width = LCDFN(getstringsize)(" ", NULL, NULL);
- /* get width */
- LCDFN(getstringsize)(s->line, &w, &h);
- if (!restart && s->width > w)
- {
- if (s->startx > w)
- s->startx = w;
- }
- s->width = w;
-
- /* scroll bidirectional or forward only depending on the string
- width */
+ /* copy contents to the line buffer */
+ strlcpy(s->linebuffer, string, sizeof(s->linebuffer));
+ /* scroll bidirectional or forward only depending on the string width */
if ( LCDFN(scroll_info).bidir_limit ) {
- s->bidir = s->width < (current_vp->width) *
+ s->bidir = w < (current_vp->width) *
(100 + LCDFN(scroll_info).bidir_limit) / 100;
}
else
s->bidir = false;
- if (!s->bidir) { /* add spaces if scrolling in the round */
- strlcat(s->line, " ", sizeof s->line);
- /* get new width incl. spaces */
- s->width += space_width * 3;
- }
-
- end = strchr(s->line, '\0');
- len = sizeof s->line - (end - s->line);
- strlcpy(end, string, MIN(current_vp->width/2, len));
+ s->scroll_func = scroll_func;
+ s->userdata = data;
- s->vp = current_vp;
- s->y = y;
- if (restart)
- {
+ if (restart) {
s->offset = x_offset;
- s->startx = x * space_width;
s->backward = false;
s->style = style;
+ /* assign the rectangle. not necessary if continuing an earlier line */
+ s->x = x;
+ s->y = y;
+ s->width = width;
+ s->height = height;
+ s->vp = current_vp;
+ LCDFN(scroll_info).lines++;
}
- s->y_offset = y_offset;
+}
- if (restart)
- LCDFN(scroll_info).lines++;
+void LCDFN(puts_scroll_style_xyoffset)(int x, int y, const unsigned char *string,
+ int style, int x_offset, int y_offset)
+{
+ LCDFN(puts_scroll_worker)(x, y, string, style, x_offset, y_offset,
+ true, LCDFN(scroll_fn), NULL);
}
void LCDFN(puts_scroll)(int x, int y, const unsigned char *string)
@@ -583,65 +590,6 @@ void LCDFN(puts_scroll_offset)(int x, int y, const unsigned char *string,
LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset);
}
-void LCDFN(scroll_fn)(void)
-{
- struct scrollinfo* s;
- int index;
- int xpos, ypos, height;
- struct viewport* old_vp = current_vp;
- bool makedelay;
-
- for ( index = 0; index < LCDFN(scroll_info).lines; index++ ) {
- s = &LCDFN(scroll_info).scroll[index];
-
- /* check pause */
- if (TIME_BEFORE(current_tick, s->start_tick))
- continue;
-
- LCDFN(set_viewport)(s->vp);
- height = s->vp->line_height ?: (int)font_get(s->vp->font)->height;
-
- if (s->backward)
- s->offset -= LCDFN(scroll_info).step;
- else
- s->offset += LCDFN(scroll_info).step;
-
- xpos = s->startx;
- ypos = s->y * height + s->y_offset;
-
- makedelay = false;
- if (s->bidir) { /* scroll bidirectional */
- if (s->offset <= 0) {
- /* at beginning of line */
- s->offset = 0;
- s->backward = false;
- makedelay = true;
- }
- else if (s->offset >= s->width - (current_vp->width - xpos)) {
- /* at end of line */
- s->offset = s->width - (current_vp->width - xpos);
- s->backward = true;
- makedelay = true;
- }
- }
- else {
- /* scroll forward the whole time */
- if (s->offset >= s->width) {
- s->offset = 0;
- makedelay = true;
- }
- }
-
- if (makedelay)
- s->start_tick = current_tick + LCDFN(scroll_info).delay +
- LCDFN(scroll_info).ticks;
-
- LCDFN(putsxyofs_style)(xpos, ypos, s->line, s->style, height, s->offset);
- LCDFN(update_viewport_rect)(xpos, ypos, current_vp->width-xpos, height);
- }
- LCDFN(set_viewport)(old_vp);
-}
-
void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string,
int style, int x_offset)
{