Text2skin-Skin erstellen
Diese Dokumentation gilt für die "1.0" Version des text2skin-plugins.
Genereller Aufbau des XML
Wer schon einmal mit XML gearbeitet hat, darf diesen Abschnitt überspringen.
XML-Dateien werden im Normalfall von einer Kontrollanweisung eingeleitet, die die Version und mögliche andere Attribute des benutzten XML-Formates enthalten kann.
<?xml version="1.0"?>
XML-Dateien sind in einer Baumstruktur angeordnet. Jedes XML-Dokument hat ein oberstes (Wurzel)-Element, welches seinerseits Unterelemente enthalten kann. Elementnamen werden in XML in spitze Klammern eingeschlossen, ein Schrägstrich vor dem Elementnamen kennzeichnet das Ende des Elements.
<element> <unterelement> </unterelement> </element>
Jedes Element kann Attribute enthalten, die weitere Eigenschaften des Elements kennzeichnen. Attribute folgen dem Elementnamen innerhalb der spitzen Klammern. Ein Attribut wird, gefolgt von einem Gleichheitszeichen und seinem Attributwert, eingeschlossen in Anführungszeichen. Mehrere Attribute werden durch Leerzeichen getrennt.
<element attribut="wert" zweitesattribut="anderer wert"> </element>
Leere Elemente (das sind solche die per Definition keine weiteren Elemente enthalten dürfen) müssen leer sein, auch ein Zeilenende zwischen dem öffnenden und dem schliessenden Tag ist verboten.
<element attribut="wert"></element>
Es gibt eine Möglichkeit, leere Elemente eleganter zu schreiben:
<element attribut="wert" />
Kommentare in XML-Dateien beginnen mit öffnender spitzer Klammer, Ausrufezeichen und zwei Bindestrichen:
<!-- Das ist eine Kommentarzeile zur Erläuterung des Skins. -->
Kommentare enden mit zwei Bindestrichen und der schließenden spitzen Klammer. Kommentare dürfen auch mehrzeilig sein, aber dürfen keine zwei Bindestriche unmittelbar hintereinander folgend enthalten.
Genereller Aufbau der Skin-Datei
Jede Skin-Datei (und zwar nur die mit der Endung .skin - die anderen sind weiterhin im bekannten Format) beginnt mit der o.a. Kontrollanweisung gefolgt von dem Wurzelelement <skin>. Dieses Element muss die Attribute screenBase, name und version enthalten, wobei letztere, die Version des Skin-Formates, "1.0" sein muss. Das zweite Attribut gibt den Namen an, der im VDR-OSD-Menü erscheint. Das erste, screenBase, kennzeichnet, ob das Skin relativ (relative)zum VDR-Setup oder absolut (absolute) auf einer Fläche von 720x576 zeichnet.
<?xml version="1.0"?> <skin version="1.0" name="brushed Aluminium" screenBase="relative"> . . . </skin>
Aufbau der einzelnen Sektionen
Die Einzelnen Darstellungen des VDR-OSD werden in mehreren <display>-Elementen verpackt. Welches Display gezeichnet wird kennzeichnet das Attribut id. Es gibt die Displays
- channelInfo,
- channelSmall,
- volume,
- message,
- replayInfo,
- replaySmall und
- menu
- audioTracks.
Jede Display-Definition beginnt mit der Vorgabe von Zeichen-Bereichen, sogenannten Fenstern (ähnlich der Backgrounds früher). Wieviele Fenster von welchen Farbtiefen anzeigbar sind ist abhängig von der verwendeten Ausgabehardware. Same Restrictions as before.
<display id="replayInfo"> <window x1="0" x2="619" y1="-113" y2="-84" bpp="4"/> <window x1="20" x2="99" y1="-83" y2="-44" bpp="4"/> . . . </display>
Zeichenobjekte
Auf diese Weise wurde eine Zeichenfläche bestimmt, auf der nun im Prinzip frei Objekte plaziert werden können. Dabei gibt es einfache Objekte
- rectangle = gefülltes Rechteck,
- text = statischer oder zusammengesetzter Text,
- image = Bild,
- ellipse = (Teil-)Kreis, Ellipse,
- slope = Kurve
erweiterte und zusammenhängende Objekte
- progress = Fortschrittsanzeige,
- scrolltext = mehrzeiliger Text,
- scrollbar = Scrollleiste
sowie Gruppierungs- und Spezialobjekte
- block - fasst mehrere Objekte zusammen,
- list - definiert die Liste im Menü,
- item - definiert ein Item der Liste.
Die einfachen Objekte beschreiben sich im wensentlichen selbst. Sie alle haben die Attribute x1, x2, y1 und y2, welche Position und Ausdehnung beschreiben (Ausnahme: image benötigt x und y, wenn das Bild nicht skaliert werden soll), sowie color, welches eine symbolische oder hexadezimale Farbe enthält. Bilder müssen desweiteren das Attribut path haben und können die Attribute bgColor und alpha (Transparenz von 0-255) enthalten. Texte können die Attribute align (left, right, center), Scrolltexte zusätzlich font enthalten. Ihr Unterelement ist der anzuzeigende Text. Ellipsen werden mit dem Attribut arc zu Teilkreisen, Kurven erhalten darüber ihre Richtung.
Scroll- und Fortschrittsleisten benötigen auch bgColor, Fortschrittsleisten zusätzlich current und total.
<image x="0" y="-70" path="Aluminium_volumebar.png"/> <rectangle x1="20" x2="99" y1="-83" y2="-44" color="#00000000"/> <text x1="42" x2="571" y1="-113" y2="-86" color="#FF000000" font="Osd">{ReplayTitle}</text> <progress x1="124" x2="577" y1="-70" y2="-55" color="#FF84ff00" bgColor="#FFFFFFFF" current="{ReplayPositionIndex}" total="{ReplayDurationIndex}"/> <scrolltext x1="24" y1="138" y2="-72" x2="583" font="helmetr.ttf:20" color="#AFFFFF00"> {PresentShortText} {PresentDescription} </scrolltext>
TrueType-Fonts
Im vorangegangenen Beispiel hat der Scrolltext als Font "helmetr.ttf:20". In diesem Fall versucht das Plugin zuerst im Plugin-Ordner im Unterordner fonts, danach im Skin-Ordner diese Datei zu öffnen. Gelingt dies wird das geladene Font in der angegebenen Größe zur Darstellung benutzt.
/etc/vdr/plugins/text2skin/fonts/helmetr.ttf /etc/vdr/plugins/text2skin/Aluminium/helmetr.ttf
Tokens und Texte
In dem letzten Beispiel werden ausserdem einige Texte benutzt, die in geschweiften Klammern notiert sind. Dies sind sogenannte Tokens, deren Inhalte von den gerade im VDR vorhandenen Informationen abhängen. Eine Liste aller Tokens wird hoffentlich demnächst ergänzt, bis dahin empfehle ich die Durchsicht des Aluminium-1.0-demo Skins. Generell dürfen Tokens auch zusammengesetzt und mit literalen Strings vermischt werden (siehe Scrolltext) und werden in Texten und Pfaden (für die Anzeige von Logos z.B.) ausgewertet.
<image x="0" y="0" path="logos/{ChannelName}.mng"/>
Jedes Objekt kann zusätzlich zu den objekteigenen Attributen eine Bedingung (Attribut condition) enthalten, deren Inhalt eine komplexe Funktion sein kann. Benutzt werden Bedingungen, um die Darstellung von Elementen (oder Blöcken) an die im VDR verfügbaren Inhalte zu binden. Eine Funktion kann auch ein Token sein, jedes Token welches keinen Inhalt hat evaluiert zu falsch. Zeichenketten innerhalb von Funktionen werden in einfachen Anführungszeichen notiert. Das Anführungszeichen selbst wird mit einem Backslash escaped.
<image x="20" y="-83" alpha="180" condition="file('replay/{ReplayMode}.png')" path="replay/{ReplayMode}.png"/> <image x="20" y="-83" alpha="180" condition="not(file('replay/{ReplayMode}.png'))" path="replay/common.png"/> <image x="314" y="-34" condition="{IsPlaying}" path="symbols/play_sml.xpm"/> <image x="334" y="-34" condition="{IsFastForward:2}" path="symbols/ffwd_sml.xpm"/> <image x="420" y="25" condition="or({HasVPS},{HasTimer},{IsRunning})" path="Aluminium_epgbottom.png"/>
Zeigt das Bild nur, wenn...
- ...die Datei existiert
- ...kein Logo existiert
- ...der ReplayMode gerade "Abspielen" ist
- ...der ReplayMode gerade "Vorwärts Stufe 2" ist (mit ":0" ist normales Replay ohne Multi-Speed und ohne ":X" ist jede Stufe gemeint)
- ...der aktuell angezeigte Event entweder VPS hat, oder gerade läuft, oder als Timer programmiert ist.
Token-Attribute
Manche Tokens können Attribute (das sind keine XML-Attribtue) tragen, die die Formatierung des Token-Inhalts beeinflussen. Bisher sind das alle Datum/Zeit-Tokens sowie {MenuTitle} und {MenuCurrent}. Attribute folgen dem Token-Namen nach einem Doppelpunkt. Ein Doppelpunkt im Attribut-Inhalt wird mit Backslash escaped.
<text .....>{DateTime:%H\:%M}</text>
Für die Datum/Zeit-Tokens gelten die Regeln von strftime (man strftime), für {MenuTitle} und {MenuCurrent} gibt es das Attribut "clean", welches den Text von Tabs und Hotkey-Zahlen befreit (Beispiel siehe unten bei Menü-Logos).
Komplexe Bedingungen und Block-Objekte
Mit komplexen Bedingungen und Block-Objekten lassen sich Anordnungen realisieren, die nur auf dem Vorhandensein einzelner Texte basieren. Folgende Beispiele sollen das verdeutlichen:
Anzeige eines Kanallogos mit Schatten, wenn Datei vorhanden, sonst transparent (aus HighTech256):
<rectangle x1="0" x2="67" y1="0" y2="51" color="#00000000" condition="not(file('logos/{ChannelName}.mng'))"/> <block condition="file('logos/{ChannelName}.mng')"> <rectangle x1="4" x2="67" y1="4" y2="51" color="#AF000000"/> <image x="0" y="0" path="logos/{ChannelName}.mng"/> </block>
Gruppierung eines Langtexts mit seinen Scroll-Objekten, die nur sichtbar sind wenn der Text länger ist als die Seite (auch HighTech256):
<block condition="{MenuText}"> <scrolltext x1="30" y1="60" x2="519" y2="343" color="#FFFFFFFF" font="Sml">{MenuText}</scrolltext> <image condition="or({CanScrollUp},{CanScrollDown})" x="561" y="52" path="menu-scrollbar.png"/> <scrollbar condition="or({CanScrollUp},{CanScrollDown})" x1="569" y1="69" x2="578" y2="315" color="#FF975000" bgColor="#DAB38D13"/> <image condition="and(not({CanScrollUp}),{CanScrollDown})" x="561" y="39" path="symbols/arrowup-off.png"/> <image condition="and(not({CanScrollUp}),{CanScrollDown})" x="561" y="319" path="symbols/arrowdown-on.png"/> <image condition="and({CanScrollUp},not({CanScrollDown}))" x="561" y="39" path="symbols/arrowup-on.png"/> <image condition="and({CanScrollUp},not({CanScrollDown}))" x="561" y="319" path="symbols/arrowdown-off.png"/> <image condition="and({CanScrollUp},{CanScrollDown})" x="561" y="39" path="symbols/arrowup-on.png"/> <image condition="and({CanScrollUp},{CanScrollDown})" x="561" y="319" path="symbols/arrowdown-on.png"/> </block>
Die Liste im Hauptmenü
Das spezielle Objekt "list" bestimmt im Menü den Anzeigebereich für eine Liste von Einträgen. Das Objekt hat nur die Attribute x1, y1, x2 und y2. Das erste Unterobjekt muss das spezielle Objekt item sein, dessen einziges Attribut height ist. Danach können wie gewohnt Objekte innerhalb der Liste plaziert werden. Die Höhe von "item" bestimmt, wieviel Platz ein einzelnes Listelement beinhaltet und dadurch auch, wieviele Listelemente auf einem Bildschirm darstellbar sind.
<list x1="24" y1="62" x2="569" y2="-82"> <item height="28"/> <text x1="25" x2="569" y1="3" y2="27" color="#AF00FFFF" font="Sml">{MenuGroup}</text> <text x1="25" x2="569" y1="3" y2="27" color="#AFFFFFFF" font="Sml">{MenuItem}</text> <rectangle x1="0" x2="579" y1="0" y2="27" color="#FF2B1B9E" condition="{IsMenuCurrent}"/> <text x1="22" x2="569" y1="0" y2="27" color="#AFFFFFFF" font="Osd">{MenuCurrent}</text> <text x1="0" x2="25" y1="0" y2="27" color="#AFFFFFFF" font="Osd" condition="{IsMenuCurrent}">-></text> </list>
Was etwas schwer zu verstehen sein mag, ist die Art und Weise wie diese Liste gerendert wird. Koordinaten von Objekten innerhalb der Liste sind stets relativ zum Anzeigebereich der Liste selbst. Jedes Objekt innerhalb der Liste wird mehrmals gezeichnet, und zwar pro Eintrag in der Liste, wobei die Y-Koordinaten bei jedem Zeichenvorgang um die Item-Höhe inkrementiert werden. Die Tokens {MenuCurrent}, {MenuItem} und {MenuGroup} werden zudem pro Tab (in eingeteilten Menüs wie z.B. Programm) gezeichnet, wohingegen die Tokens {IsMenuCurrent}, {IsMenuGroup} oder {IsMenuItem} nur einmal pro Listelement ausgewertet werden.
<text x1="25" x2="569" y1="3" y2="27" color="#AF00FFFF" font="Sml">{MenuGroup}</text> <text x1="25" x2="569" y1="3" y2="27" color="#AFFFFFFF" font="Sml">{MenuItem}</text> <rectangle x1="0" x2="579" y1="0" y2="27" color="#FF2B1B9E" condition="{IsMenuCurrent}"/>
Anlegen von Image-Maps für Menülogos
Die Variante ist nicht ganz so komfortabel wie in Plugins wie z. B. GraphTFT gelöst, ist aber meiner Meinung nach näher am VDR. Um ein Logo in Abhängigkeit des aktuell ausgewählten Elements anzuzeigen, würde man den gesäuberten Text (Attribut clean) des Elements (z. B.: "Aufzeichnungen") mit der Übersetzung einer Phrase vergleichen (z. B.: "Recordings"). Bei Plugins würde man mit dem Hauptmenüeintrag (z. B.: "MP3") des Plugins (z. B.: "mp3") vergleichen. (Beachte: Dieses Element ist nicht Teil der Liste, muss also auch ausserhalb von <list> notiert sein).
<image x="25" y="100" path="logos/schedule.png" condition="equal({MenuCurrent:clean},trans('Schedule'))"/> <image x="25" y="100" path="logos/channels.png" condition="equal({MenuCurrent:clean},trans('Channels'))"/> <image x="25" y="100" path="logos/timers.png" condition="equal({MenuCurrent:clean},trans('Timers'))"/> <image x="25" y="100" path="logos/music.png" condition="equal({MenuCurrent:clean},plugin('mp3'))"/>
Analog ist das Verfahren mit {MenuTitle:clean}, falls ein Logo für die aktuelle Menüseite gewünscht ist, statt das aktuell markierte Element zu kennzeichnen.
Liste aller Funktionen
- not - Negierung eines Ausdrucks - erwartet einen Parameter (Beispiel:
not(equal({PresentStartDateTime},{PresentVPSDateTime}))
) - and - wahr wenn alle Parameter wahr sind - erwartet zwei oder mehr Parameter (Beispiel:
and({CanScrollUp},{CanScrollDown})
) - or - wahr wenn ein Parameter wahr ist - siehe "and"
- equal - wahr wenn beide Parameter identisch sind - erwartet zwei Parameter
- file - gibt den Parameter zurück, wenn er als Datei im Skin-Ordner existiert, sonst falsch - erwartet einen Parameter (Beispiel:
file('logos/{ChannelName}.png')
) - trans - gibt die Übersetzung nach i18n des Parameters zurück, falsch wenn nicht vorhanden (Beispiel:
equal('Kanäle', trans('Channels'))
)
Wie evtl. schon aufgefallen, werden Zeichenketten in Funktionen in einfachen Anführungszeichen notiert, es sei denn die Zeichenkette besteht nur aus einem Token. In diesem Fall dürfen die Anführungszeichen ausgelassen werden. not({MenuText})
" ist also eine Kurzform von not('{MenuText}')
.
Skalierung von Bildern
Mit dieser Funktion wird es erstmals ermöglicht, Bilder abhängig von den OSD-Einstellungen zu skalieren. Wenn für das entsprechende image Tags anstatt der Attribute x und y die Attribute x1, x2, y1 und y2 mit ihren relativen Angaben genutzt werden, wird das Bild vor der Ausgabe entsprechend der berechneten Größe skaliert. Das Attribut colors gibt hierbei die Anzahl der Farben an, die das Bild nach der neuberechnung maximal haben darf.
Farben
Farben werden im RGB-Format mit Transparenz angegeben. Also etwa
color=#AARRGGBB
- A = Alphawert (Transparenz)
- R = Rotwert
- G = Grünwert
- B = Blauwert
Ein paar Beispiele
AARRGGBB color=#00000000 = Schwarz, voll transparent (durchsichtig) color=#FF000000 = Schwarz, volle Deckkraft color=#7F000000 = Schwarz, halb durchscheinend color=#7FFFFFFF = Weiß, halb durchscheinend
und natürlich alle möglichen Zwischentöne und Transparenzen.
Colorpicker
Fonts
Es gibt drei vorgegebene Fonts
- Osd
- Fix
- Sml
Wenn man die Freetype-Bibliothek installiert hat und beim compilieren aktiviert hat, lässt sich zusätzlich jeder TrueType-Font verwenden, der unter
- /etc/vdr/plugins/text2skin/fonts/
oder
- /etc/vdr/plugins/text2skin/SkinName/
installiert ist.
In der Skindatei gibt man den Fontnamen,
font="Osd"
oder, bei Truetype-Fonts, den Font-Dateinamen und die gewünschte Größe und Breite
font="helmetr.ttf:Größe[,Breite]"
an