@
TP.One , here is the code, from my template.xml, for the first dynamic content widget. What this means is that, if the conditions are met (I will explain below), the skinshortcuts script will generate an include for the widget, which will appear in the script-skinshortcuts-includes.xml file, which is automatically generated by the script in your skin's code folder. So that you can have an idea, here is what one such file looks like:
https://1drv.ms/u/s!AlII29kkG6TFiNl1hU8X-Fz5MY1mIw
xml:
<other include="shelfgroup1">
<!-- Widget conditions: a path is needed, single shelf, dynamic content -->
<condition tag="property" attribute="name|widgetPath" />
<condition tag="property" attribute="name|widgetTwoShelves">false</condition>
<condition tag="property" attribute="name|widgetContent">default</condition>
<!-- Common values -->
<propertyGroup>widgetCommon</propertyGroup>
<!-- Retrieve properties -->
<property name="label1" tag="property" attribute="name|widgetName" />
<property name="path1" tag="property" attribute="name|widgetPath" />
<property name="target1" tag="property" attribute="name|widgetTarget" />
<property name="type1" tag="property" attribute="name|widgetType" />
<property name="widget1" tag="property" attribute="name|widget" />
<property name="sortby1" tag="property" attribute="name|widgetSortBy" />
<property name="sortorder1" tag="property" attribute="name|widgetSortOrder" />
<property name="limit1" tag="property" attribute="name|widgetLimit" />
<!-- If target is set to true for next widget navigate to next (fallback if empty set to false in overrides.xml) -->
<property name="onup" tag="property" attribute="name|widgetType.2" value="none">false</property>
<property name="onup">true</property>
<!-- Top -->
<property name="top" tag="property" attribute="name|widgetDouble" value="true">170</property>
<property name="top">327</property>
<!-- Height -->
<property name="height" tag="property" attribute="name|widgetDouble" value="true">630</property>
<property name="height">315</property>
<!-- Background Height -->
<property name="backgroundheight" tag="property" attribute="name|widgetDouble" value="true">690</property>
<property name="backgroundheight">375</property>
<!-- Content -->
<property name="labelvisibility1" tag="property" attribute="name|widgetType" value="episodes">true</property>
<property name="labelvisibility1">false</property>
<property name="aspect1" tag="property" attribute="name|widgetType" value="musicvideos">scale</property>
<property name="aspect1">keep</property>
<property name="isYear1">'true' if path1 in 'years' else 'false'</property>
<property name="isPlaylist1">'true' if (path1 in 'videoplaylists' or path1 in 'musicplaylists') else 'false'</property>
<property name="isMusicGenre1">'true' if target1 in 'music' and path1 in 'genres' else 'false'</property>
<property name="content1">'Shelf_GenericSquare' if (type1 in 'movies' or type1 in 'tvshows' or type1 in 'episodes') and (path1 in 'tags' or path1 in 'genres' or path1 in 'studios' or path1 in 'actors' or path1 in 'directors' or path1 in 'country' or path1 in 'years') else 'Shelf_GenericSquare' if (type1 in 'addons' or type1 in 'games' or type1 in 'musicvideos' or target1 in 'music' or target1 in 'pvr' or target1 in 'tvguide' or target1 in 'radioguide' or path1 in 'videoplaylists' or path1 in 'musicplaylists' or path1 in 'sources') else 'Shelf_GenericPoster'</property>
<controls>
<control type="group">
<skinshortcuts>visibility</skinshortcuts>
<include content="WidgetBackground">
<param name="id">1600$SKINSHORTCUTS[id]1</param>
<param name="label">$SKINSHORTCUTS[label1]</param>
<param name="top">$SKINSHORTCUTS[top]</param>
<param name="height">$SKINSHORTCUTS[backgroundheight]</param>
<param name="visible">String.IsEmpty(Window(home).Property(WidgetFocus$SKINSHORTCUTS[id]))</param>
</include>
<control type="panel" id="1600$SKINSHORTCUTS[id]1">
<top>$SKINSHORTCUTS[top]</top>
<left>32</left>
<right>0</right>
<height>$SKINSHORTCUTS[height]</height>
<onclick condition="System.HasAddon(script.playalbum) + String.IsEqual(ListItem.DBType,album)">RunScript(script.playalbum,albumid=$INFO[ListItem.DBID])</onclick>
<onclick condition="String.IsEqual(ListItem.DBType,season)">ActivateWindow(Videos,videodb://tvshows/titles/$INFO[ListItem.Property(TVShowID)]/$INFO[ListItem.Property(Season)]/?tvshowid=$INFO[ListItem.Property(TVShowID)])</onclick>
<onup condition="$SKINSHORTCUTS[onup]">SetProperty(WidgetFocus$SKINSHORTCUTS[id],2,home)</onup>
<onup condition="$SKINSHORTCUTS[onup]">SetFocus(1600$SKINSHORTCUTS[id]2)</onup>
<ondown>300</ondown>
<onleft condition="Skin.HasSetting(VerticalHome)">300</onleft>
<preloaditems>2</preloaditems>
<orientation>horizontal</orientation>
<include content="$PYTHON[$SKINSHORTCUTS[content1]]">
<param name="id1">1600$SKINSHORTCUTS[id]1</param>
<param name="isYear">$PYTHON[$SKINSHORTCUTS[isYear1]]</param>
<param name="isPlaylist">$PYTHON[$SKINSHORTCUTS[isPlaylist1]]</param>
<param name="isMusicGenre">$PYTHON[$SKINSHORTCUTS[isMusicGenre1]]</param>
<param name="labelvisibility">$SKINSHORTCUTS[labelvisibility1]</param>
<param name="aspect">$SKINSHORTCUTS[aspect1]</param>
</include>
<content>
<item>
<icon>DefaultAddonNone.png</icon>
<thumb>DefaultAddonNone.png</thumb>
<visible>String.IsEmpty(Container(1600$SKINSHORTCUTS[id]1).ListItem(1).Label)</visible>
</item>
</content>
<content sortby="$SKINSHORTCUTS[sortby1]" sortorder="$SKINSHORTCUTS[sortorder1]" limit="$SKINSHORTCUTS[limit1]" target="$SKINSHORTCUTS[target1]">$SKINSHORTCUTS[path1]</content>
</control>
</control>
</controls>
</other>
<!-- Property groups -->
<propertyGroup name="widgetCommon">
<!-- Retrieve id -->
<property name="id" tag="mainmenuid" />
<!-- Check if other widgets are set -->
<property name="target1" tag="property" attribute="name|widgetTarget" value="false">false</property>
<property name="target1">true</property>
<property name="target2" tag="property" attribute="name|widgetTarget.2" value="false">false</property>
<property name="target2">true</property>
<property name="target3" tag="property" attribute="name|widgetTarget.3" value="false">false</property>
<property name="target3">true</property>
<property name="target4" tag="property" attribute="name|widgetTarget.4" value="false">false</property>
<property name="target4">true</property>
<property name="target5" tag="property" attribute="name|widgetTarget.5" value="false">false</property>
<property name="target5">true</property>
<property name="target6" tag="property" attribute="name|widgetTarget.6" value="false">false</property>
<property name="target6">true</property>
</propertyGroup>
So from the code above, it starts by providing what are the conditions under which the include will be generated. In this case, three are needed:
1. The widget has to have a path (there needs to be content defined for the widget). This will come from the property widgetPath.
2. It must be a single widget (I allow users to show the first two widgets together, this is controlled by the custom property widgetTwoShelves)
3. It must be a dynamic content widget, which comes from the porperty widgetContent having the value "default" (as opposed to "static" in my case for static content widgets).
All of the conditions have to be met for the include to be generated.
The properties (widgetPath, widgetContent, etc.) will be assigned by the script to each menu item, depending on what the user chooses for that menu item when script-skinshortcuts.xml is shown. Again, I encourage you to study the script's wiki.
Next, I set some common values that all of the widgets share in my skin. That is the <propertyGroup> widgetCommon, which is at the end of the file for me, and which I also put in the code excerpt above.
If you look at that above, I set the property "id" to be "mainmenuid", which tells the script to retrieve the specific id for the menu item when generating the include. This is a crucial part to having unique id's for each widget.
I also set the "target" property (target1 for the first widget, target2 for the second, etc.) to be the widgetTarget property from the menu item, since I use that property for the navigation of my widgets.
Going back to the widget code, I set all the properties that I will be using from the menu item, or that I will be assigning specific values to. For example, the property label1 will come from the widgetName property assigned to the menu item. That way, in the rest of the template, I can use label1 to refer to the widgetName property from the menu item.
Other examples in that part of the code are "top" and "height", which I set to specific values depending on the "widgetDouble" custom property assigned to the menu item. I allow the users to show double-row widgets as well as single-row widgets.
There are some more complex examples of properties in the code in the <!-- Content --> part, like "content1", which will decide which include to use for this widget, either "Shelf_GenericSquare", which shows square icons with labels below, or "Shelf_GenericPoster", which shows posters. I say that this example is more complex because it involves a python code snippet (the if ....) to decide which include to use based on the values for the type1, path1 and target1 menu item properties. Shelf_GenericSquare and Shelf_GenericPoster can be found in Includes_Shelf_Contents.xml in my skin's 1080i folder.
The <controls> part of the code has the actual controls that will be used for the widget (in the generated include), and here is where you reference all of the properties that were defined before the <controls> tag.
As you can see, I have a <group> that includes some controls from my "WidgetBackground" include (found in Includes_Shelf_Contents.xml). If you notice, the parameter "id" that I am passing to that include is "1600$SKINSHORTCUTS[id]1", which is a way of saying that the id is 1600+the id of the menu item+1. So, if the menu item's id is "1", the id passed to the include will be 160011, which will be unique.
The widget itself you can see is a <panel> control, again with a unique id. You can reference any of the properties defined in the template by using $SKINSHORTCUTS[<name of the property>]. Again, here the id of the panel is 1600$SKINSHORTCTUTS[id]1.
The content for the panel is defined in either the include Shelf_GenericSquare or Shelf_GenericPoster. The line
xml:
<include content="$PYTHON[$SKINSHORTCUTS[content1]]">
means that I am telling the script to evaluate the python snippet contained in the property "content1" to determine what is the correct include to use. Following are parameters that are needed for the include, like the id of the panel, and whether this widget is a Years widget, or a Music Genres widget (so I can show the icons I want for those) or whether there should be a label below the icon in the widget.
The lines
xml:
<content>
<item>
<icon>DefaultAddonNone.png</icon>
<thumb>DefaultAddonNone.png</thumb>
<visible>String.IsEmpty(Container(1600$SKINSHORTCUTS[id]1).ListItem(1).Label)</visible>
</item>
</content>
are a way (thanks @mr. V ) to show an icon that says there is no content in the case that the widget is empty (for example, you have an a watched movies widget, but you have not watched any movies yet).
And finally, the line
xml:
<content sortby="$SKINSHORTCUTS[sortby1]" sortorder="$SKINSHORTCUTS[sortorder1]" limit="$SKINSHORTCUTS[limit1]" target="$SKINSHORTCUTS[target1]">$SKINSHORTCUTS[path1]</content>
sets the content for the panel. The content comes from the path1 property, sort by from the sortby1 property, and so on.
I understand that perhaps this is a lot of information at one time. I hope it is useful to you.
Regards,
Bart