Wiki Navigation
- Loading...
Purpose
- Required: No
- Type of Change: Feature
To promote #defines to properties, allow #defines to contain skin expressions, and allow #defines to be added to the window definition through the use of an <include> file.
Description of Change
By promoting #defines to be tracked inside MediaPortal as properties skin designers will be able to use defines to transfer information from one page to another and to use those values in skin expressions and functions. This is very useful for skin capabilities that provide for user controlled layout changes on a "skin settings" page. Enabling this behavior will significantly reduce the need for skin developers to develop and distribute an MP plugin with their skin (where this decision logic has historically resided); e.g., for modifying the EPG length or home page layout and content.
The implementation handles a few important considerations:
- Multiple #defines with the same name - As skin xml files are loaded the #defines in those windows are loaded and saved as properties. Property values have global scope and are available to be used on any other MediaPortal window. If a window loads and #defines 'A' and a subsequent window is loaded that also #defines 'A' then the second value of #define 'A' overwrites the first value loaded. This implementation was chosen (over ignoring the second #define 'A') with the expectation that the most recently loaded window information is more correct than window information loaded in the past.
- #defines in conflict with built-in property names - If a window is loaded with a #define that redefines a built-in property name then the #define in the skin xml will overwrite the current value of the built-in property. However, this cannot be relied upon since the skin designer does not have any control over when the built-in property value is written.
Property/#define namespaces - Because #defines are now managed as properties it makes good sense for skins to maintain #defines using a namespace that will not be in conflict with built-in properties. This is easily done by adopting a simple naming convention for #defines. The recommendation is to preface all #defines with the word "Skin". This convention is safe since MediaPortal does not maintain any properties that begin with "Skin". For example, use "#Skin.tvguide.rows.is_short" rather then simply "tvguide.rows.is_short".
Defines can be added to a skin xml file using an <include> file. This behavior allows for the skin designer to create skin files that contain a common set of values that may be used throughout the skin. For example, you can create a skin file named colors.xml with the following content. Each skin xml file that includes colors.xml ( <include>colors.xml</include> ) will be able to use the #defines it contains.<?xml version="1.0" encoding="utf-8" standalone="yes"?> <window> <define>#red:ffff0000</define> <define>#green:ff00ff00</define> <define>#blue:ff0000ff</define> </window>
#define syntax and use
The syntax for a <define> has been extended to add the following new attributes:- property - a boolean value; either "true" or "false. If "true" then the #define is promoted to MediaPortal property status and can be used just as any other property is used (in any MediaPortal window).
- evaluateNow - Specifies whether or not the #define (which would normally be a skin expression in this case) should be evaluated when it is loaded ("true") or evaluated later by its consumer ("false"). The consumer must provide expression evaluation if the value is "false".
In the following, at the moment the define is read in (on window load) the define is promoted to be also an MediaPortal property (via GUIPropertyManager.SetProperty()). Expressions in the define declaration (also a property) are not evaluated when the window loads; they will be evaluated when the control that consumes the define/property is loaded.<define property="true">#name:value</define>
In the following, at the moment the define is read in (on window load) the define is evaluated and any expressions are resolved immediately (via GUIPropertyManager.Parse()). The define is not promoted to a MediaPortal property.<define evaluateNow="true">#name:value</define>
In the following, the expression is evaluated on window load and the result is promoted to a MediaPortal property.<define property="true" evaluateNow="true">#name:value</define>
The following alternatives implement the legacy behavior of a #define and are all functionally equivalent.<define>#name:value</define> <define property="false">#name:value</define> <define evaluateNow="false">#name:value</define> <define property="false" evaluateNow="false">#name:value</define>
Example:
This example shows how you can modify the number of TV EPG rows via a GUI user setting using #defines and skin settings.
In a settings xml skin file the following user control is defined to control the length of the EPG (short vs. long). The red colored attributes manage a skin setting that determine whether the EPG length should be short or long (using the skin setting #Skin.tvguide.rows.is_short). When the checkbutton control is clicked the boolean setting is toggled. Using the skin setting capability provides persistence for the setting (the setting is written to a skin config file).<control> <description>Guide Rows</description> <type>checkbutton</type> <id>14</id> <label>Display Less Rows In Guide</label> <font>font12</font> <width>471</width> <height>52</height> <textXOff>28</textXOff> <textYOff>8</textYOff> <markalign>right</markalign> <markvalign>top</markvalign> <markWidth>33</markWidth> <markHeight>21</markHeight> <markXOff>30</markXOff> <markYOff>10</markYOff> <textureFocus>settings_button_focus.png</textureFocus> <textureNoFocus>settings_button_nofocus.png</textureNoFocus> <textureCheckmark>settings_checkmark_checked.png</textureCheckmark> <textureCheckmarkNoFocus>settings_checkmark_unchecked.png</textureCheckmarkNoFocus> <textcolor>ffffffff</textcolor> <textcolorNoFocus>ffffffff</textcolorNoFocus> <onleft>#defaultcontrol.onleft</onleft> <selected>skin.hassetting(#Skin.tvguide.rows.is_short)</selected> <onclick>skin.togglesetting(#Skin.tvguide.rows.is_short)</onclick> </control>
Rendering with the setting
In the skin xml file that renders the EPG the following #defines are used to configure the individual controls that make up the EPG. Notice that each #define contains as its value a skin expression that is calculated when the #define is read in by the skin engine. Since each #define is resolved completely at window load time, and in the order in which it appears in the skin xml file, it is possible to build relationships between #defines to lessen the complexity of a compound expression.
In this example each #define consumes the value of the skin setting that is managed via the checkbutton control described above (#Skin.tvguide.rows.is_short) in a skin expression. Since #Skin.tvguide.rows.is_short is a boolean it may be used in the skin expression iif(condition, true part, false part) as the condition. In each case the appropriate value is selected (either the true part or false part) and assigned to the #define key at the moment the #define is read in by the skin engine (during window load).<define>#Skin.tvguide.viewport.height:#(iif(#Skin.tvguide.rows.is_short, 101, 789))</define> <define>#Skin.tvguide.viewport.texture:#(iif(#Skin.tvguide.rows.is_short, 'tvguide_timeline_bg.png', 'viewport_tv_guide_10rows.png'))</define> <define>#Skin.tvguide.panel.height:#(iif(#Skin.tvguide.rows.is_short, 566, 666))</define> <define>#Skin.tvguide.channel_template.height:#(iif(#Skin.tvguide.rows.is_short, 64, 66))</define> <define>#Skin.tvguide.current_program_title.posy:#(iif(#Skin.tvguide.rows.is_short, 816, 950))</define> <define>#Skin.tvguide.current_program_time.posy:#(iif(#Skin.tvguide.rows.is_short, 868, 1006))</define> <define>#Skin.tvguide.description1.visible:#(iif(#Skin.tvguide.rows.is_short, 'yes', 'no'))</define> <define>#Skin.tvguide.horizontal_scrollbar.posy:#(iif(#Skin.tvguide.rows.is_short, 905, 505))</define> <define>#Skin.tvguide.vertical_scrollbar.posx:#(iif(#Skin.tvguide.rows.is_short, 1829, 1329))</define> <define>#Skin.tvguide.tv_group_button.height:#(iif(#Skin.tvguide.rows.is_short, 533, 665))</define> <define>#Skin.tvguide.tv_group_label.posy:#(iif(#Skin.tvguide.rows.is_short, 733, 860))</define>
In the body of the skin xml that renders the EPG these #defines (above) are consumed by gui controls. Simply use the appropriate #define in place of a hard-coded value as follows.<control> <description>VIEWPORT</description> <type>image</type> <id>0</id> <posX>0</posX> <posY>162</posY> <width>1893</width> <height>#Skin.tvguide.viewport.height</height> <texture>#Skin.tvguide.viewport.texture</texture> <shouldCache>true</shouldCache> </control>
See also: Skin Expressions
Additional Information and References
- Mantis Issue: 3787
- Related xml(s): all xmls may optionally use this feature
- Window ID:
- Related GUI property/control:
This page has no comments.