1
0
Fork 0
forked from len0rd/rockbox
foxbox/firmware/drivers/lcd-scroll.c
William Wilgus 660fa3ffdc scroll engine calculate stringsize only when scroll line updated
we calculate the size of the scrolling line every scroll update
the line data doesn't ever change without a call to update
instead calculate the string size when the line is updated
re-use this value while scrolling the line

in theory the current font could change but in practice
I can't find a case when the string size needs to be updated
that the scroll engine isn't already updating the line

if this is later an issue we can recalculate the stringsize each time
the line is finished scrolling which still saves quite a few calculations

Other:
I don't think we have any targets with pixel counts exceeding 65535 pixels
where unsigned short stringsize will be an issue

Change-Id: I83d6374377ed648d9a320d4fd69f9d6a17095b0c
2024-12-20 10:31:46 -05:00

238 lines
7.2 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 by Michael Sevakis
*
* LCD scroll control functions (API to apps).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
/* This file is meant to be #included by scroll_engine.c (twice if a remote
* is present) */
#ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
#define LCDFN(fn) lcd_ ## fn
#define LCDM(ma) LCD_ ## ma
#define MAIN_LCD
#endif
#if !defined(BOOTLOADER)
static struct scrollinfo LCDFN(scroll)[LCDM(SCROLLABLE_LINES)];
struct scroll_screen_info LCDFN(scroll_info) =
{
.scroll = LCDFN(scroll),
.lines = 0,
.ticks = 12,
.delay = HZ/2,
.bidir_limit = 50,
.step = 6,
};
void LCDFN(scroll_stop)(void)
{
for (int i = 0; i < LCDFN(scroll_info).lines; i++)
{
/* inform scroller about end of scrolling */
struct scrollinfo *s = &LCDFN(scroll_info).scroll[i];
s->line = NULL;
s->scroll_func(s);
}
LCDFN(scroll_info).lines = 0;
}
/* Clears scrolling lines that intersect with the area */
void LCDFN(scroll_stop_viewport_rect)(const struct viewport *vp, int x, int y, int width, int height)
{
int i = 0;
while (i < LCDFN(scroll_info).lines)
{
struct scrollinfo *s = &LCDFN(scroll_info).scroll[i];
/* check if the specified area crosses the viewport in some way */
if (s->vp == vp
&& (x < (s->x+s->width) && (x+width) > s->x)
&& (y < (s->y+s->height) && (y+height) > s->y))
{
/* inform scroller about end of scrolling */
s->line = NULL;
s->scroll_func(s);
/* If i is not the last active line in the array, then move
the last item to position i. This compacts
the scroll array at the same time of removing the line */
if ((i + 1) != LCDFN(scroll_info).lines)
{
LCDFN(scroll_info).scroll[i] =
LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines-1];
}
LCDFN(scroll_info).lines--;
}
else
{
i++;
}
}
}
/* Stop all scrolling lines in the specified viewport */
void LCDFN(scroll_stop_viewport)(const struct viewport *vp)
{
LCDFN(scroll_stop_viewport_rect)(vp, 0, 0, vp->width, vp->height);
}
void LCDFN(scroll_speed)(int speed)
{
LCDFN(scroll_info).ticks = scroll_tick_table[speed];
}
void LCDFN(scroll_step)(int step)
{
LCDFN(scroll_info).step = step;
}
void LCDFN(scroll_delay)(int ms)
{
LCDFN(scroll_info).delay = ms / (HZ / 10);
}
void LCDFN(bidir_scroll)(int percent)
{
LCDFN(scroll_info).bidir_limit = percent;
}
/* This renders the scrolling line described by s immediatly.
* This can be called to update a scrolling line if the text has changed
* without waiting for the next scroll tick
*
* Returns true if the text scrolled to the end */
bool LCDFN(scroll_now)(struct scrollinfo *s)
{
int width = s->line_stringsize; /* Calculated by LCDFN puts_scroll_worker() */
/*int width = font_getstringsize(s->linebuffer, NULL, NULL, s->vp->font);*/
bool ended = false;
/* assume s->scroll_func() don't yield; otherwise this buffer might need
* to be mutex'd (the worst case would be minor glitches though) */
static char line_buf[SCROLL_LINE_SIZE];
if (s->bidir)
{ /* scroll bidirectional */
s->line = s->linebuffer;
if (s->offset <= 0) {
/* at beginning of line */
s->offset = 0;
s->backward = false;
ended = true;
}
else if (s->offset >= width - s->width) {
/* at end of line */
s->offset = width - s->width;
s->backward = true;
ended = true;
}
}
else
{
snprintf(line_buf, sizeof(line_buf)-1, "%s%s%s",
s->linebuffer, " ", s->linebuffer);
s->line = line_buf;
width += font_getstringsize(" ", NULL, NULL, s->vp->font) * 3;
/* scroll forward the whole time */
if (s->offset >= width) {
s->offset = 0;
ended = true;
}
}
/* Stash and restore these four, so that the scroll_func
* can do whatever it likes without destroying the state */
struct frame_buffer_t *framebuf = s->vp->buffer;
unsigned drawmode;
#if LCD_DEPTH > 1
unsigned fg_pattern, bg_pattern;
fg_pattern = s->vp->fg_pattern;
bg_pattern = s->vp->bg_pattern;
#endif
drawmode = s->vp->drawmode;
s->scroll_func(s);
LCDFN(update_viewport_rect)(s->x, s->y, s->width, s->height);
#if LCD_DEPTH > 1
s->vp->fg_pattern = fg_pattern;
s->vp->bg_pattern = bg_pattern;
#endif
s->vp->drawmode = drawmode;
s->vp->buffer = framebuf;
return ended;
}
static void LCDFN(scroll_worker)(void)
{
int index;
struct scroll_screen_info *si = &LCDFN(scroll_info);
struct viewport *oldvp;
if (global_settings.disable_mainmenu_scrolling
&& get_current_activity() == ACTIVITY_MAINMENU) {
/* No scrolling on the main menu if disabled
(to not break themes with lockscreens) */
return;
}
for ( index = 0; index < si->lines; index++ )
{
struct scrollinfo *s = &si->scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->start_tick)) {
continue;
}
s->start_tick = current_tick;
if (s->backward)
s->offset -= si->step;
else
s->offset += si->step;
/* this runs out of the ui thread, thus we need to
* save and restore the current viewport since the
* ui thread is unaware of the swapped viewports. */
oldvp = LCDFN(set_viewport_ex)(s->vp, 0); /* don't mark the last vp as dirty */
/* put the line onto the display now */
bool makedelay = LCDFN(scroll_now(s));
if (makedelay)
{
#if 0 /* haven't found a case in which this matters .. yet?? --Bilgus */
/* re-calculate stringsize in case the font changed */
s->line_stringsize = font_getstringsize(s->linebuffer, NULL, NULL, s->vp->font);
#endif
s->start_tick += si->delay + si->ticks;
}
#ifdef SIMULATOR /* Bugfix sim won't update screen unless called from active thread */
LCDFN(set_viewport)(oldvp);
#else
LCDFN(set_viewport_ex)(oldvp, 0); /* don't mark the last vp as dirty */
#endif
}
}
#endif /*!BOOTLOADER*/