release
dev builds
extras
themes manual
wiki
device status forums
mailing lists
IRC bugs
patches
dev guide



Search | Go
Wiki > Main > RockboxFAQ > CategoryFrontpage > ViewPorts > ViewPortsDesign

A Proposal for how Viewports could be implemented

(by DaveChapman. A patch is available at FS#8385)

Viewports Design

A Viewport is simply a C struct containing the LCD state. It is defined as follows:

struct viewport {
    int x;
    int y;
    int width;
    int height;
    int font;
    int drawmode;
#if LCD_DEPTH > 1
    unsigned fg_pattern;
    unsigned bg_pattern;
#endif
}

The basic principle is that the Rockbox apps/ code will statically declare the various viewports it needs, and set the current viewport used by the LCD driver functions with the function:

void lcd_set_viewport(struct viewport* vp);

All the existing LCD functions will change their behaviour so that they only draw within the boundary of the viewport, and will use the current font, drawmode and colours defined in that viewport. (x,y) co-ordinates passed to the LCD functions will always be relative to the current viewport.

Functions such as lcd_set_drawmode, lcd_set_background will set values in the current viewport.

We will want to define a transparency color to be used as foreground or background color so that the common backdrop can show through / is not obscured by the viewport -- PeterDHoye - 18 Dec 2007

Default viewport

A default viewport covering the entire screen will be declared in the LCD driver. A call to lcd_set_viewport(NULL) will set this default viewport to be current.

Scrolling lines

Scrolling lines in Rockbox currently use the LCD state (line style, margin) current at the time that lcd_puts_scroll() was called. The x position is specified by the lcd_puts_scroll() function (and is stored, added to the current left margin).

Which lines are currently scrolling is stored as a bit-pattern in screen_scroll_info.lines (the maximum number of scrolling lines any target can have is 32).

There is an array of up to 32 scrolling lines, and these lines represent the first 32 lines (based on current font height) on the screen - so the y positioning is implied by the index into the lines[] array.

This won't work with viewports, as viewports can be positioned at arbitrary positions on the screen. It is also hoped that at some point in the future, Rockbox will have support for multiple fonts, so lines can vary in height depending on the font used.

QUESTION? We can clear the scrolling lines for the current viewport when lcd_clear_display is called, but if the apps/ code switches to a new set of viewports, lcd_clear_display will never be called on the old viewports, so the lines will remain active...

Maybe an "void lcd_stop_scrolling(struct viewport* vp);" function which would destroy all scrolling lines related to that viewport? This function would also be called by lcd_clear_display();

struct scrollinfo
{
    char line[SCROLL_LINE_SIZE];
    int len;    /* length of line in chars */
    int offset;
    int startx;
#ifdef HAVE_LCD_BITMAP
    int width;  /* length of line in pixels */
    int style; /* line style */
#endif/* HAVE_LCD_BITMAP */
    bool backward; /* scroll presently forward or backward? */
    bool bidir;
    long start_tick;
};

to being:

struct scrollinfo
{
    char line[SCROLL_LINE_SIZE];
    int len;    /* length of line in chars */
    int offset;
#ifdef HAVE_LCD_BITMAP
    int width;  /* length of line in pixels */
    int style; /* line style */
#endif/* HAVE_LCD_BITMAP */
    bool backward; /* scroll presently forward or backward? */
    bool bidir;
    long start_tick;
    struct viewport* vp;  /* pointer to parent viewport */
};

The tick function that performs the scrolling will save the pointer to the current viewport, set the scrolling line's viewport as current, draw the line, then restore the old viewport.

Problems:

  1. If we want pop-up windows, then we want to be able to stop the scrolling lines of the underlying viewport(s) without clearing the display - something like: void lcd_scrolling_startstop (bool start); ?
  2. When a viewport is cleared, all scrolling lines for that viewport also need to be cleared. To do this, we need to remember the pointer to the viewport.

Backdrop handling

Backdrops will continue to be global and cover the entire LCD. However, there may be a desire for the ability to specify more backdrops than currently available - maybe use buffer_alloc() to store them on the audio buffer at boot time?

viewports in apps/ code

Multi-screen API

How can viewports be used with the multi-screen API?

[to-do]

List widget

The majority of the screens in Rockbox are based on the list widget, which has the following layout, with most elements being optional.

  1. List title - full screen width
  2. Scrollbar - potential to move to left/right side of screen. The scrollbar only appears when needed.
  3. Icons - potential to move to right side of screen for RTL text. Not supported in all lists (e.g. settings lists), and can also be disabled by users in the lists that support them.
  4. Arrow cursor - potential to move to right side of screen for RTL text
  5. List Content - the main content of the list.

We could either implement separate viewports for all five elements, or perhaps combine some, such as the scrollbar, icons and cursor.

It would be desirable to be able to specify a rectangle of the screen to be filled by a list widget when it's created. This would allow themes to specify the location/size of the widget, such as centering the main menu in a background (top/bottom/left/right margins). It would also allow "pop-up" menus to be created that don't fill the whole screen.

The list widget would then arrange the viewports to fill the area of the screen given to it.

Splashes

Splashes could initially just use the global "whole-screen" viewport, but it might be desirable to allow scrolling text within the splash, and a splash viewport would allow that.

QuickScreen

Would be redesigned to exploit viewports.

Radio screen

Initially could use a whole-screen (minus status-bar) viewport, but could be reimplemented to make use of viewports.

Recording screen

Initially could use a whole-screen (minus status-bar) viewport, but could be reimplemented to make use of viewports.

USB screen

Just use default viewport?

Yes/no dialog

This could be rewritten to use viewports and become a "pop-up" dialog. Either using a small list widget in the centre of the screen, or a new UI.

Button bar

viewport for each button? Do we want scrolling text in the button bar?

WPS

WPS syntax will need to be extended to allow the user to declare viewports, with the full set of attributes, and then to specify the content of each viewport.

A viewport declaration may look like this:

%v[A-Z]|x|y|width|height|fgcolor|bgcolor|

(can be extended with other attributes in the future, such as font size/face (if multiple font support is added)

A limit on the number of viewports will be needed, as these will be declared statically in the WPS code.

Currently, each line in the WPS can have one of the following attributes:

#define WPS_REFRESH_STATIC          1    /* line doesn't change over time */
#define WPS_REFRESH_DYNAMIC         2    /* line may change (e.g. time flag) */
#define WPS_REFRESH_SCROLL          4    /* line scrolls */
#define WPS_REFRESH_PLAYER_PROGRESS 8    /* line contains a progress bar */
#define WPS_REFRESH_PEAK_METER      16   /* line contains a peak meter */

When the WPS is parsed, it is stored in the wps_data struct as follows:

int num_lines;
struct wps_line lines[WPS_MAX_LINES]

int num_sublines
struct wps_subline sublines[WPS_MAX_LINES]

The wps_line struct just has pointers into the sublines array, along with curr_subline and num_sublines variables (signed chars).

The wps_subline struct contains a pointer to the first token in the WPS token array, the line_type variable (bit or'ed WPS_REFRESH_* values).

The main WPS drawing function (gui_wps_refresh) iterates through all lines in the WPS, refreshing them according to the type of refresh passed as a parameter to this function.

A new "viewport level" could be added to wps_data, so a WPS would then consist of a number of viewports, each containing a number of lines. The gui_wps_refresh() function would then have a new outer-loop iterating over the viewports, calling lcd_set_viewport() on each viewport in turn.

This would make the viewport refresh order known to the WPS writer (viewports are refreshed in the order declared, and then there would simply be a new %V[A-Z] tag in the WPS which means that "all lines up to the next %V tag belong to this viewport".

An implicit viewport would be defined to cover the entire screen, and all lines up to the first %V tag would be drawn in this viewport. This would maintain backwards-compatibility with WPSs not using viewports - apart from those using the %m tag, which will be removed.

There may be a desire for viewports to be conditional - e.g. if album-art is present, lay out the screen in one way, otherwise lay it out in another way. This could be dealt with by allowing a conditional tag on its own line which includes %V tags and nothing else. e.g. to switch viewports based on the presence of album-art the WPS would contain:

?%C<%VA|%VB> [code for both viewports]

OR:

?%C<%VA|> [Code only for album art present]

?%C<|%VB> [Code only for no album art present]

QUESTION? Is this straightforward to implement? Do we need the second ability, or can that be dealt with by further use of %C within the content code of the viewport?

Status bar

There will be a status bar viewport used throughout core Rockbox. If the status bar is disabled, then the other viewports need to expand to fill the screen.

IDEA! Should we integrate the status bar as a special viewport within the WPS (use numbers 0-9 to specify system viewports, letters for user viewports?), allowing the full WPS syntax in the status bar. The status bar drawing code would be replaced with a call to the WPS code, telling it to refresh the content of the statusbar viewport only. Conditionals based on a "current screen" tag could perhaps be used to customise the status bar for different screens. A "current screen" string could also be defined to be displayed in the status bar viewport - Main menu, Now Playing etc

Maybe the status bar would need to be multiple viewports - to allow scrolling text, as well as icons.

This could be done by giving a "type" to viewports defined in the WPS. So we would have TYPE_STATUSBAR, TYPE_WPS (others?) and a call to the wps_refresh() function would update all viewports with the specified type. This would allow statusbar information to be located anywhere on the screen.

QUESTION? Would we want to be able to merge the list title and status bar?

r7 - 02 Apr 2021 - 20:46:07 - UnknownUser

Copyright © by the contributing authors.