[% pagetitle = 'Display API' %] [% techinfo = '1' %] [% lefttoright = '1' %] [% PROCESS helpheader.html %]

#### Display Hash

The format of the display hash for 7.0 is the same as for 6.5.

The standard 2 line display with 2 overlays is described as:

    my $hash = {
       'line'    => [ 'Text to appear on top line',
                      'Text to appear on bottom line and possibly scroll' ],
       'overlay' => [ 'Overlay to appear at right of top line',
                      'Overlay to appear at right of bottom line' ],
    }

Arrays are used for each component of the display as the rendering code supports more than 2 lines of text. This is restricted to 2 lines for SBG and 3 for SB2/SB3/Tranporter at present [requires appropriate fonts]. For example:

    my $hash = {
       'line'    => [ 'Line1',
                      'Line2',
                      'Line3' ],
    }

The examples given on the rest of this page only include 2 lines, but 3 lines may be used for all line, overlay and center components.

Note that scrolling is possible on any line of the display if it is too long, but this is disabled for the top line.

Centered text is described as:

    my $hash = {
       'center' => [ 'Text to be centered on line 1',
                     'Text to be centered on bottom line' ],
    }

Symbols are typically displayed in one of the overlays but can exist in any component. Individual symbols can be added to the hash using $client->symbols():

    my $hash = {
       'line'    => [ 'Text to appear on top line',
                      'Text to appear on bottom line and possibly scroll' ],
       'overlay' => [ $client->symbols('notesymbol') ],
    }

See $client->symbols() below for valid symbol names.

6.5 added support for 2 screens for use with Transporter players. The second display is described within the 'screen2' hash component. Screen 1 may be described at the root of the hash, or within a 'screen1' component:

    my $hash = {
       'line'    => [ 'Screen 1 Line 1',
                      'Screen 1 Line 2' ],
       'screen2' => {
           'line' => [ 'Screen 2 Line 1',
                       'Screen 2 Line 2' ]
       }
    }

or

    my $hash = {
       'screen1' => {
           'line'    => [ 'Screen 1 Line 1',
                          'Screen 1 Line 2' ],
       },
       'screen2' => {
           'line' => [ 'Screen 2 Line 1',
                       'Screen 2 Line 2' ]
       }
    }

As screen1 may appear at the root of the hash, the empty hash represents a blank screen1.

##### Player Specifics

All player types are intended to display in as similar way as possible. However there are some specifics due to the limited screen resolution of some hardware:

Text Displays (Slimp3/Squeezebox):

In two line mode overlays are displayed. If center exists for a line then this takes precedence over line such that only the centered text and overlay are displayed.

Overlays truncate line so that the overlay is always displayed. In the case of line[0], text is simply truncated so the overlay fits. In the case of line[1], text will potentially scroll within the region of the screen to the left of overlay[1]. Centered text will also be truncated by overlays if they appear in the same position.

In single line mode overlays are not displayed by default. Again centered text takes precedence such that if center[1] exists then line[1] will not be displayed.

Graphic Displays (Squeezebox-Graphics, Squeezebox2/3, Transporter):

Graphics players attempt to display all components at the same time, so that both center and line are displayed. Overlays truncate line in the same way as for text players. However centered text is not truncated by the overlays. As the resulting bitmaps for each text component are displayed on top of each other, it is the calling function's responsibility to avoid overlapping text - e.g. centered text overlapping overlays.

##### Bitmaps

Graphics players may also display a bitmap:

    my $hash = {
       'bits' => $bitmap,
    }

Where $bitmap is a byte string which defines a bitmap of appropriate size for the display. The bitmap will be displayed on top of any other text defined in the same display hash.

Squeezebox 1 G takes a 280 x 2 byte bitmap, with the first byte defining the top 8 bits of the left most display column the second byte defining the lower 8 bits. The 3rd & 4th byte describe the second column etc.

Squeezebox 2, 3 & Transporter take a 320 x 4 byte bitmap, with the first byte defining the top 8 bits of the first column, the next 3 defining the rest of the first column etc.

##### Fonts

The display hash can define a font element to define the font to be used for a display. If it exists it takes precedence over the current font for the player.

A simple font element is used to define a single font to use for all components of the display:

    my $hash = {
       'line' => [ 'Text to appear on top line',
                   'Text to appear on bottom line and possibly scroll' ],
       'fonts' => {
           'graphic-320x32' => 'standard',
           'graphic-280x16' => 'small',
           'text'           => 2,
       }
    }

As different player use different fonts, it is normal to define the font for each type of player:

- 'graphic-320x32' is the font used for Squeezebox2/3/Transporter
- 'graphic-280x16' is the font used for Squeezebox1-Graphics
- 'text' defines the number of lines to display on Slimp3/Squeezebox1

The font element may also take a more detailed definition to allow more complex displays to be defined.

For graphics players, the specific font for each of line/overlay/center can defined. If the font for only some components are defined, other components take the current active font for the player.

The following fixes the font for overlay[0], but leaves all other fonts as the currently active player font:

    my $hash = {
       ...
       'fonts' => {
           'graphic-280x16'  => { 'overlay' => [ 'small.1' ] },
           'graphic-320x32'  => { 'overlay' => [ 'standard.1' ] },
           }
    }

Note: the font name should be the font file name including the line number. It is specified as a string (rather than a reference to a string, as used in the 6.2 hash.)

By setting non standard fonts for each component it is possible to create new types of display. Care should be taken in setting the overlay fonts to match the line font as the point at which lines are truncated is based on the respective overlays.

For text players, the font element may define the number of lines and also force display of overlays in single line mode:

    my $hash = {
       ...
       'fonts' => {
           'text'  => { 'lines' => 1,
                        'displayoverlays' => 1
    		  },
           }
    }

- 'lines' defines whether 1 line (doubled) or 2 line mode should be used.
- 'displayoverlays' set to 1 forces overlays to be displayed in two line, mode.

##### Scrolling

For all players, text in line[1] will scroll if it is too long to fit into the space to the left of overlay[1]. With 7.0/6.5 on graphic players, scrolling may also occur on line[2]. The default operation of scrolling for a player is set via preference 'scrollMode', but can be overridden by the parameter sent to update. It is no longer overridden by a component in the display hash.

Normal scrolling of line[1] shows as much of line[1] as will fit to the left of overlay[1]. This is displayed without scrolling for the 'scrollPause' interval. Line[1] then rotates to the point when the start of line[1] is displayed again. At this point the display pauses again before continuing the rotation. With 7.0/6.5 scrolling may be either right to left or left to right. This is automatically selected so that Hebrew text scrolls left to right.

During scrolling, if update is called with a display hash which changes non scrolling components these are updated without interrupting scrolling. This allows scrolling to continue while elapsed times etc are updated, for example in the Now Playing screen.

##### Ticker Scrolling

Ticker scrolling is designed to be used by screensavers such as the RssNews. It changes the scrolling operation to that of a ticker display - text appears from the right edge, scrolls across the screen and off the left side. It does not rotate in the manner of normal scrolling.

With 7.0/6.5 ticker scrolling supports scrolling on any line of the display and uses a new component of the display hash. Items are added o the ticker by calling update with a display hash such as:

    my $hash = {
       'line'  => [ 'Non scrolling top line' ],
       'ticker => [ undef, 'New item to be added to ticker' ],
    }

Note that the hash should not define text for a line[x] if it also defines text for ticker[x] as both will be displayed at once.

If line/overlay components change during ticker mode these are displayed immediately. However text defined in the ticker component will be added to the ticker queue and will appear once items currently in the ticker queue have been displayed.

The function: $client->scrollTickerTimeLeft() [$client->display->scrollTickerTimeLeft()] is used to find the current length of the ticker queue and is used to optimise when new items are added to the queue:

    my ($complete, $queue) = $client->scrollTickerTimeLeft();

Where $complete is the approx number of seconds left before all text disappears off the left hand side of the display. $queue is the approx number of seconds worth of text which is queued up but has not yet appeared on the right edge of the display.

A lines function may use this to decide whether to return undef or text for a ticker component. If undef is returned, nothing is added to the ticker queue allowing it to drain.

For example to maintain a ticker using a lines function which is called once per second:

    sub lines {
       my $client = shift;
       my ($complete, $queue) = $client->scrollTickerTimeLeft();

       my $text = 'Whatever you want to add to the ticker';

       return( {
          'line'   => [ 'Fixed top line' ],
          'ticker' => [ undef, ($queue < 1) ? $text : undef ],
       });
    }

#### Display Functions

As of 7.0/6.5 all display functions are methods of the display object rather than the client object. The display object is stored in the client object and is returned by $client->display().

All common display methods may still be accessed via client methods as wrappers are included to call the display object. Note however if you call display functions which are not part of the api below, these methods will have moved to the display object.

Displays are sent to the screen via one of the display functions:

##### $client->update()

This is the normal way of updating the display. Updated is normally called with no params and in this case the lines function registered for the current mode is called to determine the display hash.

Update can be called with a display hash to display something other than the current lines immediately:

    $client->update( {
       'line' => [ 'line 1 display',
                   'line 2 display' ],
    } );

However as the server may call $client->update() to refresh the display this is not recommended. It is normal to use the lines function to return the display and call $client->update() to use it.

If a plugin wishes to update the display on a regular basis, this is best done by setting the following in the setMode function:

    $client->param('modeUpdateInterval', X);

Where X defines the number of seconds between each update. The server will automatically call update every X seconds whilst in this mode.

##### $client->showBriefly()

This is used to display a message on the screen for a short period of time, before returning to the normal display of the mode.

showBriefly should always be called with a display hash and one or more optional parameters. The optional parameters may either be positional parameters or named parameters in a parameter hash.

    $client->showBriefly($hash, $duration, $firstline, $blockupdate, $scrolltoend, $brightness, $callback, $callbackargs)
    or
    $client->showBriefly($hash,
                         { 'duration'     => $duration,
                           'firstline'    => $firstline,
                           'block'        => $blockupdate,
                           'scroll'       => $scrolltoend,
                           'brightness'   => $brightness,
                           'callback'     => $callback,
                           'callbackargs' => $callbackargs } )

- $hash - the display hash
- $duration - number of seconds to display for (defaults to 1)
- $firstline - display only line[0] if in single line mode (otherwise displays line[1] in single line mode)
- $blockupdate - block display so that calls to update during $duration do not cancel the showBriefly display (defaults to false)
- $scrolltoend - if line is too long scroll display and continue until whole line is seen. This overrides duration.
- $brightness - brightness to display at ('powerOn', 'powerOff', 'idle' or brightness value)
- $callback - function to call when animation is done, including scrolling.
- $callbackargs - callback arguments.

For example:

    $client->showBriefly( {
       'line'       => [ $line1, $line2 ],
       'overlay'    => [ $client->symbols('notesymbol') ],
    }, { 'duration' => 5, 'block' => 1 } );

Displays two lines plus an overlay for 5 seconds and is not cancelled by updates during this time.

Note that as showBriefly now takes a display hash, there is no need to use $client->renderOverlay() to build a display to send to showBriefly

##### $client->block()

This is used to display a message for a period of time with a spinning activity notification in overlay[0]. The message is displayed using the 'block' mode so that it is not interrupted and is only cleared by a call to $client->unblock().

    $client->block($hash)

- $hash - display hash

For example:

    $client->block( {
       'line' => [ string('PLAYER_NEEDS_UPGRADE_1'),
                   string('PLAYER_NEEDS_UPGRADE_2') ],
       'fonts' => {
          'graphic-320x32' => 'standard',
          'graphic-280x16' => 'small',
          'text'           => 2,
          }
    });

This forces the font so that two lines are displayed and displays two strings until $client->unblock() is called.

[block also takes $line1, $line2 for backwards compatibility]

##### Lines

A mode's lines function should return the display hash to display when $client->update() is called.

A simple lines function would be:

    sub lines {
        my $client = shift;

        return {
           'line'    => [ 'Line1 text',
                          'Line2 text' ],
           'overlay' => [ $client->symbols('notesymbol') ],
        };
    }

A more complex lines function which specifies the fonts would be:

    sub lines {
        my $client = shift;
        my $args   = shift;

        return {
           'line'      => [ 'Line1 text', 'Line2 text' ],
           'overlay'   => [ $client->symbols('bell') ],
           'fonts'      => {
               'graphic-280x16'  => { 'overlay' => [ 'small.1' ] },
               'graphic-320x32'  => { 'overlay' => [ 'standard.1' ] },
               'text' =>            { 'lines' => 2,
                                      'displayoverlays' => 1,
                                      },
               },
        };
    }

Note: A lines function which returns a display hash is responsible for converting symbol names to symbol characters. The lines function should therefore call $client->symbols() on any text which contains symbols prior to adding to the display hash.

Note: A lines function may be passed an args hash to give information relating to the caller. When called by menu transition code, the key 'trans' defines the animation which is calling the lines function. This allows the display to be altered on per transition basis.

##### $client->symbols()

$client->symbols() is used to convert the names of symbols to the graphic character representing the symbol itself. As of 6.2 the preferred use of $client->symbols() is as a replacement for Slim::Display::Display:symbol to specify individual symbols. However it can also be used to parse a complete text line and convert symbol tokens (created by Slim::Display::Display::symbol) into the symbol character.

Preferred use:

    return {
       'line'    => [ 'text '.$client->symbols('bell').' more text' ],
       'overlay' => [ $client->symbols('bell') ],
    }

Valid symbol names are currently:

- 'notesymbol'
- 'rightarrow'
- 'cursor'
- 'mixable'
- 'bell'
- 'mixable'
- 'circle' *
- 'filledcircle' *
- 'square' *
- 'filledsquare' *
- 'bell'
- 'progress1'
- 'progress2'
- 'progress3'
- 'progress1e'
- 'progress2e'
- 'progress3e'
- 'progressEnd'

* Only available on graphics displays

Use of custom characters extends this list with custom entries - see Custom Fonts below.

##### $client->curLines()

$client->curLines() returns a display hash using the current lines function. This is equivalent to the display that would result from calling $client->update().

As of 6.5 this method replaces Slim::Display::Display::curLines() which is depreciated. Note that it always returns a display hash even if the lines function itself does not return a display hash.

##### $client->curDisplay()

$client->curDisplay() returns a display hash containing the text components of the current display.

Note curDisplay returns a display hash including the screen name ('screen1' and 'screen2') and all line, overlay, center and font components on the current screen. This is different from previous versions.

The difference between $client->curDisplay() and $client->curLines() is that $client->curLines() makes a call to the mode's lines function and hence potentially gets a new display, whereas $client->curDisplay() returns what is currently being displayed. In the case of two screen players this includes what is on both screens, even if the current lines function only covers one screen.

#### Menu Transitions

The scrolling menu transitions which make up the slim user interface are controlled by push and bump animation commands. Push animations are used for transition to new menu screens. Bump animations are used to bump the screen against the edge, normally when the end of a menu structure is reached.

##### $client->pushLeft($start, $end), $client->pushRight($start, $end)

Pushes the old screen off the left/right side of the display and replaces it with a new screen.

- $start - undef or display hash for old screen
- $end - undef or display has for new screen

SB2 does not use $start as it uses the existing displayed screen for $start. As of 6.2, $start may be set to undef for other players. In this case the server uses the last displayed screen for $start.

As of 6.2 $end may also be set to undef. In this case, the server will call the current lines function to define $end. It is therefore acceptable to use e.g. $client->pushLeft() to carry out a menu transition.

##### $client->pushUp($end), $client->pushDown($end)

- $end - undef or display hash for new screen

On SB2 this scrolls the bottom line (or all text if in one line mode) to move to the next menu or list item. On text and SBG players it simply calls $client->update() to display a new screen with the new display. As $end can only be set for SB2/SB3/Transporter it is not normally used. The new screen to display is therefore defined by the current lines function. Normally called as e.g. $client->pushUp().

##### $client->bumpLeft(), $client->bumpRight()

##### $client->bumpUp(), $client->bumpDown()

Used to bump the current screen against the edge of the display to indicate that no additional menu items are available.

#### Custom Characters

Custom characters may be defined for both character and graphic display players. These enable lines functions to display customised symbols as icons and to build up complex displays for e.g. games like SlimTris.

Note that as of 6.5, display code is dynamically loaded based on the types of player attached. This means that custom characters must be defined once a player has attached - this is different from previous versions.

##### Character Displays

The character display hardware uses a fixed font definition for all normal characters (See here).

It also supports definition of up to 8 custom characters per display. These may be defined by plugins and used anywhere on the display.

Squeezebox Server allows you to define many custom characters using: Slim::Display::Text::setCustomChar().

Each display screen can use up to 8 custom characters. If more custom characters exist on a screen they will be replaced with a blank character. [NB Squeezebox Server also uses custom characters for the predefined symbols which also count towards this limit.]

Each custom character is 5 pixels wide and 7 pixels high plus an underline which is either on or off [equivalent of a single wide pixel].

For example to define a custom character to be called 'my-icon':

    Slim::Display::Text::setCustomChar( 'my-icon', (
    		0b00000000,
    		0b00000000,
    		0b00000000,
    		0b00000000,
    		0b00011110,
    		0b00011111,
    		0b00011111,

    		0b00000000
    		));

Note: The 3 most signifcant bits of each line are not used.

Custom characters may then be added to a display via $client->symbols():

    $display = {
        'line' => [ 'text ' . $client->symbols('my-icon'). ' more text' ],
    };

Custom characters do not work in 1 line mode on character displays.

Note: Slim::Display::Text::setCustomChar() should only be called once the text display code is loaded - e.g. from the setMode within a plugin, see SlimTris for an example.

##### Graphics Displays

Graphic displays may display custom characters through the use of custom font files.

Custom font files define a bitmap to use for each character in the custom font. The format of font files is described here. For plugins, custom font files are normally placed in the plugin's root directory.

The function Slim::Display::Graphics::setCustomChar() is used to register a name to associate with specific custom characters. This may be used to name each character in a custom font file.

Once custom characters have been defined they may be included within display strings via $client->symbols('character name').

For example:

    Slim::Player::Graphics::setCustomChar( 'my-icon', chr(2), 'icon.1' );

This registers the symbol name 'my-icon' for character chr(2) within the font file 'icon.1'. This may then be included within a display using:

    $display = {
        'line' => [ 'text ' . $client->symbols('my-icon') . ' more text' ],
    };

This allows custom characters to be used in the same way for character and graphics displays.

If a custom font is to be used for all characters within a display component, it is more efficient to define that component to use a specific font within the display hash and not register the font name as part of the custom character name.

    Slim::Player::Graphics::setCustomChar( 'my-icon', chr(2) );

    $display = {
        'overlay' => [ $client->symbols('my-icon') ],
        'fonts'   => { 'graphic-320x32'  => { 'overlay' => [ 'icon.1' ] } },
    };

Note: Slim::Player::Graphics::setCustomChar should only be called once a graphics player is attached - e.g. by calling from the setMode of a plugin if it has not been previously called [see SlimTris for an example of this for text custom characters].

#### Two Screen Displays

Transporter introduces two screens which may display text or visualizers.

Modes may display text on two screens by returning the new display hash with a 'screen2' component. If a mode returns both screens, it should also set the mode param 'screen2' to indicate to the server that it may need to clear screen2 when the mode exits. Include the following in the setMode function for the mode:

    $client->param('screen2', 'mymodename');

Where 'mymodename' can be any string other than 'periodic' (which is reserved).

A mode may choose to override the current visualizer mode and always use screen2. In this case it should also set the 'visu' param in its setMode function to [0]:

    $client->param('visu', [0]);

Alternatively the mode can check the current visualizer mode and only return screen2 information if it is in extended text mode. To do this call:

    $display->showExtendedText()  [$client->display->showExtendedText()]

This returns true if the player display supports 2 screens and it is in extended text mode at present.

To check whether the current display has 2 screens, call the following:

    $display->hasScreen2()        [$client->display->hasScreen2()]

If the player is showing extended text information and the current mode does not set the 'screen2' mode param, the server will display alternative information on the second screen. In this mode, the right hand screen is updated once a second using the lines function registered with $client->lines2periodic().

By default the Now Playing screen is registered with line2periodic. It is possible to override this in a plugin by adding a notify callback to listen for new clients connecting and resetting the line2periodic function at this point. For example:

    sub initPlugin {
        Slim::Control::Request::subscribe( \&newClient, [['client']], [['new']] );
    }

    sub newClient {
        my $client = shift->client || return;
        $client->lines2periodic(\&lines);
    }

    sub lines {
        my $client = shift;
        my $args   = shift;
        return {'screen2'}->{
            'line' => [ 'top line', 'bottom line' ]
        };
    }

Note that the lines function will be called with $args->{'screen2'} set to indicate that the response is for screen2 only.

#### Custom Server Mode Displays

7.0/6.5 supports custom lines functions for the volume display and playlist mode. This allows a plugin to alter the built in screen displays for changing volume and playlist/now playing displays.

A plugin should register alternative lines function at client connect time with the client methods customVolumeLines and customPlaylistLines.

To avoid server status messages appearing on top of a custom screen, a plugin can also turn off the common play/stop/pause status messages by setting $client->suppressStatus(). Setting this to 'all' will suppress both display updates and popups on jive. Setting it to another true value will only suppress display updates.

    sub initPlugin {
        Slim::Control::Request::subscribe( \&newClient, [['client']], [['new']] );
    }

    sub newClient {
        my $client = shift->client || return;
        $client->customVolumeLines( \&volumeLines );
        $client->customPlaylistLines( \&playlistLines );
        $client->suppressStatus(1);
    }

    sub volumeLines {
        my $client = shift;
        my $vol = shift;

        if (!defined $vol && $client->param('valueRef')) {
            $vol = ${$client->param('valueRef')};
        }

        # $vol is a value 0..100
    }

    sub playlistLines {
        my $client = shift;

        # see Slim::Buttons::Playlist::lines for details
    }

[% PROCESS helpfooter.html %]