• Level: AddOn Profi
  • Tools: XML Lua-Editor, Original Interfacedateien von WoW
  • Zeitaufwand: ca. 25 min


Motivation

Mit Patch 1.10 hat Blizzard den AddOn-Entwicklern einen lange gehegten Wunsch erfüllt: Die Möglichkeit UI-Elemente dynamisch durch Lua-Code zu erzeugen. Bisher galt der Grundsatz: Alles was auf dem UI sichtbar ist, muss vorher in einer XML-File als Element deklariert werden. Die Nachteile dieser Methode liegen auf der Hand:

  • Die genaue Zahl der verfügbaren UI-Elemente wird zur Compile-Zeit festgelegt. Beispiel: Flexbar. Das AddOn besitzt von Haus aus 120 Buttons, obwohl wahrscheinlich die allerwenigsten Spieler jemals so viele Knöpfe benutzen werden. Andererseits kann es genausogut sein, dass ein Spieler gerade 125 Buttons für sein perfektes UI braucht. Diese Problematik ist in dem statischen Pre-1.10-System nicht lösbar.
  • Das Hinzufügen neuer UI-Elemente verlangt zwingend das Erstellen einer XML-Datei. Insbesondere ist es also nicht möglich, UI-Elemente nur durch ein Makro zu erstellen
  • Das Recyclen von UI-Elementen gestaltet sich als enorm schwierig. Nehmen wir an, unser AddOn begrüßt den Benutzer mit einem Hello!-Knopf, der nur einmal beim Start gezeigt werden soll. Sobald der Spieler den Button weggeklickt hat, lungert dieser nutzlos im Speicher herum. Mit den neuen 1.10-Features können wir diesen Button sobald er nicht mehr benötigt wird an anderer Stelle wiederverwenden und auf diese Weise Ressourcen und Code sparen.

Erste Schritte

Für dieses HowTo werden wir einen normalen Knopf erstellen, basierend auf dem GameMenuButtonTemplate von Blizzard. Dieses Beispiel eignet sich nicht nur hervorragend als Anschauung für die Benutzung von CreateFrame(), sondern bietet außerdem auch einen Blick in die Tücken und Kinderkrankheiten dieser noch jungen Technik. Ausgangspunkt unserer Reise ist folgender XML-Code:

  1. Button name="my_Button" inherits="GameMenuButtonTemplate" parent="UIParent"
  2. Size AbsDimension x="100" y="50"/
  3. /Size Anchors Anchor point="CENTER"/
  4. /Anchors Scripts OnClick DEFAULT_CHATFRAME:AddMessage("Hello World!");
  5. /OnClick
  6. /Scripts
  7. /Button

Unser Ziel ist ein Block Lua-Code, der einen identischen Knopf wie dieser XML-Block erstellt. Na, das kann ja so schwer gar nicht werden… 😉
Aber unerwarteterweise finden wir eine der größten Hürden bereits in der ersten Zeile unseres XML-Codes: CreateFrame() erlaubt in seiner jetzigen Form keine Verwendung von Templates!
Der Grund dafür ist denkbar einfach: WoW löst sämtliche Verweise auf Templates bereits beim Laden des UIs auf, die Templates selbst werden niemals als Objekte im Speicher erstellt! Darüberhinaus akzeptiert CreateFrame() aber auch gar keinen Parameter von dem man Elementeigenschaften ableiten könnte. Unsere Aufgabe ist es nun also, die Templateverweise von Hand aufzulösen. Ein Blick in die UIPanelTemplates.XML von Blizzard verrät uns, dass GameMenuButtonTemplate seinerseits wieder von UIPanelButtonTemplate ableitet. Dieses Template verwendet selbst jedoch auch wieder Templates für Schriftarten und Texturen… Kurz gesagt: Ein heilloses Durcheinander 😮
Der vollständig aufgelöste XML-Code sieht so aus:

  1. Button name="my_Button" parent="UIParent"
  2. Size AbsDimension x="100" y="50"/
  3. /Size Anchors Anchor point="CENTER" relativeTo="UIParent"
  4. relativePoint="CENTER"/ /Anchors !-NormalText inherits="GameFontHighlight"/ - NormalText
  5. font="FontsFRIZQT__.TTF" FontHeight AbsValue val="12"/
  6. /FontHeight Color r="1.0" g="1.0" b="1.0"/
  7. Shadow Offset AbsDimension x="1" y="-1"/
  8. /Offset Color r="0" g="0" b="0"/
  9. /Shadow
  10. /NormalText !-DisabledText inherits="GameFontDisable"
  11. /- DisabledText font="FontsFRIZQT__.TTF" FontHeight AbsValue val="12"/
  12. /FontHeight Color r="0.5" g="0.5" b="0.5"/
  13. Shadow Offset AbsDimension x="1" y="-1"/
  14. /Offset Color r="0" g="0" b="0"/
  15. /Shadow
  16. /DisabledText !-HighlightText inherits="GameFontHighlight"/- HighlightText
  17. font="FontsFRIZQT__.TTF" FontHeight AbsValue val="12"/
  18. /FontHeight Color r="1.0" g="1.0" b="1.0"/
  19. Shadow Offset AbsDimension x="1" y="-1"/
  20. /Offset Color r="0" g="0" b="0"/
  21. /Shadow
  22. /HighlightText NormalTexture file="InterfaceButtonsUI-Panel-Button-Up" TexCoords left="0"
  23. right="0.625" top="0" bottom="0.6875"/
  24. /NormalTexture PushedTexture file="InterfaceButtonsUI-Panel-Button-Down"
  25. TexCoords left="0" right="0.625" top="0" bottom="0.6875"/
  26. /PushedTexture DisabledTexture file="InterfaceButtonsUI-Panel-Button-Disabled"
  27. TexCoords left="0" right="0.625" top="0" bottom="0.6875"/
  28. /DisabledTexture HighlightTexture file="InterfaceButtonsUI-Panel-Button-Highlight"
  29. alphaMode="ADD" TexCoords left="0" right="0.625" top="0" bottom="0.6875"/
  30. /HighlightTexture Scripts OnClick DEFAULT_CHATFRAME:AddMessage("Hello World!");
  31. /OnClick
  32. /Scripts
  33. /Button

Versucht diese änderung anhand von Blizzards UI-Dateien selbst nachzuvollziehen. Das Auflösen von Templates ist nicht schwer, aber es stellt ein unverzichtbares Werkzeug im Umgang mit CreateFrame() dar!

Der Sprung zu Lua

Alles was jetzt noch zu tun bleibt, ist diesen unübersichtlichen XML-Klotz in die neuen Lua-Funktionen zu pressen. Den Anfang macht dabei unser heißgeliebtes CreateFrame():

  1. CreateFrameSkript-Sektion