Project

General

Profile

Structure of a SkinDesigner XML File in detail

To understand the following topics better, some words about the naming i used for Skindesigner. At the top level of an OSD element i talk about views. A view defines the base area position and size and can use the full OSD area.

A view contains different view elements. Each view element models a logical part of the view. For instance in the channel switching view "displaychannel" are view elements like "datetime", "channelinfo", "epginfo" and so on, in "displaymenu" which is the view for the VDR menu, you have view elements like "header", "footer", "scrollbar". These view elements have no position and size definition, they are just some kind of a "place holder". Each view element has several tokens. The tokens are dynamically provided by skindesigner and can be used inside each view element to display the current situation. Tokens are view element specific, that means that you can not use a token set in one view element in another one.

Inside a view element you can define areas where you can draw on with functions. Areas can be placed everywhere where it is allowed from the view base area which is defined in the according view tag. With functions like "fill", "drawtext", "drawimage" it is possible to draw into these areas.

For the most complex view, the VDR menu, additionally subviews like "displaymenuschedules" for displaying the various schedules lists ("what's on", "what's on now", "what's on next") in the VDR Schedules Menu are defined. Subviews can display lists (like the scheduling) or information like for instance the detailed EPG information for an event.

Is a list displayed, a menuitem container is available which allows you to position and customize the behaviour of the menu item list itself. Insinde this menuitem container a listelement exists, this list element behaves like a view element and is used to loop through the provided menu items with appropriate tokens for each loop. Additionally a currentelement which behaves also like a view element is available so that it is possible to display more detailed information for the currently selected list element.

Is a detailed view displayed, tabs as view elements are provided. You can define as many tabs as you like to display the provided complex content. If for instance the scraper2vdr plugin is installed together with epgd and epg2vdr, beside the "normal" EPG Information all the scraped information is available in form of tokens in the detailed EPG view and the detailed recoring view. With different tabs you can structure this content as you like.

 

2.1    Views, Viewelements and Tokens
2.2    Areas
2.3    Basic Functions
2.4    Numerical Attributes
2.5    Conditions
2.6    Complex Functions
2.7    Scrolling Areas
2.8    Area Containers
2.9    Subviews
2.10  List Views with Menu Items, List Elements and Current Element
2.11  Tabbed Views with Tab Elements
2.12  Custom Tokens

 


2.1 Views, Viewelements and Tokens

The six different views displaychannel, displaymenu, displayreplay, displaymessage, displayvolume and displayaudiotracks are already described in chapter 1.3. Inside these views as first child nodes of the view node the different view elements are defined. For each view different view elements exist. For the different view element tags no attributes have to be defined. Here exemplarily some view elements of the displaychannel view are shown:

<displaychannel x="0" y="0" width="100%" height="100%" fadetime="{fadeTime}">
    <background>
        ....
    </background>

    <channelinfo>
        ....
    </channelinfo>

    <epginfo>
        ...
    <epginfo>
    ....

The allowed attributes for the view itself are already explained in chapter 1.4.

In the first view element "background" the background of the channel display can be drawn. As already mentioned you can define areas and draw on these areas with different functions, but this will be described in a later chapter. The different view elements structure the view into different logical "blocks".

For each view element skindesigner provides a set of tokens. For instance the provided tokens for the "channelinfo" viewelement are the following:

  • {channelnumber}: Number of Channel, with "-" in case of channel switching
  • {channelname} Name of current Channel
  • {channellogoexists}: true if a channel logo exists
  • {channelid}: ChannelID as path to display channel logo
  • {switching}: true if a number is pressed on the remote to switch to a dedicated channel

As already mentioned, all tokens are embedded into curly braces. These tokens can now be used to draw the channel name, or alternatively a channel logo if available and so on...Skindesigner provides for each viewelement an appropriate set of tokens so that the skinner can specifically decide which information is shown in which way in the different areas.

If a view element is not used in a view or is empty (that means that no areas are defined in this view element), skindesigner ignores this view element and also is not calculating the provided tokens.

All supported view elements and all tokens provided for these view elements are documented in the "skinsketeton" folder in the plugin source tree (see https://projects.vdr-developer.org/git/vdr-plugin-skindesigner.git/tree/skinskeleton). There exist different skinskeleton files for the different views and for all other needed xml files.

Fading and Shifting of views and viewelements:

Skindesigner provides both fading in / out (setting the transparency of all ares stepwise from 0 to 100 in a defined time) and shifting (moving all areas stepwise from a start to an end point) of complete views or dedicated viewelements or menu lists (see chapter 2.10). The following additional attributes exist for <view> elements, <viewelement> elements (and with that also <currentelement> in list views) and <menuitems> list views (including the channel lists in zapcockpit views):

  • fadetime: fading duration in milliseconds
  • shifttime: shifting duration in milliseconds
  • startx, starty: shifting start point. All areas in the view / viewelement start at this point and shift to their final position defined in the area element itself (x, y attribute). (mandatory, alternatively use shifttype)
  • shifttype: possible values: top, bottom, left, right. If this attribute is set, the view or viewelement shifts in from the correspondingly OSD border. (mandatory, alternatively use shiftx and shifty)
  • shiftmode: (optional) possible values: linear, slowed. If shiftmode is set to "linear", shifting is done with a constant speed. With "slowed" shifting is slightly slowed down at the end.
  • delay: only for viewelements, delay in milliseconds till viewelement starts to fade / scroll or is displayed if no fading or shifting is activated

Fading and shifting can also be made configurable by applying appropriate skin setup parameters to "fadetime" and "shifttime". If both fadetime and shifttime are set to values larger 0, shifting is performed.

For convenience the views <displaychannel>, <displayreplay>, <displaymessage>, <displayvolume> and <displaytracks> canb e completely faded or shifted when displayed. To shift single viewelements of this views seperately, just define the shifting or fading parameters additionally for these viewelements. In estuary4vdr <displaychannel> view for instance the <scrapercontent> viewelement is displayed at the upper right corner of the screen, all other viewelements are placed at the bottom of the screen. These viewelements are shifted from bottom by setting shifttype="bottom" for the view itself. <scrapercontent> has his own shifting parameters with shifttype="left".

The VDR menu cannot be shifted completely. But for sure all viewelements and view lists can be faded or shifted individually.

viewelement conditions:
It is possible to define a condition for a viewelement. See chapter 2.5 for a detailed explanation how to define conditions. As tokens inside these viewelement conditions all defined setup parameters and any combination of them can be used. With that it is possible to allow the user to customize the layout of the different views by changing parameter values in the skin setup. For instance the different "widgets" in the main menu can be displayed depending on the setup values configured by the user.

horizontal and vertical views and viewelements:
The lists in the different VDR menus are layed out vertically by default. Navigating through the lists happens with the up/down keys. This behaviour can be changed by adding the parameter orientation="vertical" in the (sub)view tag itself. If you for instance like to display the recordings menu vertically, just add this option to the <menurecordings> tag:

<menurecordings x="0" y="0" width="100%" height="100%" fadetime="0" orientation="vertical">

The recordings menu is then displayed vertically, navigation through the list of recordings happens with left/right. The "orientation" Parameter can also be a setup value (a string value with the options "horizontal" and "vertical"), so that the user can decide how the menu is displayed. To be able to layout the viewelements according to the used orientation, each viewelement can be defined twice, once for horizontal and once for vertical orientation. For that just add the option "orientation" to the different viewelement tags. The same "orientation" parameter is available for the <menuitems> tag (see chapter 2.10), so that also two different lists for horizontal and vertical layout can be defined. As an example for a configurable menu see the recordings menu of the metrixhd skin, alsothe weather plugin main menu in the estuary4vdr skin is layed out vertically.

 


2.2 Areas

Areas are child nodes of view elements. Areas are the surfaces you can now actually draw on. Here an example for the <area> tag:

<area x="0" y="10%" width="20%" height="20%" layer="1">
    ....
</area> 

Imagine areas as a rectangular pieces of transparent paper on an base area (the OSD itself). These pieces of paper can now be placed on the base area by defining their positions (x, y) and sizes (width, height). If areas overlap, the one with the highest "layer" attribute is shown on the top of the screen, the other areas are sorted below. Valid "layer" attribute are from 1 (default) to 7 which is the highest layer. If an area has "transparency" set to a value larger 0, all the content of the area is shown with the defined transparency, 0 is completely opaque, 100 is fully transparent.

Inside a view element, as many areas as needed and as reasonable can be defined. As already described, the x, y, width and height definitions are relatively to the "parent" size and position. Since the viewelement tags have no size and position definition, the values of the view are used. In case of displaychannel, the x, y, width and height attributes of the <displaychannel> tag are used to calculate the position of the areas.

You can now draw on each defined area with so called "functions". For instance, with the function <fill> it is possible to fill the complete area with a dedicated color, with <drawrectangle> you can draw a rectangle from a point (x, y) with a size (width, height) inside the area. Keep always in mind, that all drawing functions on one area work with the same "set of pixels" of an area. That means, if a first function draws something (which means "coloring pixels of the area"), a second function which draws on the same area and so on the same pixels overwrites these pixels, there is no "blending" of colors. Consequentely, drawing with color "00000000" (completely transparent) is to erase already drawn parts on an area. This can be usefull, if you for instance want to draw an area with "rounded corners"...just fill the complete area with the background color and then draw transparent "inverted half circles" (see chapter "drawellipse" how to do that).

If you want to achieve blending effects between different "layers", you have to work with overlapping semitransparent areas with appropriate layer attribute.

The additional attribute "background" can be used to define "background areas". This is reasonable for viewelements which are drawn multiple times (like the <devices> viewelement for instance). Background areas are drawn only once at initialisation of the view, when refreshing a viewelement, background areas are not drawn again:

<devices delay="100" fadetime="300">
    <!-- background area -->
    <area background="true" x="0" y="10%" width="20%" height="20%" layer="3" transparency="30">
        ....
    </area>
    <!-- other areas -->
    <area x="0" y="10%" width="20%" height="20%" layer="3" transparency="30">
        ....
    </area>
    ...
</devices>

 


2.3 Basic Functions

The following basic functions are available to actually draw on the areas:

  • fill
  • drawrectangle
  • drawellipse
  • drawslope
  • drawtext
  • drawtextvertical

fill

The "fill" function has only the attribute "color" and fills the complete area with this color. Assume that clrRed is defined in the globals.xml:

<area x="0" y="10%" width="20%" height="20%" layer="3" transparency="30">
    <fill color="{clrRed}" />
</area> 

drawrectangle

The "drawrectangle" function draws an rectangle from the point x,y with the defined width and height and with the defined color:

<area x="0" y="10%" width="20%" height="20%" layer="3" transparency="30">
    <drawrectangle x="10" y="10" width="{areawidth}-20" height="{areaheight}-20" color="{clrRed}" />
</area> 

This example draws a rectangle with a border of 10 px into the defined area. As always, the definition of x, y, width and height of <drawrectangle> are relatively to size and position of the parent area. The x and y value of the rectangle is set 10 pix right / down of the upper left corner of the area. With the for every area available tokens {areawidth} and {areaheight} the width and height of the rectangle calculated so that the rectange has a border of 10 px inside the parent area.

Here another example for drawrectangle which is doing exactly the same as the above example:

<area x="0" y="10%" width="20%" height="20%" layer="3" transparency="30">
    <drawrectangle align="center" valign="center" width="{areawidth}-20" height="{areaheight}-20" color="{clrRed}" />
</area> 

Notice that the attributes x and y are now replaced by the attributes "align" for the horizontal alignment and "valign" for the vertical alignment. With these settings the rectangle is arranged centered inside the area. Allowed values are "left", "center" and "right" for the align attribute and "top", "center", "bottom" for the valign attribute.

drawellipse

The "drawellipse" function draws an complete ellipse or dedicated quadrants of an ellipse. The parameters are almost the same than in the drawrectangle function, allowed attributes are x, y, width, height, align, valign and quadrant. The "quadrant" attribute defines which part of the ellipse will be drawn:

0       draws the entire ellipse
1..4    draws only the first, second, third or fourth quadrant, respectively
5..8    draws the right, top, left or bottom half, respectively
-1..-4  draws the inverted part of the given quadrant

If quadrant is not 0, the x and y coordinates are those of the actual area, not the full circle! If width and height are identical, a circle (or the approproiate part of the circle) is drawn.

Here an example where drawellipse is used to create "rounded corners" with a size of 5% of the area width for an (background) area:

<area x="0" y="0" width="100%" height="100%" layer="1">
    <fill color="{clrBackground}" />
    <!-- upper left corner -->
    <drawellipse x="0" y="0" width="{areaheight}*0.05" height="{areaheight}*0.05" color="{clrTransparent}" quadrant="-2"/>
    <!-- upper right corner -->
    <drawellipse x="{areawidth} - {areaheight}*0.05" y="0" width="{areaheight}*0.05" height="{areaheight}*0.05" color="{clrTransparent}" quadrant="-1"/>
    <!-- lower left corner -->
    <drawellipse x="0" y="{areaheight} - {areaheight}*0.05" width="{areaheight}*0.05" height="{areaheight}*0.05" color="{clrTransparent}" quadrant="-3"/>
    <!-- lower right corner -->
    <drawellipse x="{areawidth} - {areaheight}*0.05" y="{areaheight} - {areaheight}*0.05" width="{areaheight}*0.05" height="{areaheight}*0.05" color="{clrTransparent}" quadrant="-4"/>
</area>

drawslope

The "drawslope" function draws an "slope" in the given rectangle. The parameters are almost the same than in the drawrectangle function, allowed attributes are x, y, width, height, align, valign and type. The "type" attribute controlls the direction of the slope:

0: horizontal, rising,  lower
1: horizontal, rising,  upper
2: horizontal, falling, lower
3: horizontal, falling, upper
4: vertical,   rising,  lower
5: vertical,   rising,  upper
6: vertical,   falling, lower
7: vertical,   falling, upper

drawtext

To display one single line of text the "drawtext" function has to be used. Here an example which demonstrates the usage of the different attributes:

<area x="0" y="0" width="50%" height="10%" layer="1">
    <drawtext x="0" valign="center" font="{vdrOsd}" fontsize="80%" color="{clrWhite}" width="{areawidth}" text="{title} {tr(and)} {subtitle}"/>
</area>

Beside the already known attributes x, y, align, valign and color, the new attriubutes "font", "fontsize" and "width" (which has a different meaning in this context) are used. "font" has to be one of the fonts defined in the "font" subarea of the globals.xml file. "fontsize" can be an absolute value (height in px) or relative value. If fontsize is set to 100%, the font has a height that fits exactly in the surrounding area, including the "internal" and "external leading" (for an explanation see for instance http://clanlib.org/img/FontMetrics.png).

The "width" attribute of the drawtext function tells the function the maximum width of the drawn text. If the width of the drawn text is larger than the width defined in the "width" attribute, the text is automatically cutted to this width and "..." is added to the text.

Finally the "text" attribute defines which text is drawn. Inside the text attribute, statical text, internationalized text from the globals.xml and every token provided in the appropriate view element can be used.

Additionally a "printf" Function can be used inside the text attribute to display numbers and dates in a well formatted way. If for instance the Tokens {day}, {month} and {year} are available as normal integers, you can use the following syntax to pad day and month with a leading zero in case day or month are smaller that 10:

<drawtext x=".." ... text="{printf('%02d.%02d.%d', day, month, year)}" />

As "format string" (in the example '%02d.%02d.%d') every valid string which can be used in the "C" printf Function is allowed (see [http://www.cplusplus.com/reference/cstdio/printf/] for a documentation).

drawtextvertical

With the "drawtextvertical" function a line of text can be drawn vertically on the OSD. The same attributes can be used as in "drawtext". With the additional attribute direction="(bottomup|topdown)" it can be determinated weather the text is drawn from bottom to top or vice versa.

Animated Elements

For the functions drawrectangle, drawellipse, drawslope, drawtext, drawtextvertical and drawimage (see below) two additional attributes are available: animtype and animfreq. animtype has to be set to "blink" (more types like "animated" may be added in the future), with animfreq the time in ms is defined how fast the element is blinking. For instance with the line

<drawtext animtype="blink" animfreq="1000" ... />

you draw a text which is drawn / erased every second.

 


2.4 Numerical Attributes

The basic functions show already some numerical attributes like x, y, width or height. As already shown in some examples, there are different possibilities to define these attributes, and it is allowed to calculate inside the attriubute values. Additionally there are some "special functions" available to reference the positioning of other drawn elements. All these topics will be explained in this chapter.

percentage values:

for all numeric attributes it is allowed to define the value as a percentage value, for instance x="40%" or height="10%". All "horizontal" values (x, width, ...) are calculated from the width of the "surrounding container", all "vertical" values (y, height, fontsize, ...) are calculated from the height of the "surrounding container". As already explained, the "surrounding container" is the first parent node of a element with a width and height setting. The "surrounding container" of the basic draw functions is the parent area, the "surrounding element" of an area is the view itself.

{areawidth} and {areaheight}

The {areawidth} and {areaheight} Tokens are available for every attribute and can be used to calculate inside numerical attributes in a more sophisticated way. {areawidth} and {areaheight} always refer to the surrounding area as described above.

calculating inside numerical parameters

Inside numerical parameters calculations can be done with the four basic mathematical operations +, -, * and /. As figures integers or decimalfractions can be used, the decimal point is a ".". Brackets are not allowed inside numerical parameters. Multiplication and division is done first, then addition and subtraction.

Keep in mind: if you have the need to calculate for instance a term like (a + b) * c, it is always possible to write a * c + b * c since no brackets are allowed.

Relative Positioning of Elements

Let's take the following example: you'd like to write a (dynamic) text, and directly after this text a second text with a different color. Both texts should be placed on the same area. So you need two <drawtext> functions for that. But what about the "x" Attribute of the 2nd <drawtext>? For that in skindesigner there are four additional "subfunctions" which can be used in attributes: "posx", "posy", "width" and "height".

To reference a dedicated function like the first <drawtext> function from inside the second <drawtext> function in our example, with the "name" attribute it is possible to give the first function a name which can be used by the second function. So this XML snippet would exactly do what we want (leaving 10px space between the end of the first and the beginning of the second text):

<area x="0" y="0" width="50%" height="10%" layer="1">
    <drawtext name="text1" x="0" valign="center" font="{vdrOsd}" fontsize="80%" color="{clrWhite}" text="{text1}"/>
    <drawtext x="{width(text1)} + 10" valign="center" font="{vdrOsd}" fontsize="80%" color="{clrRed}" text="{text2}"/>
</area>

In this way every function can be placed relatively to another function. Just give the function you want to reference a name and use this name in the second function, where:

  • {posx(name)}: x position of function with name "name"
  • {posy(name)}: y position of function with name "name"
  • {width(name)}: width of function with name "name"
  • {height(name)}: height position of function with name "name"

As a second example, if you want to place a function for instance below another function (with name "func1"), you can use: y="{posy(func1)} + {height(func1)}".

Please keep in mind that relative positioning is only allowed for functions inside the same area. Referencing the position and size of a function inside another area is not allowed. An exception are area containers described in chapter 2.8.

 


2.5 Conditions

Conditions can be used to draw a function or also a complete area or viewelement only in dedicated cases. Many Tokens are boolean Tokens, these Tokens can be used to decide during runtime what will be drawn. Conditions are allowed for <viewelement>, <menuitems>, <currentitem>, <area> and <areascroll> tags (<menuitems>, <currentitem> and <areascroll> are described later) and all functions (basic and complex functions).

Let's look at the following example: you'd like to draw a channel logo, but if no channel logo is available for a channel, you'd like to draw the channel name. In every view element where a {channelid} Token is provided to draw the channel logo (how to draw images is explained in the next chapter "complex functions"), additionally a Token named {channellogoexists} is available. With this you can do the following:

<area x="..." y="..." width="..." height="..." layer="...">
    <drawimage type="channellogo" condition="{channellogoexists}" ... />
    <drawtext condition="not{channellogoexists}" ... text="{channelname}"/>
</area>

As you see, the <drawimage> function is only executed if a channel logo exists. With "not" in front of the Token you want to evaluate inside a condition, you negate the parameter, so that the channel name is drawn in case no channellogo exists.

As already mentioned, you can also set a condition for a whole area:

<area condition="{booltoken}" ...>
    <func1 ... />
    <func2 ... />
    <func3 ... />
</area>

func1, func2 and func3 are only executed if booltoken is true.

If a condition is used for a viewelement, the whole viewelement is only displayed if the condition is true:

<devices condition="{showdevices}" ...>
    <area ...>
        <func1 ... />
        <func2 ... />
    </area>
    <area ...>
        <func1 ... />
        <func2 ... />
    </area>
    ...
</devices>

For viewelements, menuitems and currentitem tags only setup parameters can be used inside the conditions since the dynamically provided tokens are not set when the decision if a element is displayed or not is taken. If a viewelement is not displayed because of a "false" condition, because of performance reasons the appropriate dynamic tokens are not calculated by skindesigner.

Conditions can also be used to check if an integer parameter is lower, equal or greater that another value. For that you have to use the following syntax:

  • Lower than: condition="lt({token}, value)"
  • Equals: condition="eq({token}, value)"
  • Not Equals: condition="noteq({token}, value)"
  • Greater than: condition="gt({token}, value)"

For string tokens the following funtions are available:

  • check if a string token is set: condition="isset{stringtoken}"
  • check if a string token is not set: condition="empty{stringtoken}"
  • check if a string token is equal to another string: condition="strequal({stringtoken}, 'comparestring')"
  • check if a string token is not equal to another string: condition="strnotequal({stringtoken}, 'comparestring')"
  • check if a string token contains another string: condition="strcontains({stringtoken}, 'comparestring')"
  • check if a string token not contains another string: condition="strnotcontains({stringtoken}, 'comparestring')"

Conditions can be combined with "++" (and) and "||" (or), for instance': condition="not{booleantoken} ++ gt({integertoken}, 5)" is only executed if {booleantoken} is false and {integertoken} is greater than 5. You can combine as many single conditions in this way as you like.

In a condition only combinations with "and" or "or" are allowed. Mixing of "and" and "or" is not allowed.

 


2.6 Complex Functions

drawimage

With the <drawimage> function it is possible to draw different kind of JPG, PNG or SVG images (other image types are not supported), depending on the defined "type" attribute and depending on the set "type" attribute an appropriate "path" attribute. The following type attributes are allowed:

  • type="channellogo": use that type to draw a channel logo. path has to be the provided {channelid} Token, the logo is automatically searched in the "logos" folder as described in chapter 1.1
  • type="seplogo": use that type to draw a channel separator logo. path has to be set to the provided {seppath} Token, the logo is automatically searched in the subfolder "separatorlogos" of the "logos" folder as described in chapter 1.1
  • type="skinpart": use that type to draw a skinpart as a background image for instance. path has to be set to the name of the image without ".png", the skinpart image is searched automatically in the skinpart folder as described in chapter 1.1.
  • type="icon": use that type to draw an icon. path has to be set to the name of the image without ".png", the icon is searched automatically in the icon folder as described in chapter 1.1
  • type="menuicon": use that type to draw an menuicon. path has to be set just to the {icon} Token which is dymically filled with the correct icon name and path. This Token provided everywhere a menuicon can be drawn.
  • type="image": use that type to draw any image with a variable path. path each has to start with the always available token {ressourcedir} or has to consist just of a token pointing to a scraped image like {posterpath} or {bannerpath} provided dynamically by skindesigner. {ressourcedir} points to the ressource directory of your skin (where your xmlfiles and themes are located). If path starts with {ressourcedir}, any image in ressource dir can be used with just adding the relative path, for instance: path="{ressourcedir}/myicons/icon.png". Absolute pathes are not allowed. For sure also other dynamic tokens can be used additionally in the path variable.

Beside x and y also width and height of the different images have to be defined. Every image type beside "skinpart" is displayed in the original aspect ratio. If the image does not fit into the rectangle defined by with and height, the image will be scaled with the correct aspect ratio. "skinpart" images are always drawn in a way that exactly the defined width and height are used, if this doesn't match the aspect ratio, the image will be drawn distorted.

Here as an example the full example to display a channel logo or if this logo not exists draw the channel name from the MetrixHD skin displaychannel.xml:

<area x="0" y="80%" width="20%" height="20%" layer="3">
    <drawimage cache="true" condition="{channellogoexists}" imagetype="channellogo" path="{channelid}" width="94%" height="94%" align="center" valign="center" />
    <drawtext condition="not{channellogoexists}" x="5" valign="center" font="{light}" fontsize="40%" color="{clrWhite}" text="{channelnumber}: {channelname}" />
</area>

Used Icons, Menu Icons and Skin Elements are cached automatically at startup of the Plugin. To avoid too high memory usage, channel logos are only cached, if the attribute "cache" is set to "true". If <drawimage> tag which displays channel logos is cached, the first "x" logos for the defined size are cached. "x" can be configured in the Setup Menu of Skin Designer. Images can only be cached if their final size is known during startup. If the image size has to be calculated during runtime, for instance when displaying lists, images are cached firstly at their first display.

Here an example for the "encrypted" status icon:

<drawimage name="enc" condition="{isEncrypted}" imagetype="icon" path="ico_crypt_on" x="{areawidth} - {width(enc)}" valign="center" width="{areaheight}*0.8*1.76" height="{areaheight}*0.8"/>

Consider that the "width" function in the x value references the image itself so that the image is placed right-aligned in the area. width and height are calculated manually in a way so that the aspect ratio of the original image is respected.

For further examples just check the XML of the default skins.. :-)

drawtextbox

With the <drawtextbox> function it is possible to draw a longer text in a dedicated "box". The text is automatically wrapped to fit in the box. The following parameters are available:

  • x and y: top left position of the box
  • width and height: width and height of the text box. The width attribute is mandatory. If height is not defined, the whole text is drawn wrapped in a way that the defined width is respected.
  • align: (left|center|right) horizontal align of the single text lines (default left)
  • valign: (top|center|bottom) if a text does not fill the complete box height, with valign="center" the text can be placed vertically aligned in the box.
  • maxlines: if this attribute is set, only the defined number of lines is shown. If the text is longer, it is cutted automatically and completed with "..."
  • float, floatwidth, floatheight: possible values for "float" are "topleft" and "topright". If "float" is set, "floatwidth" and "floatheight" are mandatory additional attributes. The text is wrapped in a way that "floatwidth" and "floatheight" are kept empty in the upper left respectively upper right corner. In this empty area an image can be displayed for instance.

Here an example to draw the description of a series or a movie, depending which information is shown:

...
<drawimage condition="{isseries}" name="seriesposter" imagetype="image" path="{seriesposter1path}" x="{areawidth}*0.75" y="0" width="{areawidth}*0.25" height="{areawidth} * 0.25 * {seriesposter1height} / {seriesposter1width}"/>
<drawimage condition="{ismovie}" name="movieposter" imagetype="image" path="{posterpath}" x="{areawidth}*0.75" y="0" width="{areawidth}*0.25" height="{areawidth} * 0.25 * {posterheight} / {posterwidth}" />
<drawtextbox condition="{isseries}" x="0" y="0" width="96%" float="topright" floatwidth="{width(seriesposter)} + 10" floatheight="{height(seriesposter)} + 20" font="{light}" fontsize="8%" color="{clrWhite}" text="{description}" />
<drawtextbox condition="{ismovie}" x="0" y="0" width="96%" float="topright" floatwidth="{width(movieposter)} + 10" floatheight="{height(movieposter)} + 20" font="{light}" fontsize="8%" color="{clrWhite}" text="{description}" />
...

Here first the appropriate poster is displayed with a width of 25% of the area width and the appropriate height, after that a floating textbox is drawn so that the area where the image is drawn is kept empty. Since no "height" attribute is set, the whole text is displayed. How you define an area dynamically so that such an textbox with variable height fits in you will learn in chapter 2.7 "scrolling areas".

Consider that you can use the XML linewrap character

&#10;
to force a line wrap inside a textbox. Additionally you can put multiple text Tokens into the "text" attribute to display various information conveniently in one text box.

You have also the possibility to display dedicated text conditionally only if a defined Token is set. Let's say the Tokens {title}, {shorttext} and {description} are available, but {shorttext} is not filled in every case. If you know want to display the following...

<drawtextbox ... text="Title: {title} &#10;Short Text: {shorttext} &#10;Description: {description}" />

...for sure the output looks not very nice if {shorttext} is empty. To prevent this you can do the following:

<drawtextbox ... text="Title: {title} &#10;|Short Text: {shorttext} &#10;|Description: {description}" />

Consider the pipe symbols | around the "Short Text: ..." passage. With these pipe symbols the complete passage including the static text and the linebreak is only displayed if {shorttext} is not empty.

loop

Some more sophisticated information has to be provided in form of an array of Tokens. This array of Tokens is representated in the following way which is demonstrated on the basis of displaying the active timers in the main menu:

{numtimers}                  number of active timers
{timers[]}                   array with active timers (local and remote if remotetimers plugin is in use)
{timers[title]}              title of timer
{timers[datetime]}           date and time of timer
{timers[recording]}          true if timer is recording currently
{timers[channelname]}        name of channel for which timer is created
{timers[channelnumber]}      number of channel
{timers[channelid]}          ChannelID of channel
{timers[channellogoexists]}  true if channel logo exists

With that all necessary information for each timer is available via the different Tokens which are accessed identically to "regular" Tokens by surrounding them with curly braces. To display an array of Tokens, the <loop> function has to be used. The <loop> function displays every function defined as child node inside a "cell" as often as the array has elements - or less if defined by the "maxitems" attribute or by the overflow behaviour and the totally available size defined for the loop. If the columnwidth and / or rowheight are defined, the cells of the loop are drawn inside these borders. If a value is not defined, the content of the cell (the displayed functions) determinate this value dynamically by calculating the needed size of every element.

In detail the <loop> function has the following attributes:

  • condition: optional condition if loop should be displayed
  • name: Since it is possible to display different arrays inside one view element, the loop hasn to be named identically to the name of the Token array
  • orientation: possible values are "horizontal", "vertical" or "absolute". If orientation is set to "horizontal", the x position of the cell - and with that for the functions in the loop - are increased by "columnwidth" after each loop cycle, for "vertical" accordingly the y position by "rowheight". If orientation is set to "absolute", the x and y attributes for the functions inside the loop are not touched and can be set manually.
  • x, y, width, height: size and position for displaying the loop cells. If x or y are not defined, 0 is used as default so that the loop starts at the upper left corner of the surrounding area. If width or height is not set, the whole width / size of the surrounding area is used.
  • columnwidth: width which has to be used for each cell
  • rowheight: height which has to be used for one cell
  • overflow: possible values are "cut" or "linewrap". If overflow is set to "cut", only as many cells are displayed as fitting into the defined loop size. If overflow is set to "linewrap", after a cell exesses the available width the next cell is displayed in the next row with distance "rowheight" to the row above.
  • maxitems: if "maxitems" is defined, only that many loop cycles are performed.
  • valign: for vertical loops, "valign" can be set to "bottom". Default is "top". If valign is set to bottom and the number of actually displayed loop elements is lower than the possible number of elements, the complete list is aligned to the bottom of the surrounding area.

As a first example, here the code to display 7 timers in maximum horizontally in the main menu:

<area x="{areawidth}/8" y="75%" width="{areawidth}*0.875" height="25%" layer="2">
    <loop name="timers" orientation="horizontal" columnwidth="{areawidth}/7" rowheight="{areaheight}" overflow="cut">
        <drawrectangle condition="{timers[recording]}" x="0" y="0" width="{columnwidth}-5" height="{rowheight}" color="{clrRed}" />
        <drawimage  cache="true" name="logo" imagetype="channellogo" path="{timers[channelid]}" height="40%" align="center" y="10" />
        <drawtextbox x="5" y="{height(logo)} + 10" width="{columnwidth}-10" align="center" maxlines="2" font="{light}" fontsize="15%" color="{clrWhite}" text="{timers[title]}" />
        <drawtext align="center" y="75%" font="{light}" fontsize="20%" color="{clrWhite}" text="{timers[datetime]}" />
    </loop>
</area>

The surrounding area is positioned in a way that there is enoug space on the left hand side to display a "timer status cell" with the number of active timers.

As mentioned, the "name" attribute of the loop has to be set to the name of the Token array, in this case "timers". Since neither x nor y, width or height are defined, the whole surrounding area is used. "columnwidth" is set to the seventh part of the surrounding area so that 7 timers fit into the available space. Inside the loop in all numeric attributes of the functions executed in the loop the values {columnwidth} and {rowheight} can be used. Additionally the values {areawidth} and {areaheight} (size of the complete size which is available for the loop) can be used. As already mentioned, the x and y values of the loop functions are referring to the top left corner of the current cell.

As a second example for an absolute positioning of the loop cells here the way how the cutting marks are displayed in displayreplay:

<area x="5%" y="89%" width="90%" height="3%" layer="3">
    <loop name="marks" orientation="absolute">
        <drawrectangle x="{marks[position]}/{marks[total]}*{areawidth}" y="0" width="1" height="100%" color="{clrWhite}" />
        <drawrectangle condition="{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth}" y="0" width="5" height="1" color="{clrWhite}" />
        <drawrectangle condition="{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth}" y="{areaheight}-1" width="5" height="1" color="{clrWhite}" />
        <drawrectangle condition="not{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth} - 5" y="0" width="5" height="1" color="{clrWhite}" />
        <drawrectangle condition="not{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth} - 5" y="{areaheight}-1" width="5" height="1" color="{clrWhite}" />
        <drawrectangle condition="{marks[startmark]}" x="{marks[position]}/{marks[total]}*{areawidth}" y="30%" width="{marks[endposition]}/{marks[total]}*{areawidth} - {marks[position]}/{marks[total]}*{areawidth}" height="40%" color="{clrWhite}" />
    </loop>
</area>

The first four <drawrectangle> function draw the cutmark itself, the last <drawrectangle> draws the bar which shows the part of a recording which will not be cutted. The size and position of each function is defined "manually".

 


2.7 Scrolling Areas

Areas as described in chapter 2.2 are fixed in width and height. But what if the content you'd like to draw is larger than the size of the area? For sure you could enlarge the size of the area. But in some cases this is not possible or not wanted. For that you can use scrolling areas which have the difference compared to "normal" areas that the "area content size" is larger than the area size. That means, a scrolling area has also a position (x, y) and a size (width, height), which is displayed on the screen, but you can draw also outside this visible area. Scrolling of the content can then be done horizontally or vertically, and scrolling starts automatically after some period of "waiting time".

Beside all the attribute of an regular area, an scrolling area has these additional attributes:

  • mode: allowed values for the scrolling mode are "forthandback" and "carriagereturn". In the first case the text scrolls till the end and then backwards, in the second scrolling begins again from start.
  • orientation allowed values are "horizontal" and "vertical"
  • scrollelement: since the necessary size of the content of the scrolling area is calculated dynamically, with that attribute you can tell Skindesigner which function is "responsible" for this size. This drawing function has to be named identically as the "scrollelement" attribute. If no scrollelement is defined, Skindesigner uses per default all drawing functions inside the scrolling area to determinate the correct width (for horizontal scrolling) or height (for vertical scrolling) for the content area size. Because in case of horizontal scrolling Skindesigner automatically cuts the displayed text in case this text is too long to fit into the area size itself, the defined name of the <drawtext> function which draws this text has to be used as value for "scrollelement".
  • scrollspeed: allowed values are "slow", "medium" and "fast".
  • delay: time in ms to wait starting scrolling after initial display

Here an example of an scrolling area to display text on a menu list item:

<areascroll scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="1%" width="58%" layer="3">
    <drawtext name="menutext" x="20" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text="{start} {title}" />
</areascroll>

The position and size of the "visible area" is normally defined with the x, y, width and height attribute. As already mentioned, if the width of the complete text of the <drawtext> function is larger than the defined visible width of the scrolling area, it is automatically cutted and "..." is added so that the cutted text fits into the display size of the area. After 1s (1000 ms) the text starts scrolling.

Here another example for vertical scrolling to display a list of schedules:

<areascroll mode="forthandback" orientation="vertical" delay="1000" scrollspeed="medium" x="63%" y="85%" width="36%" height="15%" layer="2">
    <drawtext x="10" y="0" font="{semibold}" fontsize="30%" color="{clrWhite}" text="Next Schedules:" />
    <loop name="schedule" x="0" y="{areaheight}/4 + 5" orientation="vertical">
        <drawtext x="10" font="{light}" width="{areawidth}-20" fontsize="30%" color="{clrWhite}" text="{schedule[start]} {schedule[title]}" />
    </loop>
</areascroll>

In this example the scrolling area is placed at the lower right part of the screen and displays a header "Next Schedules" and a list of Schedules drawn by a loop. Since no scrollelement is defined, all functions are used to determinate the necessary height of the content area.

Consider that only one scrolling area is allowed per view respectively subview respectively list element respectively current element. That means you can place only one scrolling area inside "displaychannel", but for instance one scrolling area on a "listelement" and in parallel on the according "currentelement" (see chapter 2.10 for a more detailed explanation of this elements).

 


2.8 Area Containers

Area containers can be used to group areas and / or scrolling areas. Grouping areas can be reasonable because of two reasons:

  • conditions can be used conveniently for an area container instead of defining the same condition for every single area
  • the posx, posy, width and height functions (which can normaly only be used inside one area) can be used "area overlapping" inside an area container

For the first use case, assume that you'd like to display two or more areas in the following way:

...
<area condition="{cond}" x="0" y="0" width="10%" height="10%" layer="1">
....
</area>
<area condition="{cond}" x="0" y="0" width="10%" height="10%" layer="2">
    ....
</area>
...

This two areas can be grouped inside an area container, the condition has then only to be defined for the area container:

...
<areacontainer condition="{cond}">
    <area x="0" y="0" width="10%" height="10%" layer="1">
        ....
    </area>
    <area x="0" y="0" width="10%" height="10%" layer="2">
        ....
    </area>
</areacontainer>
...

Additionally for convenience it is possible to define x, y, width and height for the areacontainer. These values are then used as default values for each area inside the container if the according value of the area is not defined. So in our example we could do the following:

...
<areacontainer condition="{cond}" x="0" y="0" width="10%" height="10%">
    <area layer="1">
        ....
    </area>
    <area layer="2">
        ....
    </area>
</areacontainer>
...

All three examples produce the completely identical output. So using areacontainers in this way is just an alternative and more convenient way.

As described in chapter 2.4, referencing functions via their "name" attribute inside the posx, posy, width or height functions is only allowd inside the same area. As a second use case inside an area container it is allowed to reference also functions from other areas:

<areacontainer condition="{cond}" x="0" y="0" width="10%" height="10%">
    <area layer="1">
        <drawtext name="text1" x="10" valign="center" color="{clrText}" text="{text}" />
    </area>
    <area layer="2">
        <drawtext x="{posx(text1)} + {width(text1)}" valign="center" color="{clrText}" text="{text2}" />
    </area>
</areacontainer>

As you can see, the second drawtext function references the first drawtext function in another area to determinate the x postition of the second text. This is only possible inside a <areacontainer>, if the areas would be defined "standalone" without a container, this example would not work.

 


2.9 Subviews

The VDR menu is divided into ten different subviews:

  • menudefault: default menu list view, used in VDR setup menus, plugin setup menus, plugins, ...
  • menumain: VDR Main menu
  • menusetup: VDR Setup menu
  • menuschedules: VDR Schedules menu
  • menutimers: VDR Timers menu
  • menuchannels: VDR Channels menu
  • menurecordings: VDR recordings menu
  • menudetailepg: Detailed EPG Information of an event
  • menudetailrecording: Detailed Information of a recording
  • menudetailtext: Pure text information for displaying log files for instance

Beside these subviews, the "menu root view" displaymenu exists. The displaymenu view contains the view elements background, header, datetime and colorbuttons and message. The message view element is responsible to draw system messages while the VDR menu is opened and can only be implemented in the root view. The other four view elements are "default implementations" for all subviews. That means, a subview can implement these view elements also. Is a subview implementing on of these view elements, the implementation of the subview is used, otherwise the default implementation of the root view is used. If you want that in a subview one of this view elements is just not shown, implement it "empty" with only defining the empty view element tag.

Each subview has additional specific view elements which allow to display additional information. In the main menu for instance view elements for displaying the active timers or for displaying some system information are available.

Each subview has the identical set of attributes as a view itself. With the x, y, width and height attributes you can define the position and size of the subview relatively to the position and size of the root view. Here an example:

<displaymenu x="3%" y="3%" width="94%" height="94%">
    ...
    <menuschedules x="0" y="0" width="80%" height="80%" fadetime="0">
    </menuschedules>
    ...
</displaymenu>

The VDR menu is always displayed centered with a "3% border", independent which subview is displayed. The menuschedules subview is positioned in the upper left corner of the root view, but uses only 80% of it's width and height. Consider that this 80% are relatively to the width of displaymenu so that the actual width is only 75,2% of the complete OSD width.

The attributes fadetime, scaletvx, scaletvy, scaletvwidth and scaletvheight can be defined individually for each subview. If the scaling attributes are not set, the full tv picture is shown, otherwise the picture is scaled to the defined position and size when using the subview.

 


2.10 List Views with Menu Items, List Elements and Current Element

In all "list views" the menuitems element is available which is responsible for positioning and customizing the way the list is shown. The menuitems tag has the following attributes:

  • x, y, width, height: position and size of the container for the menuitems itself relatively to the subview position and size. The position and size of the menu item areas itself is calculated relative to this attributes.
  • orientation: allowed values are "horizontal" and "vertical", states if the list of menu items is drawn horizontally or vertically. If orientation is set to "horizontal", the up / down and left / right keys are toggled. For VDR <= 2.2.x a patch is required (see patches folder in source tree).
  • align: allowed values are "left", "center", and "right" for orientation horizontal and "top", "center" or "bottom" for vertical align. Align defines, how the complete block of menu items is aligned inside the menuitem container. This setting is only interesting for lists with a small number of menu items, since the height of a menu item is calculated by the complete available size divided by the number of menu items to display. If the "rest" of the division is larger then zero, there is a difference in positioning the single menu items.
  • numlistelements: integer which defines the number of menu items to be displayed. The height of the vertically displayed menu items is calculated as the height of the menuitems container divided by the number of menuitems to display.
  • condition: optional, can be used to define different <menuitems> tags for instance for a vertical and a horizontal menu.
For the menuitems tag in the menudefault subview the following attributes have additionally to be set:
  • menuitemwidth: the complete available width of the menuitems. You can use just a percentage value to define, which part of the available space in the menuitems container is available for the menuitems text itself.
  • determinatefont: You have to name (using the name attribute) a "drawtext" function which draws text of a typical size inside the list items. Use this name as value for the "determinatefont" attribute. This is necessary because Skindesigner has to know which font is used to display the columns of the menu items correctly.

Inside <menuitems> the <listelement> view element and the <currentelement> view element are available.

listelement contains the areas which have to be displayed on every menu item. For vertical lists, the x and the width attribute reffer to the position and size of the menuitems container. The y position and the height of the area are set by Skindesigner automatically so that they have not to be used. For horizontal menus the y and height value have to be set, x and width are set automatically. The tokens {current} and {separator} are available for every list element and can be used to handle these list elements differently by using according "condition" attributes.

This simple example places the schedules list 10% below the top with a hight of 80% of the complete screen and displays 10 menu items.

<menuitems x="0" y="10%" orientation="vertical" width="100%" height="80%" align="center" numlistelements="10">
    <listelement>
        <!-- Background -->
        <area x="1%" width="98%" layer="2">
            <fill condition="not{current}" color="{clrInactive}" />
            <fill condition="{current}" color="{clrActive}" />
            <fill condition="{separator}" color="{clrSeparator}" />
        </area>
        <areascroll condition="not{separator}" scrollelement="menutext" mode="forthandback" orientation="horizontal" delay="1000" scrollspeed="medium" x="1%" width="98%" layer="3">
            <drawtext name="menutext" x="20" valign="center" font="{light}" fontsize="95%" color="{clrWhite}" text="{start} {title}" />
        </areascroll>
    </listelement>
</menuitems>

The menuitems are placed to get the full width of the menu with 1% border on each side. First the background is drawn in a color which depends on the "type" of schedules menu item. After that a scrolling area is drawn which shows the start time and the title of the event. In a list, a scrolling area starts scrolling as soon as the menu item is selected...and for sure after the delay.

Animation of list elements: <listelement> can carry the optional attributes fadetime and shifttime. If fadetime is set to a value larger 0 (time in ms), when scrolling through a list the last active element is faded out and the new active element is faded in. When shifttime is set to a value larger 0, the last active element "moves out" and the new active element "moves in". For that the area which displays the background when the list element is active has to be marked with the attribute indicator="true". See both metrixhd and estuary menus for exapmles of this feature.

The currentelement view element can be used to display further information for the currently selected menu item. It can carry the following attributes:

  • delay: time in ms to wait till currentelement is shown. Don't use 0 here, otherwise scrolling through the menu could get slow, because the currentelement is displayed and immediately destroyed when scrolling through the list.
  • fadetime: if you like that currentelement fades in, set a value > 0 to define the duration of fading in ms.
  • shifttime: shifting duration in milliseconds
  • shiftx, shifty: shifting start point. All areas in currentelement start at this point and shift to their final position defined in the area element itself (x, y attribute). (mandatory, alternatively use shifttype)
  • shifttype: possible values: top, bottom, left, right. If this attribute is set, currentelement shifts in from the correspondingly OSD border. (mandatory, alternatively use shiftx and shifty)
  • shiftmode: (optional) possible values: linear, slowed. If shiftmode is set to "linear", shifting is done with a constant speed. With "slowed" shifting is slightly slowed down at the end.
  • condition: optional, can be used if the <currentelement> should only be displayed in dedicated cases.

For the areas of currentelement the position (x, y) and size (width, height) can by set relatively to the menuitems container. For placing the currentelement areas depending on the position of the according listelement, the tokens {menuitemx}, {menuitemy}, {menuitemwidth} and {menuitemheight} are available and can be used in the attributes of the areas. There is nothing more special about the currentelement, it can be used as any other view element.

In all list subviews beside the menudefault subview tokens suitaible for the current context are provided. The tokens for the main menu item for instance are "number", "label" with the name or "icon" for displaying an appropriate icon for the menu item. Schedules menu item tokens are {title}, {start} or {stop} with information about the EPG event to display. All these tokens are more or less independent and "orderless". In these lists, the various information can be placed completely user defined on the menu buttons.

An exeption is the menudefault subview. This subview is shown for all "standard" menus like VDR setup menus or plugin setup menus for instance. But also if another plugin creates "normal" lists to print some information on the screen, this view is used. The information displayed is completely unknown and should be displayed in form of a table with up to six columns. To display this generic information, generic tokens are provided:

  • {column1} ... {column6}: content of the columns
  • {column2x} ... {column6x}: proposed x value for the text of the column on this "row" resp. menu item
  • {column1width} ... {column6width}: proposed maximum width for the text of the column on this "row" resp. menu item
  • {column2set} ... {column6set}: true if the column is used in the view

With these tokens you are able to display the generic information in fact in a more or less predetermined and fixed way, but at least you can use your favorite design to display the default menus.

Beside these tokens some additional "special" tokens exist in default menus:

  • {column1pb} ... {column6pb}: some plugins use a textual representation of progress bars like "[|||   ]". If skindesigner detects such a progress bar in a column, the appropriate {columnXpb} is set to true
  • {column1pbtotalsize} ... {column6pbtotalsize}: total size of detected progress bar (total number of characters)
  • {column1pbsize} ... {column6pbsize}: progress of detected progress bar (number of pipes). To display a graphical progress bar, use columnXpbsize / columnXpbtotalsize to calculate the progress in percent.
Additionally in default menus a dynamic token is set to indicate the current menu category or the plugin which is currently running. With that it is possible to display different default menus with an individual style.
  • If a VDR setup menu is diplayed, the token {setup} is set to true
  • For the following VDR menus a token named as the menu is set: channeledit, timeredit, recordinginfo, recordingedit
  • For the commands menu {commands} is set to true
  • For some plugins running, a token called as the name of the plugin is set to true: {pluginname} is set to true. Plugins considered are: fritzbox, systeminfo, mailbox, neutrinoepg, remotetimers, zaphistory, remoteosd, filebrowser, epgsearch

As an another difference compared to all other list subviews, in the menudefault subview no "currentelement" view element is available.

In all list views the view element <scrollbar> is available and should be used to illustrate the position of the displayed cutout of the complete list compared to the complete list. For that the tokens {height} and {offset} are provided dynamically when clicking through the menu items list. {height} contains the number of menu items divided by the total number of menu items. {offset} is the distance from the top of the list to the current position in the list. Both values are provided in one-tenth of a percent values to avoid rounding errors. Because of that you have to divide these figures by 1000 to calculate actual pixel values, for instance "{areaheight} * {height} / 1000" to calculate the height of the scrollbar displayed in a area with height {areaheight}.

 


2.11 Tabbed views with Tab Elements

tab elements are available inside all "tabbed views" (menudetailepg, menudetailrecording, menudetailtext). A tab behaves like one single scrolling area, the content height of the scrolling area is calculated dynamically from the drawn content on this tab. A tab has the following attributes:

  • x, y, width, height, layer, transparency: analog to area
  • name: The name of the tab, this name is used in the <tablabels> viewelement to display the different tab labels.
  • scrollheight: the height in px which will be scrolled (if content is higher that screen) by pressing up / down

An example tab definition could look like this:

<tab name="EPG Info" x="2%" y="20%" width="94%" height="65%" layer="2" scrollheight="{areaheight}/4">
    <drawtextbox x="0" y="0" width="96%" font="{light}" fontsize="8%" color="{clrWhite}" text="{description}" />
</tab>

This EPG Info Tab draws the description in a textbox with unlimited height. So if the description is such long that the wrapped text in the textbox doesn't fit, it is possible to scroll this area manually by pressing up / down on your remote. With one click, 1/4 of the screenheight will be scrolled. Like in list views, in tab views <scrollbar> is also available. In case of a tab {height} contains the height of the displayed part divided by the full height of the content. {offset} is the distance from the top of the content to the top of the displayed part divided by the full content height.

Since in the "menudetailtext" tab view only one token {text} is provided, in this view only one tab can be used. In the "menudetailepg" and "menudetailrecording" tab view you can define as many tabs as you like. All tabs can access the complete set of tokens provided for the tabs. Inside the tabs you can use all drawing functions exactly as in any other area. The width of the area has to be respected when drawing on the area, but you don't have to care about the total height of the content.

In tabbed views the <tablabels> view element is available. Inside this view element the tab labels of the used tabs are provided as an array, the currently displayed tab is marked, so that you can display the tablabels in any arbitrary way by looping through the array. For sure you can use only one tab also in "menudetailepg" and "menudetailrecording", then for sure the usage of <tablabels> can be omited.

If more than one tab is used in a tabbed view, up / down is used to scroll inside the tabs (with the defined "scrollheight"). left / right is used to navigate through the different tabs. If only one tab is used in a tabbed view, left / right can be used to jump one complete "page" up or down.

 


2.12 Custom Tokens

In the views <displaychannel>, <displaymenumain> and <displayreplay> a special view element <customtokens> is available. With that view element it is possible to display user specific non VDR information inside the skin. For the <customtokens> view element up to 10 integer and string values can be set by the user from outside VDR with this SVDRP commands:

Setting custom integer tokens:

svdrpsend PLUG skindesigner SCIT 1 = value1
svdrpsend PLUG skindesigner SCIT 2 = value2
...

Setting custom string tokens:
svdrpsend PLUG skindesigner SCST 1 = value1
svdrpsend PLUG skindesigner SCST 2 = value2
...

The maximum number of custom integer and string tokens can be enlarged in Skindesigner setup menu if necessary.

With

svdrpsend PLUG skindesigner LCTK

all already set custom tokens are listed in the system log.

With several svdrp commands an arbitrary number of custom tokens can be set. After setting the numbered custom tokens, they can be displayed inside the <customtoken> view elements in the different templates just by using the appropriate token {customint1}, {customint2}, ... and {customstring1}, {customstring2}, ...