Kolja Strohm пре 3 дана
родитељ
комит
1515b284c6
38 измењених фајлова са 2520 додато и 562 уклоњено
  1. 5 0
      FactoryCraft/BasicBlocks.cpp
  2. 1 0
      FactoryCraft/BasicBlocks.h
  3. 4 4
      FactoryCraft/BlockType.cpp
  4. 7 5
      FactoryCraft/Entity.cpp
  5. 1 0
      FactoryCraft/FactoryCraft.vcxproj
  6. 6 0
      FactoryCraft/FactoryCraft.vcxproj.filters
  7. 2 3
      FactoryCraft/FireBasedProcessingBlockComponent.cpp
  8. 11 9
      FactoryCraft/FluidContainer.cpp
  9. 1 1
      FactoryCraft/FluidContainer.h
  10. 3 4
      FactoryCraft/Game.cpp
  11. 6 3
      FactoryCraft/GameClient.cpp
  12. 9 5
      FactoryCraft/GrowingPlant.cpp
  13. 10 1
      FactoryCraft/Inventory.cpp
  14. 5 4
      FactoryCraft/Item.cpp
  15. 3 1
      FactoryCraft/Item.h
  16. 32 36
      FactoryCraft/ItemFilter.cpp
  17. 11 10
      FactoryCraft/ItemFilter.h
  18. 14 7
      FactoryCraft/ItemType.cpp
  19. 5 3
      FactoryCraft/ItemType.h
  20. 94 39
      FactoryCraft/Player.cpp
  21. 2 2
      FactoryCraft/Player.h
  22. 2 9
      FactoryCraft/Quest.cpp
  23. 1 1
      FactoryCraft/Quest.h
  24. 179 140
      FactoryCraft/QuestDialog.cpp
  25. 174 146
      FactoryCraft/QuestRequirement.cpp
  26. 13 18
      FactoryCraft/QuestRequirement.h
  27. 45 40
      FactoryCraft/QuestReward.cpp
  28. 5 6
      FactoryCraft/QuestReward.h
  29. 31 41
      FactoryCraft/Recipie.cpp
  30. 3 3
      FactoryCraft/Recipie.h
  31. 10 13
      FactoryCraft/RecipieLoader.cpp
  32. 1 1
      FactoryCraft/RecipieLoader.h
  33. 11 5
      FactoryCraft/TreeSeblingBlock.cpp
  34. 1 1
      FactoryCraft/TreeSeblingBlock.h
  35. 1767 0
      FactoryCraft/UIMLBuilder.h
  36. 1 0
      Windows Version/Windows Version.vcxproj
  37. 6 0
      Windows Version/Windows Version.vcxproj.filters
  38. 38 1
      Windows Version/data/quests/quests.json

+ 5 - 0
FactoryCraft/BasicBlocks.cpp

@@ -20,6 +20,11 @@ void BasicBlock::addComponent(BlockComponent* component)
     components.add(component);
 }
 
+BlockComponent* BasicBlock::zComponent(int index) const
+{
+    return components.z(index);
+}
+
 Framework::XML::Element* BasicBlock::getTargetUIML() const
 {
     Framework::XML::Element* element

+ 1 - 0
FactoryCraft/BasicBlocks.h

@@ -22,6 +22,7 @@ public:
         int dimensionId,
         bool hasInventory);
     void addComponent(BlockComponent* component);
+    BlockComponent* zComponent(int index) const;
     virtual Framework::XML::Element* getTargetUIML() const override;
     virtual bool onTick(
         TickQueue* zQueue, int numTicks, bool& blocked) override;

+ 4 - 4
FactoryCraft/BlockType.cpp

@@ -4,6 +4,7 @@
 #include "Dimension.h"
 #include "Game.h"
 #include "MultiblockStructure.h"
+#include "UIMLBuilder.h"
 
 using namespace Framework;
 
@@ -163,10 +164,9 @@ void BlockType::writeTypeInfo(StreamWriter* zWriter) const
 
 Framework::XML::Element* BlockType::getTargetUIML() const
 {
-    return new Framework::XML::Element(
-        Framework::Text(
-            "<targetInfo><text id=\"type\" width=\"auto\" height=\"auto\">")
-        + name + "</text></targetInfo>");
+    return UIMLBuilder::createContainer()
+        ->addChild(UIMLBuilder::createTextAuto(name)->setID("type")->build())
+        ->build();
 }
 
 Block* BlockType::loadBlock(Framework::Vec3<int> position,

+ 7 - 5
FactoryCraft/Entity.cpp

@@ -11,6 +11,7 @@
 #include "ItemStack.h"
 #include "ItemType.h"
 #include "Quest.h"
+#include "UIMLBuilder.h"
 
 ActionTarget::ActionTarget(Framework::Vec3<int> blockPos, Direction blockSide)
     : blockPos(blockPos),
@@ -1316,11 +1317,12 @@ void Entity::onFall(float collisionSpeed)
 
 Framework::XML::Element* Entity::getTargetUIML() const
 {
-    return new Framework::XML::Element(
-        Framework::Text(
-            "<targetInfo><text id=\"type\" width=\"auto\" height=\"auto\">")
-        + Game::INSTANCE->zEntityType(typeId)->getName()
-        + "</text></targetInfo>");
+    return UIMLBuilder::createContainer()
+        ->addChild(UIMLBuilder::createTextAuto(
+            Game::INSTANCE->zEntityType(typeId)->getName())
+                ->setID("type")
+                ->build())
+        ->build();
 }
 
 void Entity::setChatSecurityLevel(int level)

+ 1 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -217,6 +217,7 @@
     <ClInclude Include="UIElement.h" />
     <ClInclude Include="UIFuelState.h" />
     <ClInclude Include="UIInventory.h" />
+    <ClInclude Include="UIMLBuilder.h" />
     <ClInclude Include="UIObservable.h" />
     <ClInclude Include="UIReference.h" />
     <ClInclude Include="UIText.h" />

+ 6 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -127,6 +127,9 @@
     <Filter Include="world\generator\biom\plants">
       <UniqueIdentifier>{5e366c8e-008c-4c5b-935e-ea58adcdc94c}</UniqueIdentifier>
     </Filter>
+    <Filter Include="UI\Builder">
+      <UniqueIdentifier>{e4ccd6d2-96b0-442e-81d3-ae23ce66d438}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Chunk.h">
@@ -510,6 +513,9 @@
     <ClInclude Include="PlantConfig.h">
       <Filter>world\generator\biom\plants</Filter>
     </ClInclude>
+    <ClInclude Include="UIMLBuilder.h">
+      <Filter>UI\Builder</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">

+ 2 - 3
FactoryCraft/FireBasedProcessingBlockComponent.cpp

@@ -5,6 +5,7 @@
 #include "Recipie.h"
 #include "RecipieList.h"
 #include "RecipieLoader.h"
+#include "UIMLBuilder.h"
 
 FireBasedProcessingBlockComponent::FireBasedProcessingBlockComponent()
     : BlockComponent(),
@@ -327,8 +328,6 @@ FireBasedProcessingBlockComponent::getTooltipUIML() const
 {
     if (currentRecipie)
     {
-        Framework::XML::Element* result = new Framework::XML::Element(
-            "<text width=\"auto\" height=\"auto\"></text>");
         Framework::Text content;
         content.append() << "Processing: ";
         int first = 1;
@@ -347,7 +346,7 @@ FireBasedProcessingBlockComponent::getTooltipUIML() const
             << " ("
             << (int)((ticksNeeded / currentRecipie->getTicksNeeded()) * 100)
             << "%)";
-        result->setText(content);
+        return UIMLBuilder::createTextAuto(content)->build();
     }
     return 0;
 }

+ 11 - 9
FactoryCraft/FluidContainer.cpp

@@ -7,6 +7,7 @@
 #include "Entity.h"
 #include "FluidBlock.h"
 #include "Game.h"
+#include "UIMLBuilder.h"
 
 FluidContainerItem::FluidContainerItem(int itemTypeId, Framework::Text name)
     : Item(itemTypeId, name),
@@ -64,22 +65,23 @@ void FluidContainerItem::onPlaced()
     setAmount(fluidAmount - 1000);
 }
 
-Framework::Text FluidContainerItem::getTooltipUIML() const
+UIMLTooltipBuilder* FluidContainerItem::getTooltipUIML() const
 {
-    Framework::Text uiml = "<tip><text width=\"auto\" height=\"auto\">";
-    uiml.append() << getName();
+    UIMLTooltipBuilder* builder = UIMLBuilder::createTooltip();
+    Framework::Text content;
+    content.append() << getName();
     if (fluidTypeId != 0)
     {
-        uiml.append() << "\nFluid: "
-                      << Game::INSTANCE->zBlockType(fluidTypeId)->getName()
-                      << "\nAmount: " << fluidAmount << " L";
+        content.append() << "\nFluid: "
+                         << Game::INSTANCE->zBlockType(fluidTypeId)->getName()
+                         << "\nAmount: " << fluidAmount << " L";
     }
     else
     {
-        uiml.append() << "\nEmpty";
+        content.append() << "\nEmpty";
     }
-    uiml.append() << "</text></tip>";
-    return uiml;
+    return UIMLBuilder::createTooltip()->addElement(
+        UIMLBuilder::createTextAuto(content)->build());
 }
 
 bool FluidContainerItem::applyFoodEffects(Entity* zTarget)

+ 1 - 1
FactoryCraft/FluidContainer.h

@@ -22,7 +22,7 @@ public:
     virtual bool canBePlacedAt(
         int dimensionId, Framework::Vec3<int> worldPos) const override;
     virtual void onPlaced();
-    virtual Framework::Text getTooltipUIML() const override;
+    virtual UIMLTooltipBuilder* getTooltipUIML() const override;
     virtual bool applyFoodEffects(Entity* zTarget) override;
     virtual bool canApplyFoodEffectsFully(Entity* zTarget) const override;
 

+ 3 - 4
FactoryCraft/Game.cpp

@@ -633,12 +633,11 @@ void Game::api(Framework::InMemoryBuffer* zRequest, GameClient* zOrigin)
         { // crafting uiml request
             int id;
             zRequest->lese((char*)&id, 4);
-            Text uiml = recipies->getCrafingUIML(id);
+            Framework::XML::Element* uiml = recipies->getCrafingUIML(id);
             Text dialogId = "crafting_";
             dialogId += id;
-            uiController->addDialog(new UIDialog(dialogId,
-                zOrigin->zEntity()->getId(),
-                new Framework::XML::Element(uiml)));
+            uiController->addDialog(
+                new UIDialog(dialogId, zOrigin->zEntity()->getId(), uiml));
             break;
         }
     case 6:

+ 6 - 3
FactoryCraft/GameClient.cpp

@@ -219,10 +219,13 @@ void GameClient::sendTypes()
             char len = (char)t->getName().getLength();
             client->zForegroundWriter()->schreibe((char*)&len, 1);
             client->zForegroundWriter()->schreibe(t->getName().getText(), len);
-            short tlen = (short)t->getTooltipUIML().getLength();
+            Framework::XML::Element* tooltip = t->getTooltipUIML();
+            Framework::Text tooltipText
+                = tooltip ? tooltip->toString() : Framework::Text("");
+            short tlen = (short)tooltipText.getLength();
             client->zForegroundWriter()->schreibe((char*)&tlen, 2);
-            client->zForegroundWriter()->schreibe(
-                t->getTooltipUIML().getText(), tlen);
+            client->zForegroundWriter()->schreibe(tooltipText.getText(), tlen);
+            tooltip->release();
             if (t->zModel())
             {
                 t->zModel()->writeTo(client->zForegroundWriter());

+ 9 - 5
FactoryCraft/GrowingPlant.cpp

@@ -2,6 +2,7 @@
 
 #include "Dimension.h"
 #include "Game.h"
+#include "UIMLBuilder.h"
 
 GrowthState::GrowthState(float percentage, ModelInfo* model)
     : ReferenceCounter(),
@@ -112,11 +113,14 @@ TickSourceType GrowingPlantBlock::isTickSource() const
 
 Framework::XML::Element* GrowingPlantBlock::getTargetUIML() const
 {
-    return new Framework::XML::Element(
-        Framework::Text("<targetInfo><text width=\"auto\" height=\"auto\">")
-        + name + "\n" + "Growth: "
-        + Framework::Text((int)(seblingTicks / (float)seblingTicksMax * 100.f))
-        + "%</text></targetInfo>");
+    return UIMLBuilder::createContainer()
+        ->addChild(UIMLBuilder::createTextAuto(
+            name + "\n" + "Growth: "
+            + Framework::Text(
+                (int)(seblingTicks / (float)seblingTicksMax * 100.f))
+            + "%")
+                ->build())
+        ->build();
 }
 
 GrowingPlantBlock* GrowingPlantBlock::addGrowthState(GrowthState* state)

+ 10 - 1
FactoryCraft/Inventory.cpp

@@ -11,6 +11,7 @@
 #include "ItemStack.h"
 #include "ItemType.h"
 #include "NetworkMessage.h"
+#include "UIMLBuilder.h"
 
 using namespace Framework;
 
@@ -863,7 +864,15 @@ void Inventory::inventoryApi(Framework::StreamReader* zRequest,
                 if (slot->getId() == slotId)
                 {
                     if (slot->zStack() && slot->zStack()->zItem())
-                        uiml = slot->zStack()->zItem()->getTooltipUIML();
+                    {
+                        Framework::XML::Element* element
+                            = slot->zStack()
+                                  ->zItem()
+                                  ->getTooltipUIML()
+                                  ->build();
+                        uiml = element->toString();
+                        element->release();
+                    }
                 }
             }
             short len = (short)uiml.getLength();

+ 5 - 4
FactoryCraft/Item.cpp

@@ -4,6 +4,7 @@
 
 #include "Block.h"
 #include "Game.h"
+#include "UIMLBuilder.h"
 
 Item::Item(int itemTypeId, Framework::Text name)
     : ReferenceCounter(),
@@ -146,10 +147,10 @@ void Item::onPlaced()
     hp = 0;
 }
 
-Framework::Text Item::getTooltipUIML() const
+UIMLTooltipBuilder* Item::getTooltipUIML() const
 {
-    return Framework::Text("<tip><text width=\"auto\" height=\"auto\">") + name
-         + "</text></tip>";
+    return UIMLBuilder::createTooltip()->addElement(
+        UIMLBuilder::createTextAuto(name)->build());
 }
 
 void Item::applyInventoryEffects(Entity* zTarget) {}
@@ -180,7 +181,7 @@ Item* ItemJsonType::fromJson(Framework::JSON::JSONObject* zJson) const
         zJson->asObject()->zValue("type")->asString()->getString());
     Item* result = type->createItem();
     for (auto attribute = zJson->asObject()->getFields(); attribute;
-         attribute++)
+        attribute++)
     {
         if (attribute.val().istGleich("type")) continue;
         type->setItemAttribute(

+ 3 - 1
FactoryCraft/Item.h

@@ -9,6 +9,8 @@ class BlockType;
 class StoneToolItemType;
 class Entity;
 
+class UIMLTooltipBuilder;
+
 class Item : public virtual Framework::ReferenceCounter
 {
 protected:
@@ -55,7 +57,7 @@ public:
     virtual bool canBePlacedAt(
         int dimensionId, Framework::Vec3<int> worldPos) const;
     virtual void onPlaced();
-    virtual Framework::Text getTooltipUIML() const;
+    virtual UIMLTooltipBuilder* getTooltipUIML() const;
 
     virtual void applyInventoryEffects(Entity* zTarget);
     virtual void removeInventoryEffects(Entity* zTarget);

+ 32 - 36
FactoryCraft/ItemFilter.cpp

@@ -5,6 +5,7 @@
 #include "ItemSlot.h"
 #include "ItemStack.h"
 #include "ItemType.h"
+#include "UIMLBuilder.h"
 
 ItemFilter::ItemFilter()
     : ReferenceCounter()
@@ -76,40 +77,35 @@ bool CombinedItemFilter::matchTargetSlot(ItemSlot* zSlot) const
     return result;
 }
 
-Framework::Text CombinedItemFilter::getLogicUIML() const
+UIMLItemFilterBuilder* CombinedItemFilter::getUIML() const
 {
     if (filters.getEintragAnzahl() == 0)
     {
-        return "";
+        throw std::runtime_error(
+            "Cannot build UIML for CombinedItemFilter with no filters");
     }
     if (filters.getEintragAnzahl() == 1)
     {
-        return filters.z(0)->getLogicUIML();
+        return filters.z(0)->getUIML();
     }
     else
     {
-        Framework::Text result = "<operator result_0_0=\"";
-        result.append() << (int)op(0, 0) << "\" result_0_1=\"" << (int)op(0, 1)
-                        << "\" result_1_0=\"" << (int)op(1, 0)
-                        << "\" result_1_1=\"" << (int)op(1, 1) << "\">";
-        int openCount = 1;
-        for (int i = 0; i < filters.getEintragAnzahl() - 1; i++)
+        UIMLItemFilterBuilder* builder = 0;
+        for (int i = 0; i < filters.getEintragAnzahl(); i++)
         {
-            if (i < filters.getEintragAnzahl() - 2)
+            if (builder == 0)
             {
-                result.append()
-                    << filters.z(i)->getLogicUIML() << "<operator result_0_0=\""
-                    << (int)op(0, 0) << "\" result_0_1=\"" << (int)op(0, 1)
-                    << "\" result_1_0=\"" << (int)op(1, 0) << "\" result_1_1=\""
-                    << (int)op(1, 1) << "\">";
+                builder = filters.z(i)->getUIML();
             }
             else
             {
-                filters.z(i)->getLogicUIML();
-                filters.z(i + 1)->getLogicUIML();
+                builder = UIMLBuilder::createOperatorItemFilter()
+                              ->setOperator(op)
+                              ->setOperands(builder, filters.z(i)->getUIML())
+                              ->build();
             }
         }
-        return result;
+        return builder;
     }
 }
 
@@ -381,9 +377,9 @@ bool AnyItemFilter::matchItem(const Item* zItem) const
     return true;
 }
 
-Framework::Text AnyItemFilter::getLogicUIML() const
+UIMLItemFilterBuilder* AnyItemFilter::getUIML() const
 {
-    return "<anyItem/>";
+    return UIMLBuilder::createAnyItemFilter()->build();
 }
 
 AnyItemFilterFactory::AnyItemFilterFactory()
@@ -423,11 +419,11 @@ bool TypeItemFilter::matchItem(const Item* zItem) const
     return zItem->zItemType() == type;
 }
 
-Framework::Text TypeItemFilter::getLogicUIML() const
+UIMLItemFilterBuilder* TypeItemFilter::getUIML() const
 {
-    Framework::Text result = "<attribute name=\"Type\" operator=\"=\" value=\"";
-    result.append() << type->getId() << "\"/>";
-    return result;
+    return UIMLBuilder::createItemAttributeFilter()
+        ->requireAttributeEquals("Type", Framework::Text() += type->getId())
+        ->build();
 }
 
 void TypeItemFilter::setType(const ItemType* type)
@@ -491,9 +487,9 @@ bool SpecificSlotFilter::matchTargetSlot(ItemSlot* zSlot) const
     return targetSlotId == zSlot->getId();
 }
 
-Framework::Text SpecificSlotFilter::getLogicUIML() const
+UIMLItemFilterBuilder* SpecificSlotFilter::getUIML() const
 {
-    return "<anyItem/>";
+    return UIMLBuilder::createAnyItemFilter()->build();
 }
 
 SourceSlotBlacklistFilter::SourceSlotBlacklistFilter()
@@ -519,9 +515,9 @@ bool SourceSlotBlacklistFilter::matchTargetSlot(ItemSlot* zSlot) const
     return 1;
 }
 
-Framework::Text SourceSlotBlacklistFilter::getLogicUIML() const
+UIMLItemFilterBuilder* SourceSlotBlacklistFilter::getUIML() const
 {
-    return "<anyItem/>";
+    return UIMLBuilder::createAnyItemFilter()->build();
 }
 
 TargetSlotBlacklistFilter::TargetSlotBlacklistFilter()
@@ -547,9 +543,9 @@ bool TargetSlotBlacklistFilter::matchTargetSlot(ItemSlot* zSlot) const
     return 1;
 }
 
-Framework::Text TargetSlotBlacklistFilter::getLogicUIML() const
+UIMLItemFilterBuilder* TargetSlotBlacklistFilter::getUIML() const
 {
-    return "<anyItem/>";
+    return UIMLBuilder::createAnyItemFilter()->build();
 }
 
 GroupItemFilter::GroupItemFilter()
@@ -568,7 +564,7 @@ bool GroupItemFilter::matchItem(const Item* zItem) const
     return false;
 }
 
-Framework::Text GroupItemFilter::getLogicUIML() const
+UIMLItemFilterBuilder* GroupItemFilter::getUIML() const
 {
     CombinedItemFilter filter;
     for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
@@ -598,7 +594,7 @@ Framework::Text GroupItemFilter::getLogicUIML() const
         }
     }
     filter.setOp([](bool a, bool b) { return a || b; });
-    return filter.getLogicUIML();
+    return filter.getUIML();
 }
 
 void GroupItemFilter::addGroup(const Framework::Text group)
@@ -670,9 +666,9 @@ bool TargetSlotNameItemFilter::matchTargetSlot(ItemSlot* zSlot) const
     return zSlot->getName().istGleich(slotName);
 }
 
-Framework::Text TargetSlotNameItemFilter::getLogicUIML() const
+UIMLItemFilterBuilder* TargetSlotNameItemFilter::getUIML() const
 {
-    return "<anyItem/>";
+    return UIMLBuilder::createAnyItemFilter()->build();
 }
 
 SourceSlotNameItemFilter::SourceSlotNameItemFilter(
@@ -691,7 +687,7 @@ bool SourceSlotNameItemFilter::matchTargetSlot(ItemSlot* zSlot) const
     return 1;
 }
 
-Framework::Text SourceSlotNameItemFilter::getLogicUIML() const
+UIMLItemFilterBuilder* SourceSlotNameItemFilter::getUIML() const
 {
-    return "<anyItem/>";
+    return UIMLBuilder::createAnyItemFilter()->build();
 }

+ 11 - 10
FactoryCraft/ItemFilter.h

@@ -8,6 +8,7 @@
 class Item;
 class ItemType;
 class ItemSlot;
+class UIMLItemFilterBuilder;
 
 class ItemFilter : public virtual Framework::ReferenceCounter
 {
@@ -16,7 +17,7 @@ public:
     virtual bool matchItem(const Item* zItem) const;
     virtual bool matchSourceSlot(ItemSlot* zSlot) const;
     virtual bool matchTargetSlot(ItemSlot* zSlot) const;
-    virtual Framework::Text getLogicUIML() const = 0;
+    virtual UIMLItemFilterBuilder* getUIML() const = 0;
 };
 
 class CombinedItemFilter : public ItemFilter
@@ -32,7 +33,7 @@ public:
     bool matchItem(const Item* zItem) const override;
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
-    Framework::Text getLogicUIML() const override;
+    UIMLItemFilterBuilder* getUIML() const override;
     void addFilter(ItemFilter* filter);
     const Framework::RCArray<ItemFilter>& getFilters() const;
     void setOp(std::function<bool(bool, bool)> op);
@@ -58,7 +59,7 @@ class AnyItemFilter : public ItemFilter
 public:
     AnyItemFilter();
     bool matchItem(const Item* zItem) const override;
-    Framework::Text getLogicUIML() const override;
+    UIMLItemFilterBuilder* getUIML() const override;
 };
 
 class AnyItemFilterFactory : public SubTypeFactory<ItemFilter, AnyItemFilter>
@@ -81,7 +82,7 @@ private:
 public:
     TypeItemFilter();
     bool matchItem(const Item* zItem) const override;
-    Framework::Text getLogicUIML() const override;
+    UIMLItemFilterBuilder* getUIML() const override;
     void setType(const ItemType* type);
     const ItemType* zType() const;
 };
@@ -108,7 +109,7 @@ public:
     SpecificSlotFilter(int sourceSlotId, int targetSlotId);
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
-    Framework::Text getLogicUIML() const override;
+    UIMLItemFilterBuilder* getUIML() const override;
 };
 
 class SourceSlotBlacklistFilter : public ItemFilter
@@ -121,7 +122,7 @@ public:
     void addBlackListSlotId(int id);
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
-    Framework::Text getLogicUIML() const override;
+    UIMLItemFilterBuilder* getUIML() const override;
 };
 
 class TargetSlotBlacklistFilter : public ItemFilter
@@ -134,7 +135,7 @@ public:
     void addBlackListSlotId(int id);
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
-    Framework::Text getLogicUIML() const override;
+    UIMLItemFilterBuilder* getUIML() const override;
 };
 
 class GroupItemFilter : public ItemFilter
@@ -145,7 +146,7 @@ private:
 public:
     GroupItemFilter();
     bool matchItem(const Item* zItem) const override;
-    Framework::Text getLogicUIML() const override;
+    UIMLItemFilterBuilder* getUIML() const override;
     void addGroup(const Framework::Text group);
     const Framework::RCArray<Framework::Text>& getGroups() const;
 };
@@ -173,7 +174,7 @@ public:
     TargetSlotNameItemFilter(const Framework::Text& slotName);
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
-    Framework::Text getLogicUIML() const override;
+    UIMLItemFilterBuilder* getUIML() const override;
 };
 
 class SourceSlotNameItemFilter : public ItemFilter
@@ -185,5 +186,5 @@ public:
     SourceSlotNameItemFilter(const Framework::Text& slotName);
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
-    Framework::Text getLogicUIML() const override;
+    UIMLItemFilterBuilder* getUIML() const override;
 };

+ 14 - 7
FactoryCraft/ItemType.cpp

@@ -7,11 +7,12 @@
 #include "Game.h"
 #include "ItemSkill.h"
 #include "ItemStack.h"
+#include "UIMLBuilder.h"
 
 ItemType::ItemType()
     : ReferenceCounter(),
       name(""),
-      tooltipUIML(""),
+      tooltipUIML(0),
       model(0),
       maxStackSize(0),
       groups()
@@ -20,6 +21,7 @@ ItemType::ItemType()
 ItemType::~ItemType()
 {
     if (model) model->release();
+    if (tooltipUIML) tooltipUIML->release();
 }
 
 void ItemType::loadSuperItem(
@@ -167,11 +169,12 @@ int ItemType::getId() const
 void ItemType::setName(Framework::Text name)
 {
     this->name = name;
-    if (!tooltipUIML.getLength())
+    if (!tooltipUIML)
     {
         tooltipUIML
-            = Framework::Text("<tip><text width=\"auto\" height=\"auto\">")
-            + name + "</text></tip>";
+            = UIMLBuilder::createTooltip()
+                  ->addElement(UIMLBuilder::createTextAuto(name)->build())
+                  ->build();
     }
 }
 
@@ -182,12 +185,16 @@ const Framework::Text& ItemType::getName() const
 
 void ItemType::setTooltipUIML(Framework::Text tooltipUIML)
 {
-    this->tooltipUIML = tooltipUIML;
+    if (this->tooltipUIML)
+    {
+        this->tooltipUIML->release();
+    }
+    this->tooltipUIML = new Framework::XML::Element(tooltipUIML);
 }
 
-const Framework::Text& ItemType::getTooltipUIML() const
+Framework::XML::Element* ItemType::getTooltipUIML() const
 {
-    return tooltipUIML;
+    return dynamic_cast<Framework::XML::Element*>(tooltipUIML->getThis());
 }
 
 void ItemType::setModel(ModelInfo* model)

+ 5 - 3
FactoryCraft/ItemType.h

@@ -24,7 +24,7 @@ class ItemType : public virtual Framework::ReferenceCounter
 protected:
     int id;
     Framework::Text name;
-    Framework::Text tooltipUIML;
+    Framework::XML::Element* tooltipUIML;
     ModelInfo* model;
     int maxStackSize;
     Framework::RCArray<Framework::Text> groups;
@@ -66,7 +66,7 @@ public:
     void setName(Framework::Text name);
     const Framework::Text& getName() const;
     void setTooltipUIML(Framework::Text tooltipUIML);
-    const Framework::Text& getTooltipUIML() const;
+    Framework::XML::Element* getTooltipUIML() const;
     void setModel(ModelInfo* model);
     ModelInfo* zModel() const;
     void setMaxStackSize(int maxStackSize);
@@ -129,8 +129,10 @@ public:
                 zType->zModel()));
         zResult->addValue(
             "name", new Framework::JSON::JSONString(zType->getName()));
+        Framework::XML::Element* tooltipUIML = zType->getTooltipUIML();
         zResult->addValue("tooltipUIML",
-            new Framework::JSON::JSONString(zType->getTooltipUIML()));
+            new Framework::JSON::JSONString(tooltipUIML->toString()));
+        tooltipUIML->release();
         zResult->addValue("maxStack",
             new Framework::JSON::JSONNumber(zType->getMaxStackSize()));
         Framework::JSON::JSONArray* groupNames

+ 94 - 39
FactoryCraft/Player.cpp

@@ -1,6 +1,7 @@
 #include "Player.h"
 
 #include "ArrayUtils.h"
+#include "BasicBlocks.h"
 #include "Block.h"
 #include "Chat.h"
 #include "Game.h"
@@ -9,6 +10,7 @@
 #include "ItemType.h"
 #include "QuestDialog.h"
 #include "UIController.h"
+#include "UIMLBuilder.h"
 
 Player::Player(Framework::Vec3<float> location, int dimensionId, int entityId)
     : Entity(EntityTypeEnum::PLAYER, location, dimensionId, entityId),
@@ -51,44 +53,77 @@ void Player::onTargetChange()
     Game::INSTANCE->sendMessage(msg, this);
 }
 
-Framework::Text Player::getInventoryUIML()
+Framework::XML::Element* Player::getInventoryUIML() const
 {
-    Framework::Text result
-        = "<dialog id=\"player_inventory\" title=\"Inventory\" width=\"610\" "
-          "height=\"450\">";
-    result.append()
-        << "<craftingGrid id=\"crafting\" margin-top=\"9\" "
-           "align-top=\"start\" align-left=\"start\" margin-left=\"9\" "
-           "width=\"282\" height=\"172\" rowSize=\"3\" colSize=\"3\" "
-           "numOutputSlots=\"1\" target=\""
-        << getId() << "\"/>"
-        << "<inventory id=\"inventory\" margin-bottom=\"18\" "
-           "align-bottom=\"item_bar\" align-left=\"start\" "
-           "margin-left=\"9\" width=\"592\" height=\"172\" rowSize=\"10\" "
-           "numSlots=\"30\" slotNameFilter=\"Inventory\" target=\""
-        << getId() << "\"/>"
-        << "<inventory id=\"item_bar\" margin-bottom=\"9\" "
-           "align-bottom=\"end\" align-left=\"start\" margin-left=\"9\" "
-           "width=\"592\" height=\"52\" rowSize=\"10\" numSlots=\"10\" "
-           "slotNameFilter=\"ItemBar\" target=\""
-        << getId() << "\"/>"
-        << "</dialog>";
-    return result;
+    return UIMLBuilder::createDialog("player_inventory")
+        ->setTitle("Inventory")
+        ->setWidth(610)
+        ->setHeight(450)
+        ->addElement(UIMLBuilder::createCraftingGrid()
+                ->setID("crafting")
+                ->setMarginTop(9)
+                ->setAlignTopStart()
+                ->setAlignLeftStart()
+                ->setMarginLeft(9)
+                ->setWidth(282)
+                ->setHeight(172)
+                ->setRows(3)
+                ->setColumns(3)
+                ->setOutputSize(1)
+                ->setEntitySource(getId())
+                ->build())
+        ->addElement(UIMLBuilder::createInventory()
+                ->setID("inventory")
+                ->setMarginBottom(18)
+                ->setAlignBottomToElement("item_bar")
+                ->setAlignLeftStart()
+                ->setMarginLeft(9)
+                ->setWidth(592)
+                ->setHeight(172)
+                ->setRowSize(10)
+                ->setSlotCount(30)
+                ->setSlotNameFilter("Inventory")
+                ->setEntitySource(getId())
+                ->build())
+        ->addElement(UIMLBuilder::createInventory()
+                ->setID("item_bar")
+                ->setMarginBottom(9)
+                ->setAlignBottomEnd()
+                ->setAlignLeftStart()
+                ->setMarginLeft(9)
+                ->setWidth(592)
+                ->setHeight(52)
+                ->setRowSize(10)
+                ->setSlotCount(10)
+                ->setSlotNameFilter("ItemBar")
+                ->setEntitySource(getId())
+                ->build())
+        ->build();
 }
 
-Framework::Text Player::getPlayerGUI()
+Framework::XML::Element* Player::getPlayerGUI() const
 {
-    Framework::Text result = "<gui id=\"player_gui\">";
-    result.append()
-        << "<itemBar id=\"gui_item_bar\" margin-bottom=\"9\" "
-           "align-bottom=\"end\" align-left=\"center\" width=\"592\" "
-           "height=\"52\" rowSize=\"10\" slotNameFilter=\"ItemBar\" target=\""
-        << getId() << "\"/>"
-        << "<statusBars id=\"gui_status_bars\" margin-bottom=\"9\" "
-           "align-bottom=\"gui_item_bar\" align-left=\"center\" target=\""
-        << getId() << "\"/>"
-        << "</gui>";
-    return result;
+    return UIMLBuilder::createContainer()
+        ->setID("player_gui")
+        ->addChild(UIMLBuilder::createItemBar()
+                ->setID("gui_item_bar")
+                ->setMarginBottom(9)
+                ->setAlignBottomEnd()
+                ->setAlignLeftCenter()
+                ->setWidth(592)
+                ->setHeight(52)
+                ->setRowSize(10)
+                ->setSlotNameFilter("ItemBar")
+                ->setEntitySource(getId())
+                ->build())
+        ->addChild(UIMLBuilder::createStatusBars()
+                ->setID("gui_status_bars")
+                ->setMarginBottom(9)
+                ->setAlignBottomToElement("gui_item_bar")
+                ->setAlignLeftCenter()
+                ->setEntitySource(getId())
+                ->build())
+        ->build();
 }
 
 void Player::useItemSlot(ItemSlot* zSlot, bool left)
@@ -232,15 +267,15 @@ void Player::playerApi(
     case 4:
         {
             Game::INSTANCE->zUIController()->addDialog(
-                new UIDialog("player_inventory",
-                    getId(),
-                    new Framework::XML::Element(getInventoryUIML())));
+                new UIDialog("player_inventory", getId(), getInventoryUIML()));
             break;
         }
     case 5:
         {
             // request gui
-            Framework::Text uiml = getPlayerGUI();
+            Framework::XML::Element* element = getPlayerGUI();
+            Framework::Text uiml = element->toString();
+            element->release();
             int msgSize = 6 + uiml.getLength();
             char* msg = new char[msgSize];
             msg[0] = 2; // gui message
@@ -313,6 +348,7 @@ void Player::playerApi(
                 zRequest->lese((char*)&id, 4);
                 target = dynamic_cast<BasicShapedCrafter*>(
                     Game::INSTANCE->zEntity(id, dimensionId));
+                if (target) target->applyCurrentRecipie();
             }
             else
             {
@@ -324,8 +360,27 @@ void Player::playerApi(
                 zRequest->lese((char*)&pos.z, 4);
                 target = dynamic_cast<BasicShapedCrafter*>(
                     Game::INSTANCE->zRealBlockInstance(pos, dim));
+                if (target)
+                {
+                    target->applyCurrentRecipie();
+                }
+                else
+                {
+                    BasicBlock* block = dynamic_cast<BasicBlock*>(
+                        Game::INSTANCE->zRealBlockInstance(pos, dim));
+                    if (block)
+                    {
+                        int index;
+                        zRequest->lese((char*)&index, 4);
+                        block->zComponent(index);
+                        target = dynamic_cast<BasicShapedCrafter*>(block);
+                        if (target)
+                        {
+                            target->applyCurrentRecipie();
+                        }
+                    }
+                }
             }
-            if (target) target->applyCurrentRecipie();
             break;
         }
     case 8: // request left hand position

+ 2 - 2
FactoryCraft/Player.h

@@ -30,8 +30,8 @@ private:
     void useItemSlot(ItemSlot* zSlot, bool left);
     Player(Framework::Vec3<float> location, int dimensionId, int entityId);
 
-    Framework::Text getInventoryUIML();
-    Framework::Text getPlayerGUI();
+    Framework::XML::Element* getInventoryUIML() const;
+    Framework::XML::Element* getPlayerGUI() const;
 
 public:
     virtual void onTargetChange() override;

+ 2 - 9
FactoryCraft/Quest.cpp

@@ -702,16 +702,9 @@ QuestParty* QuestManager::zParty(int entityId)
     return result;
 }
 
-QuestCollection* QuestManager::zCollection(Framework::Text collectionName)
+QuestCollection* QuestManager::zCollection(int index)
 {
-    for (QuestCollection* collection : questCollections)
-    {
-        if (collection->getName().istGleich(collectionName))
-        {
-            return collection;
-        }
-    }
-    return 0;
+    return questCollections.z(index);
 }
 
 void QuestManager::loadQuests()

+ 1 - 1
FactoryCraft/Quest.h

@@ -201,7 +201,7 @@ private:
     Framework::RCArray<QuestParty> parties;
 
     QuestParty* zParty(int entityId);
-    QuestCollection* zCollection(Framework::Text collectionName);
+    QuestCollection* zCollection(int index);
 
 public:
     QuestManager();

+ 179 - 140
FactoryCraft/QuestDialog.cpp

@@ -5,39 +5,55 @@
 
 #include "Game.h"
 #include "Quest.h"
+#include "UIMLBuilder.h"
 
 QuestDialog::QuestDialog(int playerId)
     : UIDialog("quests", playerId, 0)
 {
     QuestManager* zManager = Game::INSTANCE->zQuestManager();
-    Framework::Text uiml = "<dialog id=\"quests\" title=\"Quests\" "
-                           "width=\"1200\" height=\"800\">";
-    uiml.append()
-        << "<listView id=\"collectionList\" width=\"200\" height=\"100%\" "
-           "member-height=\"40\" align-top=\"start\" "
-           "align-left=\"start\" onSelectMessage=\"quests;0\">";
+    UIMLListSelectionBuilder* listBuilder
+        = UIMLBuilder::createListSelection()
+              ->setID("collectionList")
+              ->setWidth(200)
+              ->setHeightPercentage(100)
+              ->setItemHeight(40)
+              ->setAlignTopStart()
+              ->setAlignLeftStart()
+              ->setOnSelectNotification("quests", 0);
     QuestParty* party = zManager->zParty(playerId);
     int index = 0;
     for (QuestCollection* questCollection : zManager->questCollections)
     {
         if (questCollection->isVisible(party, zManager))
         {
-            uiml.append() << "<listItem id=\"quest_collection_" << index++
-                          << "\" collectionName=\""
-                          << questCollection->getName() << "\">"
-                          << questCollection->getName() << "</listItem>";
+            listBuilder->addItem(
+                Framework::Text("quest_collection_") += index++,
+                questCollection->getName(),
+                false);
         }
     }
-    uiml.append()
-        << "</listView><questGraph id=\"visible_quest_graph\" width=\"1000\" "
-           "align-left=\"collectionList\" "
-           "height=\"100%\"/><frame id=\"questDetailView\" width=\"100%\" "
-           "height=\"0%\" style=\""
-        << (Framework::Fenster::Style::Titel
-               | Framework::Fenster::Style::Erlaubt
-               | Framework::Fenster::Style::Sichtbar)
-        << "\" title-height=\"30\" title-font-size=\"20\"/></dialog>";
-    this->uiml = new Framework::XML::Element(uiml);
+    this->uiml = UIMLBuilder::createDialog("quests")
+                     ->setTitle("Quests")
+                     ->setWidth(1200)
+                     ->setHeight(800)
+                     ->addElement(listBuilder->build())
+                     ->addElement(UIMLBuilder::createQuestGraph()
+                             ->setID("visible_quest_graph")
+                             ->setWidth(1000)
+                             ->setHeightPercentage(100)
+                             ->setAlignLeftToElement("collectionList")
+                             ->build())
+                     ->addElement(UIMLBuilder::createContainer()
+                             ->setID("questDetailView")
+                             ->setWidthPercentage(100)
+                             ->setHeightPercentage(0)
+                             ->setStyle(Framework::Fenster::Style::Titel
+                                        | Framework::Fenster::Style::Erlaubt
+                                        | Framework::Fenster::Style::Sichtbar)
+                             ->setTitleHeight(30)
+                             ->setTitleFontSize(20)
+                             ->build())
+                     ->build();
 }
 
 void QuestDialog::api(
@@ -56,27 +72,23 @@ void QuestDialog::api(
             auto listItems
                 = uiml->selectChildsByName("listView").selectChildren();
             listItems.removeAttribute("selected");
+            QuestManager* zManager = Game::INSTANCE->zQuestManager();
+            auto questCollection = zManager->zCollection(selection);
+            QuestParty* zParty = zManager->zParty(getPlayerId());
+            for (Quest* quest : questCollection->quests)
+            {
+                if (quest->isVisible(zParty, zManager))
+                {
+                    questGraph.addChild(getQuestGraphItem(quest, zParty));
+                }
+            }
             listItems
                 .whereAttributeEquals(
                     "id", Framework::Text("quest_collection_") + selection)
-                .forEach([this, &questGraph](
-                             Framework::XML::Element* zElement) {
-                    zElement->setAttribute("selected", "");
-                    auto collectionName
-                        = zElement->getAttributeValue("collectionName");
-                    QuestManager* zManager = Game::INSTANCE->zQuestManager();
-                    auto questCollection
-                        = zManager->zCollection(collectionName);
-                    QuestParty* zParty = zManager->zParty(getPlayerId());
-                    for (Quest* quest : questCollection->quests)
-                    {
-                        if (quest->isVisible(zParty, zManager))
-                        {
-                            questGraph.addChild(
-                                getQuestGraphItem(quest, zParty));
-                        }
-                    }
-                });
+                .forEach(
+                    [this, &questGraph](Framework::XML::Element* zElement) {
+                        zElement->setAttribute("selected", "");
+                    });
             update();
             break;
         }
@@ -87,18 +99,20 @@ void QuestDialog::api(
             char* id = new char[len + 1];
             zRequest->lese(id, len);
             id[len] = 0;
-            Framework::Text collectionName
+            Framework::Text selectedId
                 = uiml->selectChildsByName("listView")
                       .selectChildren()
                       .whereAttributeExists("selected")
                       .getFirstElement()
-                      .map<Framework::Text>([](auto element) {
-                          return element->getAttributeValue("collectionName");
-                      })
+                      .map<Framework::Text>(
+                          [](Framework::XML::Element* element) {
+                              return element->getAttributeValue("id");
+                          })
                       .orElse("");
             QuestManager* zManager = Game::INSTANCE->zQuestManager();
             QuestCollection* questCollection
-                = zManager->zCollection(collectionName);
+                = zManager->zCollection(Framework::TextZuInt(
+                    selectedId.getText() + strlen("quest_collection_"), 10));
             QuestParty* zParty = zManager->zParty(getPlayerId());
             for (Quest* quest : questCollection->quests)
             {
@@ -142,18 +156,19 @@ void QuestDialog::api(
         }
     case 3: // onClick Message of give_rewards
         {
-            Framework::Text collectionName
+            Framework::Text selectedId
                 = uiml->selectChildsByName("listView")
                       .selectChildren()
                       .whereAttributeExists("selected")
                       .getFirstElement()
                       .map<Framework::Text>([](auto element) {
-                          return element->getAttributeValue("collectionName");
+                          return element->getAttributeValue("id");
                       })
                       .orElse("");
             QuestManager* zManager = Game::INSTANCE->zQuestManager();
             QuestCollection* questCollection
-                = zManager->zCollection(collectionName);
+                = zManager->zCollection(Framework::TextZuInt(
+                    selectedId.getText() + strlen("quest_collection_"), 10));
             QuestParty* zParty = zManager->zParty(getPlayerId());
             Framework::Text questId
                 = uiml->selectChildsByAttribute("id", "questDetailView")
@@ -208,18 +223,19 @@ void QuestDialog::api(
         }
     case 4: // requirement message
         {
-            Framework::Text collectionName
+            Framework::Text selectedId
                 = uiml->selectChildsByName("listView")
                       .selectChildren()
                       .whereAttributeExists("selected")
                       .getFirstElement()
                       .map<Framework::Text>([](auto element) {
-                          return element->getAttributeValue("collectionName");
+                          return element->getAttributeValue("id");
                       })
                       .orElse("");
             QuestManager* zManager = Game::INSTANCE->zQuestManager();
             QuestCollection* questCollection
-                = zManager->zCollection(collectionName);
+                = zManager->zCollection(Framework::TextZuInt(
+                    selectedId.getText() + strlen("quest_collection_"), 10));
             QuestParty* zParty = zManager->zParty(getPlayerId());
             Framework::Text questId
                 = uiml->selectChildsByAttribute("id", "questDetailView")
@@ -258,18 +274,19 @@ void QuestDialog::api(
         }
     case 5: // reward message
         {
-            Framework::Text collectionName
+            Framework::Text selectedId
                 = uiml->selectChildsByName("listView")
                       .selectChildren()
                       .whereAttributeExists("selected")
                       .getFirstElement()
                       .map<Framework::Text>([](auto element) {
-                          return element->getAttributeValue("collectionName");
+                          return element->getAttributeValue("id");
                       })
                       .orElse("");
             QuestManager* zManager = Game::INSTANCE->zQuestManager();
             QuestCollection* questCollection
-                = zManager->zCollection(collectionName);
+                = zManager->zCollection(Framework::TextZuInt(
+                    selectedId.getText() + strlen("quest_collection_"), 10));
             QuestParty* zParty = zManager->zParty(getPlayerId());
             Framework::Text questId
                 = uiml->selectChildsByAttribute("id", "questDetailView")
@@ -337,35 +354,36 @@ Framework::XML::Element* QuestDialog::getQuestGraphItem(
     }
     if (!zQuest->isActive(zParty))
     {
-        Framework::Text result = "<questGraphItem id=\"quest_";
-        result.append()
-            << zQuest->questId << "\" name=\"Unknown Quest\" image=\""
-            << zQuest->imagePath
-            << "\" description=\"You have to finish other quests befor this "
-               "quest will be available.\" finished=\"false\" "
-               "rewarded=\"false\" mainQuest=\""
-            << zQuest->mainQuest << "\" requirements=\"" << requirements
-            << "\" width=\"" << (zQuest->mainQuest ? "50" : "30")
-            << "\" height=\"" << (zQuest->mainQuest ? "50" : "30") << "\"/>";
-        return new Framework::XML::Element(result);
+        return UIMLBuilder::createQuestNode()
+            ->setID(Framework::Text("quest_") += zQuest->questId)
+            ->setQuestName("Unknown Quest")
+            ->setImagePath(zQuest->imagePath)
+            ->setDescription("You have to finish other quests befor this "
+                             "quest will be available.")
+            ->setFinished(0)
+            ->setRewarded(0)
+            ->setMainQuest(zQuest->mainQuest)
+            ->setRequirements(requirements)
+            ->setWidth(zQuest->mainQuest ? 50 : 30)
+            ->setHeight(zQuest->mainQuest ? 50 : 30)
+            ->build();
     }
     else
     {
         QuestStorage* zStorage = zParty->zQuestStorage(zQuest->questId);
-        Framework::Text result = "<questGraphItem id=\"quest_";
-        result.append() << zQuest->questId << "\" name=\""
-                        << zQuest->questName + "\" image=\""
-                        << zQuest->imagePath << "\" description=\""
-                        << zQuest->description << "\" finished=\""
-                        << zStorage->isQuestFinished() << "\" rewarded=\""
-                        << zStorage->isQuestRewarded() << "\" mainQuest=\""
-                        << zQuest->mainQuest << "\" requirements=\""
-                        << requirements << "\" width=\""
-                        << (zQuest->mainQuest ? "50" : "30") << "\" height=\""
-                        << (zQuest->mainQuest ? "50" : "30")
-                        << "\" onClick=\"quests;(char)1;" << zQuest->questId
-                        << "\"/>";
-        return new Framework::XML::Element(result);
+        return UIMLBuilder::createQuestNode()
+            ->setID(Framework::Text("quest_") += zQuest->questId)
+            ->setQuestName(zQuest->questName)
+            ->setImagePath(zQuest->imagePath)
+            ->setDescription(zQuest->description)
+            ->setFinished(zStorage->isQuestFinished())
+            ->setRewarded(zStorage->isQuestRewarded())
+            ->setMainQuest(zQuest->mainQuest)
+            ->setRequirements(requirements)
+            ->setWidth(zQuest->mainQuest ? 50 : 30)
+            ->setHeight(zQuest->mainQuest ? 50 : 30)
+            ->setOnClickMessage("quests", {1})
+            ->build();
     }
 }
 
@@ -373,77 +391,98 @@ void QuestDialog::showQuestDetails(
     Quest* zQuest, QuestStorage* zStorage, Framework::XML::Element* zParent)
 {
     zParent->setAttribute("title", zQuest->questName);
-    zParent->addChild(new Framework::XML::Element(
-        (((Framework::Text("<text id=\"quest_description\" width=\"50% - 15\" "
-                           "height=\"50% - 10\" "
-                           "align-left=\"start\" margin-left=\"10\" "
-                           "align-top=\"start\" margin-top=\"10\" border=\"1\" "
-                           "border-color=\"0xFF52525E\" vScroll=\"auto\" "
-                           "style=\"")
-              += Framework::TextFeld::Style::Text
-               | Framework::TextFeld::Style::Mehrzeilig
-               | Framework::TextFeld::Style::AutoLineBreak)
-             += "\">")
-            += zQuest->description)
-        += "</text>"));
-    Framework::XML::Element* requirementsContainer
-        = new Framework::XML::Element(
-            "<frame id=\"quest_requirements\" align-left=\"quest_description\" "
-            "margin-left=\"10\" "
-            "align-top=\"start\" margin-top=\"10\" width=\"50% - 15\" "
-            "height=\"100% - "
-            "50\" vScroll=\"auto\" display=\"column\" gap=\"10\" border=\"1\" "
-            "border-color=\"0xFF52525E\"/>");
-    requirementsContainer->addChild(new Framework::XML::Element(
-        "<text id=\"quest_requirements_title\" width=\"100%\" "
-        "height=\"30\" text-align-horizontal=\"center\"  "
-        "text-align-vertical=\"center\" "
-        "font-size=\"20\">Requirements</text>"));
-    requirementsContainer->setAttribute("style",
-        Framework::Text() += (Framework::Fenster::Style::Sichtbar
-                              | Framework::Fenster::Style::Erlaubt
-                              | Framework::Fenster::Style::Rahmen));
+    zParent->addChild(UIMLBuilder::createText(zQuest->description)
+            ->setID("quest_description")
+            ->setWidth(50, -15)
+            ->setHeight(50, -10)
+            ->setAlignLeftStart()
+            ->setMarginLeft(10)
+            ->setAlignTopStart()
+            ->setMarginTop(10)
+            ->setBorder(1, 0xFF52525E)
+            ->enableVerticalScrollbar()
+            ->setStyle(Framework::TextFeld::Style::Text
+                       | Framework::TextFeld::Style::Mehrzeilig
+                       | Framework::TextFeld::Style::AutoLineBreak)
+            ->build());
+    UIMLContainerBuilder* requirementsContainerBuilder
+        = UIMLBuilder::createContainer()
+              ->setID("quest_requirements")
+              ->setAlignLeftToElement("quest_description")
+              ->setMarginLeft(10)
+              ->setAlignTopStart()
+              ->setMarginTop(10)
+              ->setWidth(50, -15)
+              ->setHeight(100, -50)
+              ->setDisplayAsColumn(0, 10)
+              ->setBorder(1, 0xFF52525E)
+              ->setStyle(Framework::Fenster::Style::Sichtbar
+                         | Framework::Fenster::Style::Erlaubt
+                         | Framework::Fenster::Style::Rahmen)
+              ->enableVerticalScrollbar()
+              ->addChild(UIMLBuilder::createText("Requirements")
+                      ->setID("quest_requirements_title")
+                      ->setWidthPercentage(100)
+                      ->setHeight(30)
+                      ->setStyle(Framework::TextFeld::Style::Text
+                                 | Framework::TextFeld::Style::Center)
+                      ->setFontSize(20)
+                      ->build());
     for (QuestRequirement* requirement : zQuest->requirements)
     {
-        requirement->addRequirementUIML(zStorage,
-            requirementsContainer,
-            Framework::Text("quests;(char)4;")
-            += requirement->getRequirementId());
+        requirement->addRequirementUIML(zStorage, requirementsContainerBuilder);
     }
-    zParent->addChild(requirementsContainer);
-    Framework::XML::Element* rewardsContainer = new Framework::XML::Element(
-        "<frame id=\"quest_rewards\" align-left=\"start\" margin-left=\"10\" "
-        "margin-top=\"10\" "
-        "align-top=\"quest_description\" width=\"50% - 15\" height=\"50% - "
-        "20\" vScroll=\"auto\" display=\"column\" gap=\"10\" border=\"1\" "
-        "border-color=\"0xFF52525E\"/>");
-    rewardsContainer->addChild(new Framework::XML::Element(
-        "<text id=\"quest_rewards_title\" width=\"100%\" height=\"30\" "
-        "text-align-horizontal=\"center\"  text-align-vertical=\"center\" "
-        "font-size=\"20\">Rewards</text>"));
-    rewardsContainer->setAttribute("style",
-        Framework::Text() += (Framework::Fenster::Style::Sichtbar
-                              | Framework::Fenster::Style::Erlaubt
-                              | Framework::Fenster::Style::Rahmen));
+    zParent->addChild(requirementsContainerBuilder->build());
+    UIMLContainerBuilder* rewardsContainerBuilder
+        = UIMLBuilder::createContainer()
+              ->setID("quest_rewards")
+              ->setAlignLeftStart()
+              ->setMarginLeft(10)
+              ->setAlignTopToElement("quest_description")
+              ->setMarginTop(10)
+              ->setWidth(50, -15)
+              ->setHeight(50, -20)
+              ->setDisplayAsColumn(0, 10)
+              ->setBorder(1, 0xFF52525E)
+              ->setStyle(Framework::Fenster::Style::Sichtbar
+                         | Framework::Fenster::Style::Erlaubt
+                         | Framework::Fenster::Style::Rahmen)
+              ->enableVerticalScrollbar()
+              ->addChild(UIMLBuilder::createText("Rewards")
+                      ->setID("quest_rewards_title")
+                      ->setWidthPercentage(100)
+                      ->setHeight(30)
+                      ->setStyle(Framework::TextFeld::Style::Text
+                                 | Framework::TextFeld::Style::Center)
+                      ->setFontSize(20)
+                      ->build());
     for (QuestReward* reward : zQuest->rewards)
     {
-        reward->addRewardUIML(rewardsContainer,
-            zStorage,
-            Framework::Text("quests;(char)5;") += reward->getRewardId());
+        reward->addRewardUIML(rewardsContainerBuilder, zStorage);
     }
-    zParent->addChild(rewardsContainer);
-    zParent->addChild(new Framework::XML::Element(
-        "<button id=\"back_to_graph\" width=\"100\" height=\"20\" "
-        "align-right=\"end\" align-top=\"quest_requirements\" "
-        "margin-right=\"10\" margin-top=\"10\" "
-        "onClick=\"quests;(char)2\">Back</button>"));
+    zParent->addChild(rewardsContainerBuilder->build());
+    zParent->addChild(UIMLBuilder::createButton("Back")
+            ->setID("back_to_graph")
+            ->setWidth(100)
+            ->setHeight(20)
+            ->setAlignRightEnd()
+            ->setMarginRight(10)
+            ->setAlignTopToElement("quest_requirements")
+            ->setMarginTop(10)
+            ->setOnClickMessage("quests", {2})
+            ->build());
     if (zStorage->isQuestFinished() && !zStorage->isQuestRewarded())
     {
-        zParent->addChild(new Framework::XML::Element(
-            "<button id=\"give_rewards\" width=\"100\" height=\"20\" "
-            "align-left=\"quest_rewards\" align-top=\"quest_requirements\" "
-            "margin-left=\"10\" margin-top=\"10\" "
-            "onClick=\"quests;(char)3\">Give rewards</button>"));
+        zParent->addChild(UIMLBuilder::createButton("Give rewards")
+                ->setID("give_rewards")
+                ->setWidth(100)
+                ->setHeight(20)
+                ->setAlignLeftToElement("quest_rewards")
+                ->setMarginLeft(10)
+                ->setAlignTopToElement("quest_requirements")
+                ->setMarginTop(10)
+                ->setOnClickMessage("quests", {3})
+                ->build());
     }
     update();
 }

+ 174 - 146
FactoryCraft/QuestRequirement.cpp

@@ -7,6 +7,7 @@
 #include "ItemFilter.h"
 #include "ItemType.h"
 #include "Quest.h"
+#include "UIMLBuilder.h"
 
 QuestRequirement::QuestRequirement()
     : ReferenceCounter()
@@ -56,40 +57,46 @@ void QuestRequirementOpenDialog::processEvent(
     }
 }
 
-void QuestRequirementOpenDialog::addRequirementUIML(QuestStorage* zStorage,
-    Framework::XML::Element* zParent,
-    Framework::Text onClickPrefix)
-{
-    Framework::XML::Element* container = new Framework::XML::Element(
-        "<frame width=\"100%\" height=\"50\" display=\"row\" gap=\"10\"/>");
-    container->setAttribute("style",
-        Framework::Text() += (Framework::Fenster::Style::Sichtbar
-                              | Framework::Fenster::Style::Erlaubt));
-    container->setAttribute(
-        "id", Framework::Text("requirement_") += getRequirementId());
+void QuestRequirementOpenDialog::addRequirementUIML(
+    QuestStorage* zStorage, UIMLContainerBuilder* zParent)
+{
+    UIMLContainerBuilder* builder
+        = UIMLBuilder::createContainer()
+              ->setWidthPercentage(100)
+              ->setHeight(50)
+              ->setDisplayAsRow(0, 10)
+              ->setStyle(Framework::Fenster::Style::Sichtbar
+                         | Framework::Fenster::Style::Erlaubt)
+              ->setID(Framework::Text("requirement_") += getRequirementId());
     // TODO: add icon of dialog
-    auto text
-        = new Framework::XML::Element("<text width=\"auto\" height=\"auto\"/>");
-    text->setAttribute("id",
-        Framework::Text("requirement_description_") += getRequirementId());
-    text->setText(description);
-    container->addChild(text);
-    auto status = new Framework::XML::Element(
-        "<text margin-top=\"10\" width=\"auto\" height=\"auto\"/>");
-    status->setAttribute("align-top", text->getAttributeValue("id"));
-    status->setAttribute("align-x", text->getAttributeValue("id"));
+    Framework::Text status;
+    int color;
     if (zStorage->zStorage(getRequirementId())->isFullfilled())
     {
-        status->setText("Completed");
-        status->setAttribute("text-color", "0xFF00FF00");
+        status = "Completed";
+        color = 0xFF00FF00;
     }
     else
     {
-        status->setText("Not completed");
-        status->setAttribute("text-color", "0xFFFF0000");
+        status = "Not completed";
+        color = 0xFFFF0000;
     }
-    container->addChild(status);
-    zParent->addChild(container);
+    zParent->addChild(builder
+            ->addChild(UIMLBuilder::createTextAuto(description)
+                    ->setID(Framework::Text("requirement_description_")
+                            += getRequirementId())
+                    ->build())
+            ->addChild(UIMLBuilder::createTextAuto(status)
+                    ->setAlignXToElement(
+                        Framework::Text("requirement_description_")
+                        += getRequirementId())
+                    ->setAlignTopToElement(
+                        Framework::Text("requirement_description_")
+                        += getRequirementId())
+                    ->setMarginTop(10)
+                    ->setTextColor(color)
+                    ->build())
+            ->build());
 }
 
 void QuestRequirementOpenDialog::setDialogId(Framework::Text dialogId)
@@ -179,34 +186,25 @@ void QuestRequirementBlockBreak::processEvent(
     }
 }
 
-void QuestRequirementBlockBreak::addRequirementUIML(QuestStorage* zStorage,
-    Framework::XML::Element* zParent,
-    Framework::Text onClickPrefix)
-{
-    Framework::XML::Element* container = new Framework::XML::Element(
-        "<frame width=\"100%\" height=\"50\" display=\"row\" gap=\"10\"/>");
-    container->setAttribute("style",
-        Framework::Text() += (Framework::Fenster::Style::Sichtbar
-                              | Framework::Fenster::Style::Erlaubt));
-    container->setAttribute(
-        "id", Framework::Text("requirement_") += getRequirementId());
+void QuestRequirementBlockBreak::addRequirementUIML(
+    QuestStorage* zStorage, UIMLContainerBuilder* zParent)
+{
+    UIMLContainerBuilder* builder
+        = UIMLBuilder::createContainer()
+              ->setWidthPercentage(100)
+              ->setHeight(50)
+              ->setDisplayAsRow(0, 10)
+              ->setStyle(Framework::Fenster::Style::Sichtbar
+                         | Framework::Fenster::Style::Erlaubt)
+              ->setID(Framework::Text("requirement_") += getRequirementId());
     // TODO: add icon of block
-    auto text
-        = new Framework::XML::Element("<text width=\"auto\" height=\"auto\"/>");
-    text->setAttribute("id",
-        Framework::Text("requirement_description_") += getRequirementId());
-    text->setText(description);
-    container->addChild(text);
-    auto status = new Framework::XML::Element(
-        "<text margin-top=\"10\" width=\"auto\" height=\"auto\"/>");
-    status->setAttribute("align-top", text->getAttributeValue("id"));
-    status->setAttribute("align-x", text->getAttributeValue("id"));
+    Framework::Text status;
+    int color;
     if (zStorage->zStorage(getRequirementId())->isFullfilled())
     {
-        Framework::Text completedText = "Completed (";
-        completedText.append() << amount << "/" << amount << ")";
-        status->setText(completedText.getText());
-        status->setAttribute("text-color", "0xFF00FF00");
+        status = "Completed (";
+        status.append() << amount << "/" << amount << ")";
+        color = 0xFF00FF00;
     }
     else
     {
@@ -215,12 +213,26 @@ void QuestRequirementBlockBreak::addRequirementUIML(QuestStorage* zStorage,
                                     ->asNumber()
                                     ->getNumber()
                               : 0;
-        Framework::Text completedText = "Not completed (";
-        completedText.append() << currentAmount << "/" << amount << ")";
-        status->setAttribute("text-color", "0xFFFF0000");
+        status = "Not completed (";
+        status.append() << currentAmount << "/" << amount << ")";
+        color = 0xFFFF0000;
     }
-    container->addChild(status);
-    zParent->addChild(container);
+    zParent->addChild(builder
+            ->addChild(UIMLBuilder::createTextAuto(description)
+                    ->setID(Framework::Text("requirement_description_")
+                            += getRequirementId())
+                    ->build())
+            ->addChild(UIMLBuilder::createTextAuto(status)
+                    ->setAlignXToElement(
+                        Framework::Text("requirement_description_")
+                        += getRequirementId())
+                    ->setAlignTopToElement(
+                        Framework::Text("requirement_description_")
+                        += getRequirementId())
+                    ->setMarginTop(10)
+                    ->setTextColor(color)
+                    ->build())
+            ->build());
 }
 
 void QuestRequirementBlockBreak::setBlockTypeId(int blockTypeId)
@@ -354,34 +366,25 @@ void QuestRequirementBlockPlace::processEvent(
     }
 }
 
-void QuestRequirementBlockPlace::addRequirementUIML(QuestStorage* zStorage,
-    Framework::XML::Element* zParent,
-    Framework::Text onClickPrefix)
-{
-    Framework::XML::Element* container = new Framework::XML::Element(
-        "<frame width=\"100%\" height=\"50\" display=\"row\" gap=\"10\"/>");
-    container->setAttribute("style",
-        Framework::Text() += (Framework::Fenster::Style::Sichtbar
-                              | Framework::Fenster::Style::Erlaubt));
-    container->setAttribute(
-        "id", Framework::Text("requirement_") += getRequirementId());
+void QuestRequirementBlockPlace::addRequirementUIML(
+    QuestStorage* zStorage, UIMLContainerBuilder* zParent)
+{
+    UIMLContainerBuilder* builder
+        = UIMLBuilder::createContainer()
+              ->setWidthPercentage(100)
+              ->setHeight(50)
+              ->setDisplayAsRow(0, 10)
+              ->setStyle(Framework::Fenster::Style::Sichtbar
+                         | Framework::Fenster::Style::Erlaubt)
+              ->setID(Framework::Text("requirement_") += getRequirementId());
     // TODO: add icon of block
-    auto text
-        = new Framework::XML::Element("<text width=\"auto\" height=\"auto\"/>");
-    text->setAttribute("id",
-        Framework::Text("requirement_description_") += getRequirementId());
-    text->setText(description);
-    container->addChild(text);
-    auto status = new Framework::XML::Element(
-        "<text margin-top=\"10\" width=\"auto\" height=\"auto\"/>");
-    status->setAttribute("align-top", text->getAttributeValue("id"));
-    status->setAttribute("align-x", text->getAttributeValue("id"));
+    Framework::Text status;
+    int color;
     if (zStorage->zStorage(getRequirementId())->isFullfilled())
     {
-        Framework::Text completedText = "Completed (";
-        completedText.append() << amount << "/" << amount << ")";
-        status->setText(completedText.getText());
-        status->setAttribute("text-color", "0xFF00FF00");
+        status = "Completed (";
+        status.append() << amount << "/" << amount << ")";
+        color = 0xFF00FF00;
     }
     else
     {
@@ -390,12 +393,26 @@ void QuestRequirementBlockPlace::addRequirementUIML(QuestStorage* zStorage,
                                     ->asNumber()
                                     ->getNumber()
                               : 0;
-        Framework::Text completedText = "Not completed (";
-        completedText.append() << currentAmount << "/" << amount << ")";
-        status->setAttribute("text-color", "0xFFFF0000");
+        status = "Not completed (";
+        status.append() << currentAmount << "/" << amount << ")";
+        color = 0xFFFF0000;
     }
-    container->addChild(status);
-    zParent->addChild(container);
+    zParent->addChild(builder
+            ->addChild(UIMLBuilder::createTextAuto(description)
+                    ->setID(Framework::Text("requirement_description_")
+                            += getRequirementId())
+                    ->build())
+            ->addChild(UIMLBuilder::createTextAuto(status)
+                    ->setAlignXToElement(
+                        Framework::Text("requirement_description_")
+                        += getRequirementId())
+                    ->setAlignTopToElement(
+                        Framework::Text("requirement_description_")
+                        += getRequirementId())
+                    ->setMarginTop(10)
+                    ->setTextColor(color)
+                    ->build())
+            ->build());
 }
 
 void QuestRequirementBlockPlace::setBlockTypeId(int blockTypeId)
@@ -496,40 +513,46 @@ void QuestRequirementBlockInteract::processEvent(
     }
 }
 
-void QuestRequirementBlockInteract::addRequirementUIML(QuestStorage* zStorage,
-    Framework::XML::Element* zParent,
-    Framework::Text onClickPrefix)
-{
-    Framework::XML::Element* container = new Framework::XML::Element(
-        "<frame width=\"100%\" height=\"50\" display=\"row\" gap=\"10\"/>");
-    container->setAttribute("style",
-        Framework::Text() += (Framework::Fenster::Style::Sichtbar
-                              | Framework::Fenster::Style::Erlaubt));
-    container->setAttribute(
-        "id", Framework::Text("requirement_") += getRequirementId());
-    // TODO: add icon of block
-    auto text
-        = new Framework::XML::Element("<text width=\"auto\" height=\"auto\"/>");
-    text->setAttribute("id",
-        Framework::Text("requirement_description_") += getRequirementId());
-    text->setText(description);
-    container->addChild(text);
-    auto status = new Framework::XML::Element(
-        "<text margin-top=\"10\" width=\"auto\" height=\"auto\"/>");
-    status->setAttribute("align-top", text->getAttributeValue("id"));
-    status->setAttribute("align-x", text->getAttributeValue("id"));
+void QuestRequirementBlockInteract::addRequirementUIML(
+    QuestStorage* zStorage, UIMLContainerBuilder* zParent)
+{
+    UIMLContainerBuilder* builder
+        = UIMLBuilder::createContainer()
+              ->setWidthPercentage(100)
+              ->setHeight(50)
+              ->setDisplayAsRow(0, 10)
+              ->setStyle(Framework::Fenster::Style::Sichtbar
+                         | Framework::Fenster::Style::Erlaubt)
+              ->setID(Framework::Text("requirement_") += getRequirementId());
+    // TODO: add icon of dialog
+    Framework::Text status;
+    int color;
     if (zStorage->zStorage(getRequirementId())->isFullfilled())
     {
-        status->setText("Completed");
-        status->setAttribute("text-color", "0xFF00FF00");
+        status = "Completed";
+        color = 0xFF00FF00;
     }
     else
     {
-        status->setText("Not completed");
-        status->setAttribute("text-color", "0xFFFF0000");
+        status = "Not completed";
+        color = 0xFFFF0000;
     }
-    container->addChild(status);
-    zParent->addChild(container);
+    zParent->addChild(builder
+            ->addChild(UIMLBuilder::createTextAuto(description)
+                    ->setID(Framework::Text("requirement_description_")
+                            += getRequirementId())
+                    ->build())
+            ->addChild(UIMLBuilder::createTextAuto(status)
+                    ->setAlignXToElement(
+                        Framework::Text("requirement_description_")
+                        += getRequirementId())
+                    ->setAlignTopToElement(
+                        Framework::Text("requirement_description_")
+                        += getRequirementId())
+                    ->setMarginTop(10)
+                    ->setTextColor(color)
+                    ->build())
+            ->build());
 }
 
 void QuestRequirementBlockInteract::setBlockTypeId(int blockTypeId)
@@ -653,34 +676,25 @@ void QuestRequirementItemInInventory::processEvent(
     }
 }
 
-void QuestRequirementItemInInventory::addRequirementUIML(QuestStorage* zStorage,
-    Framework::XML::Element* zParent,
-    Framework::Text onClickPrefix)
-{
-    Framework::XML::Element* container = new Framework::XML::Element(
-        "<frame width=\"100%\" height=\"50\" display=\"row\" gap=\"10\"/>");
-    container->setAttribute("style",
-        Framework::Text() += (Framework::Fenster::Style::Sichtbar
-                              | Framework::Fenster::Style::Erlaubt));
-    container->setAttribute(
-        "id", Framework::Text("requirement_") += getRequirementId());
-    // TODO: add icon of item
-    auto text
-        = new Framework::XML::Element("<text width=\"auto\" height=\"auto\"/>");
-    text->setAttribute("id",
-        Framework::Text("requirement_description_") += getRequirementId());
-    text->setText(description);
-    container->addChild(text);
-    auto status = new Framework::XML::Element(
-        "<text margin-top=\"10\" width=\"auto\" height=\"auto\"/>");
-    status->setAttribute("align-top", text->getAttributeValue("id"));
-    status->setAttribute("align-x", text->getAttributeValue("id"));
+void QuestRequirementItemInInventory::addRequirementUIML(
+    QuestStorage* zStorage, UIMLContainerBuilder* zParent)
+{
+    UIMLContainerBuilder* builder
+        = UIMLBuilder::createContainer()
+              ->setWidthPercentage(100)
+              ->setHeight(50)
+              ->setDisplayAsRow(0, 10)
+              ->setStyle(Framework::Fenster::Style::Sichtbar
+                         | Framework::Fenster::Style::Erlaubt)
+              ->setID(Framework::Text("requirement_") += getRequirementId());
+    // TODO: add icon of block
+    Framework::Text status;
+    int color;
     if (zStorage->zStorage(getRequirementId())->isFullfilled())
     {
-        Framework::Text completedText = "Completed (";
-        completedText.append() << amount << "/" << amount << ")";
-        status->setText(completedText.getText());
-        status->setAttribute("text-color", "0xFF00FF00");
+        status = "Completed (";
+        status.append() << amount << "/" << amount << ")";
+        color = 0xFF00FF00;
     }
     else
     {
@@ -689,12 +703,26 @@ void QuestRequirementItemInInventory::addRequirementUIML(QuestStorage* zStorage,
                                     ->asNumber()
                                     ->getNumber()
                               : 0;
-        Framework::Text completedText = "Not completed (";
-        completedText.append() << currentAmount << "/" << amount << ")";
-        status->setAttribute("text-color", "0xFFFF0000");
+        status = "Not completed (";
+        status.append() << currentAmount << "/" << amount << ")";
+        color = 0xFFFF0000;
     }
-    container->addChild(status);
-    zParent->addChild(container);
+    zParent->addChild(builder
+            ->addChild(UIMLBuilder::createTextAuto(description)
+                    ->setID(Framework::Text("requirement_description_")
+                            += getRequirementId())
+                    ->build())
+            ->addChild(UIMLBuilder::createTextAuto(status)
+                    ->setAlignXToElement(
+                        Framework::Text("requirement_description_")
+                        += getRequirementId())
+                    ->setAlignTopToElement(
+                        Framework::Text("requirement_description_")
+                        += getRequirementId())
+                    ->setMarginTop(10)
+                    ->setTextColor(color)
+                    ->build())
+            ->build());
 }
 
 void QuestRequirementItemInInventory::setItemTypeId(int itemTypeId)

+ 13 - 18
FactoryCraft/QuestRequirement.h

@@ -4,6 +4,7 @@
 #include "TypeRegistry.h"
 
 class QuestStorage;
+class UIMLContainerBuilder;
 
 class QuestRequirement : public virtual Framework::ReferenceCounter
 {
@@ -14,9 +15,8 @@ protected:
 public:
     QuestRequirement();
     virtual void processEvent(QuestEvent* zEvent, QuestStorage* zStorage) = 0;
-    virtual void addRequirementUIML(QuestStorage* zStorage,
-        Framework::XML::Element* zParent,
-        Framework::Text onClickPrefix)
+    virtual void addRequirementUIML(
+        QuestStorage* zStorage, UIMLContainerBuilder* zParent)
         = 0;
     virtual void api(Framework::StreamReader* message,
         Framework::XML::Element* zParent,
@@ -82,9 +82,8 @@ private:
 public:
     QuestRequirementOpenDialog();
     void processEvent(QuestEvent* zEvent, QuestStorage* zStorage) override;
-    void addRequirementUIML(QuestStorage* zStorage,
-        Framework::XML::Element* zParent,
-        Framework::Text onClickPrefix) override;
+    void addRequirementUIML(
+        QuestStorage* zStorage, UIMLContainerBuilder* zParent) override;
     void setDialogId(Framework::Text dialogId);
     const Framework::Text& getDialogId() const;
 
@@ -117,9 +116,8 @@ private:
 public:
     QuestRequirementBlockBreak();
     void processEvent(QuestEvent* zEvent, QuestStorage* zStorage) override;
-    void addRequirementUIML(QuestStorage* zStorage,
-        Framework::XML::Element* zParent,
-        Framework::Text onClickPrefix) override;
+    void addRequirementUIML(
+        QuestStorage* zStorage, UIMLContainerBuilder* zParent) override;
     void setBlockTypeId(int blockTypeId);
     int getBlockTypeId() const;
     void setAmount(int amount);
@@ -153,9 +151,8 @@ private:
 public:
     QuestRequirementBlockPlace();
     void processEvent(QuestEvent* zEvent, QuestStorage* zStorage) override;
-    void addRequirementUIML(QuestStorage* zStorage,
-        Framework::XML::Element* zParent,
-        Framework::Text onClickPrefix) override;
+    void addRequirementUIML(
+        QuestStorage* zStorage, UIMLContainerBuilder* zParent) override;
     void setBlockTypeId(int blockTypeId);
     int getBlockTypeId() const;
     void setAmount(int amount);
@@ -186,9 +183,8 @@ class QuestRequirementBlockInteract : public QuestRequirement
 public:
     QuestRequirementBlockInteract();
     void processEvent(QuestEvent* zEvent, QuestStorage* zStorage) override;
-    void addRequirementUIML(QuestStorage* zStorage,
-        Framework::XML::Element* zParent,
-        Framework::Text onClickPrefix) override;
+    void addRequirementUIML(
+        QuestStorage* zStorage, UIMLContainerBuilder* zParent) override;
     void setBlockTypeId(int blockTypeId);
     int getBlockTypeId() const;
     void setItemTypeId(int itemTypeId);
@@ -220,9 +216,8 @@ private:
 public:
     QuestRequirementItemInInventory();
     void processEvent(QuestEvent* zEvent, QuestStorage* zStorage) override;
-    void addRequirementUIML(QuestStorage* zStorage,
-        Framework::XML::Element* zParent,
-        Framework::Text onClickPrefix) override;
+    void addRequirementUIML(
+        QuestStorage* zStorage, UIMLContainerBuilder* zParent) override;
     void setItemTypeId(int itemTypeId);
     int getItemTypeId() const;
     void setAmount(int amount);

+ 45 - 40
FactoryCraft/QuestReward.cpp

@@ -6,6 +6,7 @@
 #include "Game.h"
 #include "Player.h"
 #include "Quest.h"
+#include "UIMLBuilder.h"
 
 QuestReward::QuestReward()
     : ReferenceCounter()
@@ -135,57 +136,61 @@ void QuestRewardGiveItems::giveReward(Framework::XML::Element* zParent,
     }
 }
 
-void QuestRewardGiveItems::addRewardUIML(Framework::XML::Element* zParent,
-    QuestStorage* zStorage,
-    Framework::Text onClickPrefix)
-{
-    Framework::XML::Element* container
-        = new Framework::XML::Element("<frame width=\"100%\" height=\"auto\" "
-                                      "display=\"column\" gap=\"10\"/>");
-    container->setAttribute("style",
-        Framework::Text() += (Framework::Fenster::Style::Sichtbar
-                              | Framework::Fenster::Style::Erlaubt));
-    container->setAttribute("id", Framework::Text("reward_") += rewardId);
-    container->addChild(new Framework::XML::Element(
-        "<text width=\"auto\" height=\"auto\">Item Reward:</text>"));
+void QuestRewardGiveItems::addRewardUIML(
+    UIMLContainerBuilder* zParent, QuestStorage* zStorage)
+{
+    UIMLContainerBuilder* containerBuilder
+        = UIMLBuilder::createContainer()
+              ->setWidthPercentage(100)
+              ->setHeightAuto()
+              ->setDisplayAsColumn(0, 10)
+              ->setStyle(Framework::Fenster::Style::Sichtbar
+                         | Framework::Fenster::Style::Erlaubt)
+              ->setID(Framework::Text("reward_") += rewardId)
+              ->addChild(UIMLBuilder::createTextAuto("Item Reward:")->build());
     for (ItemStackInfo* info : items)
     {
-        auto stack = new Framework::XML::Element(
-            "<itemStack width=\"50\" height=\"50\"/>");
-        stack->setAttribute(
-            "id", (Framework::Text("reward_") += rewardId) += "_item_stack");
-        stack->setAttribute("count", info->getCount());
-        stack->setAttribute("type", info->zItem()->getTypeId());
-        stack->addChild(
-            new Framework::XML::Element(info->zItem()->getTooltipUIML()));
-        auto text = new Framework::XML::Element(
-            "<text margin-left=\"10\" width=\"auto\" height=\"auto\"/>");
-        text->setAttribute("id",
-            (Framework::Text("reward_") += rewardId) += "_item_description");
-        text->setText((Framework::Text(info->getCount()) += " ")
-                      += info->zItem()->getName());
-        text->setAttribute("align-left", stack->getAttributeValue("id"));
-        text->setAttribute("align-y", stack->getAttributeValue("id"));
-        container->addChild(stack);
-        container->addChild(text);
+        containerBuilder->addChild(UIMLBuilder::createItemStack()
+                ->setWidth(50)
+                ->setHeight(50)
+                ->setID(
+                    (Framework::Text("reward_") += rewardId) += "_item_stack")
+                ->setAmount(info->getCount())
+                ->setItemTypeID(info->zItem()->getTypeId())
+                ->setToolTip(info->zItem()->getTooltipUIML())
+                ->build());
+        containerBuilder->addChild(UIMLBuilder::createTextAuto(
+            (Framework::Text(info->getCount()) += " ")
+            += info->zItem()->getName())
+                ->setMarginLeft(10)
+                ->setID((Framework::Text("reward_") += rewardId)
+                        += "_item_description")
+                ->setAlignLeftToElement(
+                    (Framework::Text("reward_") += rewardId) += "_item_stack")
+                ->setAlignYToElement(
+                    (Framework::Text("reward_") += rewardId) += "_item_stack")
+                ->build());
         if (zStorage->containsKey(
                 (Framework::Text("reward_") += rewardId) += "_given_to"))
         {
-            auto givenTo = new Framework::XML::Element(
-                "<text width=\"auto\" height=\"auto\" margin-top=\"10\" "
-                "text-color=\"0xFF00FF00\"/>");
             auto name = zStorage
                             ->zValue((Framework::Text("reward_") += rewardId)
                                      += "_given_to")
                             ->asString();
-            givenTo->setText(
-                (Framework::Text("Given to: ") += name->getString()));
-            givenTo->setAttribute("align-top", text->getAttributeValue("id"));
-            givenTo->setAttribute("align-x", text->getAttributeValue("id"));
-            container->addChild(givenTo);
+            containerBuilder->addChild(UIMLBuilder::createTextAuto(
+                Framework::Text("Given to: ") += name->getString())
+                    ->setMarginTop(10)
+                    ->setTextColor(0xFF00FF00)
+                    ->setAlignTopToElement(
+                        (Framework::Text("reward_") += rewardId)
+                        += "_item_description")
+                    ->setAlignXToElement(
+                        (Framework::Text("reward_") += rewardId)
+                        += "_item_description")
+                    ->build());
         }
     }
-    zParent->addChild(container);
+    zParent->addChild(containerBuilder->build());
 }
 
 QuestRewardGiveItemsType::QuestRewardGiveItemsType()

+ 5 - 6
FactoryCraft/QuestReward.h

@@ -5,6 +5,7 @@
 class Entity;
 class Item;
 class QuestStorage;
+class UIMLContainerBuilder;
 
 class QuestReward : public virtual Framework::ReferenceCounter
 {
@@ -18,9 +19,8 @@ public:
         QuestStorage* zStorage,
         Entity* zTargetEntity)
         = 0;
-    virtual void addRewardUIML(Framework::XML::Element* zParent,
-        QuestStorage* zStorage,
-        Framework::Text onClickPrefix)
+    virtual void addRewardUIML(
+        UIMLContainerBuilder* zParent, QuestStorage* zStorage)
         = 0;
     virtual bool validateSettings(
         Framework::XML::Element* zParent, QuestStorage* zStorage);
@@ -106,9 +106,8 @@ public:
     void giveReward(Framework::XML::Element* zParent,
         QuestStorage* zStorage,
         Entity* zTargetEntity) override;
-    void addRewardUIML(Framework::XML::Element* zParent,
-        QuestStorage* zStorage,
-        Framework::Text onClickPrefix) override;
+    void addRewardUIML(
+        UIMLContainerBuilder* zParent, QuestStorage* zStorage) override;
 
     friend QuestRewardGiveItemsType;
 };

+ 31 - 41
FactoryCraft/Recipie.cpp

@@ -6,6 +6,7 @@
 #include "Game.h"
 #include "Item.h"
 #include "ItemType.h"
+#include "UIMLBuilder.h"
 
 RecipieInput::RecipieInput()
     : ReferenceCounter(),
@@ -337,39 +338,33 @@ void UnshapedRecipie::produceOutputs(CraftingStorage* zStorage)
     }
 }
 
-Framework::Text UnshapedRecipie::getRecipieUIML()
+Framework::XML::Element* UnshapedRecipie::getRecipieUIML() const
 {
-    Framework::Text result = "<recipie type=\"unshaped\"><ingredients>";
+    UIMLUnshapedRecipieBuilder* builder = UIMLBuilder::createUnshapedRecipie();
     for (RecipieInput* input : inputs)
     {
-        result.append() << "<ingredient amount=\"" << input->getAmount()
-                        << "\">";
-        if (input->zFilter())
-        {
-            result.append()
-                << "<logic>" << input->zFilter()->getLogicUIML() << "</logic>";
-        }
-        result += "</ingredient>";
+        builder->addIngredient(UIMLBuilder::createRecipieIngredient()
+                ->setAmount(input->getAmount())
+                ->setFilter(input->zFilter()->getUIML()));
         // TODO: add modifiers
     }
-    result += "</ingredients><outputs>";
     for (RecipieOutput* output : outputs)
     {
         Item* item = output->createItem();
         if (item)
         {
-            result.append()
-                << "<output amount=\"" << output->getAmount()
-                << "\" itemType=\"" << item->zItemType()->getId() << "\" hp=\""
-                << item->getHp() << "\" durability=\"" << item->getDurability()
-                << "\" maxHp=\"" << item->getMaxHp() << "\" maxDurability=\""
-                << item->getMaxDurability() << "\">" << item->getTooltipUIML()
-                << "</output>";
+            builder->addOutput(UIMLBuilder::createRecipieOutput()
+                    ->setAmount(output->getAmount())
+                    ->setItemTypeID(item->zItemType()->getId())
+                    ->setHP(item->getHp())
+                    ->setDurability(item->getDurability())
+                    ->setMaxHP(item->getMaxHp())
+                    ->setMaxDurability(item->getMaxDurability())
+                    ->setToolTip(item->getTooltipUIML()));
             item->release();
         }
     }
-    result += "</outputs></recipie>";
-    return result;
+    return builder->build();
 }
 
 void UnshapedRecipie::addInput(RecipieInput* input)
@@ -439,40 +434,35 @@ void ShapedRecipie::produceOutputs(CraftingStorage* zStorage)
     }
 }
 
-Framework::Text ShapedRecipie::getRecipieUIML()
+Framework::XML::Element* ShapedRecipie::getRecipieUIML() const
 {
-    Framework::Text result = "<recipie type=\"shaped\" width=\"";
-    result.append() << width << "\" height=\"" << height << "\"><ingredients>";
+    UIMLShapedRecipieBuilder* builder
+        = UIMLBuilder::createShapedRecipie()->setWidth(width)->setHeight(
+            height);
     for (RecipieInput* input : inputs)
     {
-        result.append() << "<ingredient amount=\"" << input->getAmount()
-                        << "\">";
-        if (input->zFilter())
-        {
-            result.append()
-                << "<logic>" << input->zFilter()->getLogicUIML() << "</logic>";
-        }
-        result += "</ingredient>";
+        builder->addIngredient(UIMLBuilder::createRecipieIngredient()
+                ->setAmount(input->getAmount())
+                ->setFilter(input->zFilter()->getUIML()));
         // TODO: add modifiers
     }
-    result += "</ingredients><outputs>";
     for (RecipieOutput* output : outputs)
     {
         Item* item = output->createItem();
         if (item)
         {
-            result.append()
-                << "<output amount=\"" << output->getAmount()
-                << "\" itemType=\"" << item->zItemType()->getId() << "\" hp=\""
-                << item->getHp() << "\" durability=\"" << item->getDurability()
-                << "\" maxHp=\"" << item->getMaxHp() << "\" maxDurability=\""
-                << item->getMaxDurability() << "\">" << item->getTooltipUIML()
-                << "</output>";
+            builder->addOutput(UIMLBuilder::createRecipieOutput()
+                    ->setAmount(output->getAmount())
+                    ->setItemTypeID(item->zItemType()->getId())
+                    ->setHP(item->getHp())
+                    ->setDurability(item->getDurability())
+                    ->setMaxHP(item->getMaxHp())
+                    ->setMaxDurability(item->getMaxDurability())
+                    ->setToolTip(item->getTooltipUIML()));
             item->release();
         }
     }
-    result += "</outputs></recipie>";
-    return result;
+    return builder->build();
 }
 
 void ShapedRecipie::setWidth(int width)

+ 3 - 3
FactoryCraft/Recipie.h

@@ -91,7 +91,7 @@ public:
     virtual void consumeInputs(CraftingStorage* zStorage) = 0;
     virtual void produceOutputs(CraftingStorage* zStorage) = 0;
     virtual void apply(CraftingStorage* zStorage);
-    virtual Framework::Text getRecipieUIML() = 0;
+    virtual Framework::XML::Element* getRecipieUIML() const = 0;
     void addOutput(RecipieOutput* outputs);
     virtual Framework::Array<ItemInfo> getOutput() const;
     bool createsOutput(int itemTypeId);
@@ -164,7 +164,7 @@ public:
     bool testApplicability(CraftingStorage* zStorage) override;
     void consumeInputs(CraftingStorage* zStorage) override;
     void produceOutputs(CraftingStorage* zStorage) override;
-    Framework::Text getRecipieUIML() override;
+    Framework::XML::Element* getRecipieUIML() const override;
     void addInput(RecipieInput* input);
     const Framework::RCArray<RecipieInput>& getInputs() const;
 };
@@ -237,7 +237,7 @@ public:
     bool testApplicability(CraftingStorage* zStorage) override;
     void consumeInputs(CraftingStorage* zStorage) override;
     void produceOutputs(CraftingStorage* zStorage) override;
-    Framework::Text getRecipieUIML() override;
+    Framework::XML::Element* getRecipieUIML() const override;
     void setWidth(int width);
     int getWidth() const;
     void setHeight(int height);

+ 10 - 13
FactoryCraft/RecipieLoader.cpp

@@ -7,6 +7,7 @@
 
 #include "Game.h"
 #include "JsonUtils.h"
+#include "UIMLBuilder.h"
 
 using namespace Framework::JSON;
 using namespace Framework::Validator;
@@ -147,10 +148,10 @@ void RecipieLoader::registerRecipieList(const char* name)
     lists.add(new RecipieList(name));
 }
 
-Framework::Text RecipieLoader::getCrafingUIML(int itemTypeId)
+Framework::XML::Element* RecipieLoader::getCrafingUIML(int itemTypeId) const
 {
-    Framework::Text result = "<dialog id=\"crafting_";
-    result.append() << itemTypeId << "\"><craftingRecipies>";
+    UIMLCraftingRecipiesBuilder* recipiesBuilder
+        = UIMLBuilder::createCraftingRecipies();
     for (RecipieList* list : lists)
     {
         Framework::RCArray<Recipie> recipies;
@@ -161,19 +162,15 @@ Framework::Text RecipieLoader::getCrafingUIML(int itemTypeId)
             {
                 if (list->getName().istGleich(groupConfig->getGroupName()))
                 {
-                    result.append() << "<craftingRecipieGroup name=\""
-                                    << list->getName() << "\" itemIcon=\""
-                                    << groupConfig->getIconItemType() << "\">";
-                    for (Recipie* recipie : recipies)
-                    {
-                        result += recipie->getRecipieUIML();
-                    }
-                    result += "</craftingRecipieGroup>";
+                    recipiesBuilder->addRecipieGroup(list->getName(),
+                        groupConfig->getIconItemType(),
+                        recipies);
                     break;
                 }
             }
         }
     }
-    result += "</craftingRecipies></dialog>";
-    return result;
+    return UIMLBuilder::createDialog(Framework::Text("crafting_") += itemTypeId)
+        ->addElement(recipiesBuilder->build())
+        ->build();
 }

+ 1 - 1
FactoryCraft/RecipieLoader.h

@@ -16,5 +16,5 @@ public:
     void loadRecipies(const char* path);
     RecipieList* zRecipieList(const char* name) const;
     void registerRecipieList(const char* name);
-    Framework::Text getCrafingUIML(int itemTypeId);
+    Framework::XML::Element* getCrafingUIML(int itemTypeId) const;
 };

+ 11 - 5
FactoryCraft/TreeSeblingBlock.cpp

@@ -4,6 +4,7 @@
 #include "Game.h"
 #include "RandNoise.h"
 #include "TreeTemplate.h"
+#include "UIMLBuilder.h"
 #include "WorldGenerator.h"
 
 TreeSeblingBlock::TreeSeblingBlock(int typeId,
@@ -59,12 +60,17 @@ TickSourceType TreeSeblingBlock::isTickSource() const
     return TickSourceType::EACH_TICK;
 }
 
-Framework::Text TreeSeblingBlock::getTargetUIML()
+Framework::XML::Element* TreeSeblingBlock::getTargetUIML() const
 {
-    return Framework::Text("<targetInfo><text width=\"auto\" height=\"auto\">")
-         + Game::INSTANCE->zBlockType(typeId)->getName() + "\n" + "Growth: "
-         + Framework::Text((int)(seblingTicks / (float)seblingTicksMax * 100.f))
-         + "%</text></targetInfo>";
+    return UIMLBuilder::createContainer()
+        ->addChild(UIMLBuilder::createTextAuto(
+            Framework::Text(Game::INSTANCE->zBlockType(typeId)->getName())
+            + "\n" + "Growth: "
+            + Framework::Text(
+                (int)(seblingTicks / (float)seblingTicksMax * 100.f))
+            + "%")
+                ->build())
+        ->build();
 }
 
 TreeSeblingBlockType::TreeSeblingBlockType()

+ 1 - 1
FactoryCraft/TreeSeblingBlock.h

@@ -22,7 +22,7 @@ public:
         TickQueue* zQueue, int numTicks, bool& blocked) override;
     virtual void onPostTick() override;
     virtual TickSourceType isTickSource() const override;
-    virtual Framework::Text getTargetUIML();
+    virtual Framework::XML::Element* getTargetUIML() const override;
 
     friend TreeSeblingBlockType;
 };

+ 1767 - 0
FactoryCraft/UIMLBuilder.h

@@ -0,0 +1,1767 @@
+#pragma once
+
+#include <XML.h>
+
+#include "Recipie.h"
+
+template<typename T> class UIMLElementBuilder
+{
+protected:
+    Framework::XML::Element* result;
+
+    void calculate(int percentage, int pixelOffset, Framework::Text& result)
+    {
+        if (percentage != 0)
+        {
+            result += percentage;
+            result += "%";
+            if (pixelOffset > 0)
+            {
+                result += "+";
+            }
+            if (pixelOffset != 0)
+            {
+                result += pixelOffset;
+            }
+        }
+        else
+        {
+            result += pixelOffset;
+        }
+    }
+
+public:
+    UIMLElementBuilder()
+        : result(new Framework::XML::Element())
+    {}
+
+    ~UIMLElementBuilder()
+    {
+        if (result)
+        {
+            result->release();
+        }
+    }
+
+    T* setID(const Framework::Text& id)
+    {
+        result->setAttribute("id", id);
+        return (T*)this;
+    }
+
+    T* setWidth(int width)
+    {
+        result->setAttribute("width", Framework::Text() += width);
+        return (T*)this;
+    }
+
+    T* setHeight(int height)
+    {
+        result->setAttribute("height", Framework::Text() += height);
+        return (T*)this;
+    }
+
+    T* setWidthPercentage(int width)
+    {
+        result->setAttribute("width", (Framework::Text() += width) += "%");
+        return (T*)this;
+    }
+
+    T* setHeightPercentage(int height)
+    {
+        result->setAttribute("height", (Framework::Text() += height) += "%");
+        return (T*)this;
+    }
+
+    T* setWidth(int percentage, int pixelOffset)
+    {
+        Framework::Text value;
+        calculate(percentage, pixelOffset, value);
+        result->setAttribute("width", value);
+        return (T*)this;
+    }
+
+    T* setHeight(int percentage, int pixelOffset)
+    {
+        Framework::Text value;
+        calculate(percentage, pixelOffset, value);
+        result->setAttribute("height", value);
+        return (T*)this;
+    }
+
+    T* setAlignXStart()
+    {
+        result->setAttribute("align-x", "start");
+        return (T*)this;
+    }
+
+    T* setAlignXCenter()
+    {
+        result->setAttribute("align-x", "center");
+        return (T*)this;
+    }
+
+    T* setAlignXEnd()
+    {
+        result->setAttribute("align-x", "end");
+        return (T*)this;
+    }
+
+    T* setAlignXToElement(const char* elementId)
+    {
+        result->setAttribute("align-x", elementId);
+        return (T*)this;
+    }
+
+    T* setMarginX(int margin)
+    {
+        result->setAttribute("margin-x", Framework::Text() += margin);
+        return (T*)this;
+    }
+
+    T* setMarginXPercentage(int margin)
+    {
+        result->setAttribute("margin-x", (Framework::Text() += margin) += "%");
+        return (T*)this;
+    }
+
+    T* setMarginX(int percentage, int pixelOffset)
+    {
+        Framework::Text value;
+        calculate(percentage, pixelOffset, value);
+        result->setAttribute("margin-x", value);
+        return (T*)this;
+    }
+
+    T* setAlignLeftStart()
+    {
+        result->setAttribute("align-left", "start");
+        return (T*)this;
+    }
+
+    T* setAlignLeftCenter()
+    {
+        result->setAttribute("align-left", "center");
+        return (T*)this;
+    }
+
+    T* setAlignLeftEnd()
+    {
+        result->setAttribute("align-left", "end");
+        return (T*)this;
+    }
+
+    T* setAlignLeftToElement(const char* elementId)
+    {
+        result->setAttribute("align-left", elementId);
+        return (T*)this;
+    }
+
+    T* setMarginLeft(int margin)
+    {
+        result->setAttribute("margin-left", Framework::Text() += margin);
+        return (T*)this;
+    }
+
+    T* setMarginLeftPercentage(int margin)
+    {
+        result->setAttribute(
+            "margin-left", (Framework::Text() += margin) += "%");
+        return (T*)this;
+    }
+
+    T* setMarginLeft(int percentage, int pixelOffset)
+    {
+        Framework::Text value;
+        calculate(percentage, pixelOffset, value);
+        result->setAttribute("margin-left", value);
+        return (T*)this;
+    }
+
+    T* setAlignRightStart()
+    {
+        result->setAttribute("align-right", "start");
+        return (T*)this;
+    }
+
+    T* setAlignRightCenter()
+    {
+        result->setAttribute("align-right", "center");
+        return (T*)this;
+    }
+
+    T* setAlignRightEnd()
+    {
+        result->setAttribute("align-right", "end");
+        return (T*)this;
+    }
+
+    T* setAlignRightToElement(const char* elementId)
+    {
+        result->setAttribute("align-right", elementId);
+        return (T*)this;
+    }
+
+    T* setMarginRight(int margin)
+    {
+        result->setAttribute("margin-right", Framework::Text() += margin);
+        return (T*)this;
+    }
+
+    T* setMarginRightPercentage(int margin)
+    {
+        result->setAttribute(
+            "margin-right", (Framework::Text() += margin) += "%");
+        return (T*)this;
+    }
+
+    T* setMarginRight(int percentage, int pixelOffset)
+    {
+        Framework::Text value;
+        calculate(percentage, pixelOffset, value);
+        result->setAttribute("margin-right", value);
+        return (T*)this;
+    }
+
+    T* setAlignYStart()
+    {
+        result->setAttribute("align-y", "start");
+        return (T*)this;
+    }
+
+    T* setAlignYCenter()
+    {
+        result->setAttribute("align-y", "center");
+        return (T*)this;
+    }
+
+    T* setAlignYEnd()
+    {
+        result->setAttribute("align-y", "end");
+        return (T*)this;
+    }
+
+    T* setAlignYToElement(const char* elementId)
+    {
+        result->setAttribute("align-y", elementId);
+        return (T*)this;
+    }
+
+    T* setMarginY(int margin)
+    {
+        result->setAttribute("margin-y", Framework::Text() += margin);
+        return (T*)this;
+    }
+
+    T* setMarginYPercentage(int margin)
+    {
+        result->setAttribute("margin-y", (Framework::Text() += margin) += "%");
+        return (T*)this;
+    }
+
+    T* setMarginY(int percentage, int pixelOffset)
+    {
+        Framework::Text value;
+        calculate(percentage, pixelOffset, value);
+        result->setAttribute("margin-y", value);
+        return (T*)this;
+    }
+
+    T* setAlignTopStart()
+    {
+        result->setAttribute("align-top", "start");
+        return (T*)this;
+    }
+
+    T* setAlignTopCenter()
+    {
+        result->setAttribute("align-top", "center");
+        return (T*)this;
+    }
+
+    T* setAlignTopEnd()
+    {
+        result->setAttribute("align-top", "end");
+        return (T*)this;
+    }
+
+    T* setAlignTopToElement(const char* elementId)
+    {
+        result->setAttribute("align-top", elementId);
+        return (T*)this;
+    }
+
+    T* setMarginTop(int margin)
+    {
+        result->setAttribute("margin-top", Framework::Text() += margin);
+        return (T*)this;
+    }
+
+    T* setMarginTopPercentage(int margin)
+    {
+        result->setAttribute(
+            "margin-top", (Framework::Text() += margin) += "%");
+        return (T*)this;
+    }
+
+    T* setMarginTop(int percentage, int pixelOffset)
+    {
+        Framework::Text value;
+        calculate(percentage, pixelOffset, value);
+        result->setAttribute("margin-top", value);
+        return (T*)this;
+    }
+
+    T* setAlignBottomStart()
+    {
+        result->setAttribute("align-bottom", "start");
+        return (T*)this;
+    }
+
+    T* setAlignBottomCenter()
+    {
+        result->setAttribute("align-bottom", "center");
+        return (T*)this;
+    }
+
+    T* setAlignBottomEnd()
+    {
+        result->setAttribute("align-bottom", "end");
+        return (T*)this;
+    }
+
+    T* setAlignBottomToElement(const char* elementId)
+    {
+        result->setAttribute("align-bottom", elementId);
+        return (T*)this;
+    }
+
+    T* setMarginBottom(int margin)
+    {
+        result->setAttribute("margin-bottom", Framework::Text() += margin);
+        return (T*)this;
+    }
+
+    T* setMarginBottomPercentage(int margin)
+    {
+        result->setAttribute(
+            "margin-bottom", (Framework::Text() += margin) += "%");
+        return (T*)this;
+    }
+
+    T* setMarginBottom(int percentage, int pixelOffset)
+    {
+        Framework::Text value;
+        calculate(percentage, pixelOffset, value);
+        result->setAttribute("margin-bottom", value);
+        return (T*)this;
+    }
+
+    T* setX(int pixelOffset)
+    {
+        result->setAttribute("x", Framework::Text() += pixelOffset);
+        return (T*)this;
+    }
+
+    T* setXPercentage(int percentage)
+    {
+        result->setAttribute("x", (Framework::Text() += percentage) += "%");
+        return (T*)this;
+    }
+
+    T* setX(int percentage, int pixelOffset)
+    {
+        Framework::Text value;
+        calculate(percentage, pixelOffset, value);
+        result->setAttribute("x", value);
+        return (T*)this;
+    }
+
+    T* setY(int pixelOffset)
+    {
+        result->setAttribute("y", Framework::Text() += pixelOffset);
+        return (T*)this;
+    }
+
+    T* setYPercentage(int percentage)
+    {
+        result->setAttribute("y", (Framework::Text() += percentage) += "%");
+        return (T*)this;
+    }
+
+    T* setY(int percentage, int pixelOffset)
+    {
+        Framework::Text value;
+        calculate(percentage, pixelOffset, value);
+        result->setAttribute("y", value);
+        return (T*)this;
+    }
+
+    T* setBorder(int width, int color)
+    {
+        result->setAttribute("border", Framework::Text() += width);
+        Framework::Text value = "0x";
+        value.appendHex(color);
+        result->setAttribute("border-color", value);
+        return (T*)this;
+    }
+
+    T* setOnClickMessage(
+        const char* dialogName, std::initializer_list<char> message)
+    {
+        Framework::Text value(dialogName);
+        value += ";";
+        for (char c : message)
+        {
+            value += "(char)";
+            value.appendHex((int)c);
+        }
+        result->setAttribute("onClick", value);
+        return (T*)this;
+    }
+
+    Framework::XML::Element* build()
+    {
+        Framework::XML::Element* r = result;
+        result = 0;
+        delete this;
+        return r;
+    }
+};
+
+template<class T> class UIMLTextElementBuilder : public UIMLElementBuilder<T>
+{
+public:
+    UIMLTextElementBuilder()
+        : UIMLElementBuilder<T>()
+    {}
+
+    T* setText(const char* text)
+    {
+        this->result->setText(text);
+        return (T*)this;
+    }
+
+    T* setFontSize(int size)
+    {
+        this->result->setAttribute("font-size", Framework::Text() += size);
+        return (T*)this;
+    }
+
+    T* setWidthAuto()
+    {
+        this->result->setAttribute("width", "auto");
+        return (T*)this;
+    }
+
+    T* setHeightAuto()
+    {
+        this->result->setAttribute("height", "auto");
+        return (T*)this;
+    }
+
+    T* setTextColor(int color)
+    {
+        Framework::Text value("0x");
+        value.appendHex(color);
+        this->result->setAttribute("text-color", value);
+        return (T*)this;
+    }
+
+    T* centerHorizontally()
+    {
+        this->result->setAttribute("text-align-horizontal", "center");
+        return (T*)this;
+    }
+
+    T* centerVertically()
+    {
+        this->result->setAttribute("text-align-vertical", "center");
+        return (T*)this;
+    }
+
+    T* enableVerticalScrollbar()
+    {
+        this->result->setAttribute("vScroll", "auto");
+        return (T*)this;
+    }
+
+    T* enableHorizontalScrollbar()
+    {
+        this->result->setAttribute("hScroll", "auto");
+        return (T*)this;
+    }
+
+    T* setStyle(__int64 style)
+    {
+        this->result->setAttribute("style", Framework::Text() += style);
+        return (T*)this;
+    }
+
+    T* setDisabled(bool disabled)
+    {
+        if (disabled)
+        {
+            this->result->setAttribute("disabled", "");
+        }
+        else
+        {
+            this->result->removeAttribute("disabled");
+        }
+        return (T*)this;
+    }
+};
+
+class UIMLTextBuilder : public UIMLTextElementBuilder<UIMLTextBuilder>
+{
+public:
+    UIMLTextBuilder()
+        : UIMLTextElementBuilder()
+    {
+        result->setName("text");
+    }
+};
+
+class UIMLTextInputBuilder : public UIMLTextElementBuilder<UIMLTextInputBuilder>
+{
+public:
+    UIMLTextInputBuilder()
+        : UIMLTextElementBuilder()
+    {
+        result->setName("textfield");
+    }
+};
+
+class UIMLTextAreaBuilder : public UIMLTextElementBuilder<UIMLTextInputBuilder>
+{
+public:
+    UIMLTextAreaBuilder()
+        : UIMLTextElementBuilder()
+    {
+        result->setName("textarea");
+    }
+};
+
+class UIMLButtonBuilder : public UIMLElementBuilder<UIMLButtonBuilder>
+{
+public:
+    UIMLButtonBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("button");
+    }
+
+    UIMLButtonBuilder* setText(const char* text)
+    {
+        result->setText(text);
+        return this;
+    }
+
+    UIMLButtonBuilder* setFontSize(int size)
+    {
+        result->setAttribute("font-size", Framework::Text() += size);
+        return this;
+    }
+
+    UIMLButtonBuilder* setStyle(__int64 style)
+    {
+        result->setAttribute("style", Framework::Text() += style);
+        return this;
+    }
+};
+
+class UIMLCheckboxBuilder : public UIMLElementBuilder<UIMLCheckboxBuilder>
+{
+public:
+    UIMLCheckboxBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("check");
+    }
+
+    UIMLCheckboxBuilder* setText(const char* text)
+    {
+        result->setText(text);
+        return this;
+    }
+
+    UIMLCheckboxBuilder* setFontSize(int size)
+    {
+        result->setAttribute("font-size", Framework::Text() += size);
+        return this;
+    }
+
+    UIMLCheckboxBuilder* setStyle(__int64 style)
+    {
+        result->setAttribute("style", Framework::Text() += style);
+        return this;
+    }
+};
+
+class UIMLTableBuilder;
+
+class UIMLTableRowBuilder
+{
+protected:
+    Framework::XML::Element* result;
+    Framework::XML::Element* parentElement;
+    UIMLTableBuilder* parent;
+
+public:
+    UIMLTableRowBuilder(
+        Framework::XML::Element* zParentElement, UIMLTableBuilder* zParent)
+        : result(new Framework::XML::Element()),
+          parentElement(zParentElement),
+          parent(zParent)
+    {
+        result->setName("tr");
+    }
+
+    ~UIMLTableRowBuilder()
+    {
+        if (result)
+        {
+            result->release();
+        }
+    }
+
+    UIMLTableRowBuilder* setID(const char* id)
+    {
+        result->setAttribute("id", id);
+        return this;
+    }
+
+    UIMLTableRowBuilder* addCell(Framework::XML::Element* cell)
+    {
+        result->addChild(cell);
+        return this;
+    }
+
+    UIMLTableBuilder* build()
+    {
+        parentElement->addChild(result);
+        result = 0;
+        delete this;
+        return parent;
+    }
+};
+
+class UIMLTableBuilder : public UIMLElementBuilder<UIMLTableBuilder>
+{
+public:
+    UIMLTableBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("table");
+    }
+
+    UIMLTableRowBuilder* addRow()
+    {
+        return new UIMLTableRowBuilder(result, this);
+    }
+
+    UIMLTableBuilder* setStyle(__int64 style)
+    {
+        result->setAttribute("style", Framework::Text() += style);
+        return this;
+    }
+
+    UIMLTableBuilder* setLineHeight(int height)
+    {
+        result->setAttribute("line-height", Framework::Text() += height);
+        return this;
+    }
+};
+
+class UIMLContainerBuilder : public UIMLElementBuilder<UIMLContainerBuilder>
+{
+public:
+    UIMLContainerBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("frame");
+    }
+
+    UIMLContainerBuilder* addChild(Framework::XML::Element* child)
+    {
+        result->addChild(child);
+        return this;
+    }
+
+    UIMLContainerBuilder* setStyle(__int64 style)
+    {
+        result->setAttribute("style", Framework::Text() += style);
+        return this;
+    }
+
+    UIMLContainerBuilder* setTitle(const char* title)
+    {
+        result->setAttribute("title", title);
+        return this;
+    }
+
+    UIMLContainerBuilder* setTitleHeight(int height)
+    {
+        result->setAttribute("title-height", Framework::Text() += height);
+        return this;
+    }
+
+    UIMLContainerBuilder* setTitleFontSize(int size)
+    {
+        result->setAttribute("title-font-size", Framework::Text() += size);
+        return this;
+    }
+
+    UIMLContainerBuilder* setTitleTextColor(int color)
+    {
+        Framework::Text value("0x");
+        value.appendHex(color);
+        result->setAttribute("title-text-color", value);
+        return this;
+    }
+
+    UIMLContainerBuilder* setWidthAuto()
+    {
+        result->setAttribute("width", "auto");
+        return this;
+    }
+
+    UIMLContainerBuilder* setHeightAuto()
+    {
+        result->setAttribute("height", "auto");
+        return this;
+    }
+
+    UIMLContainerBuilder* setDisplayAsColumn(int gapPercentage, int gapPixel)
+    {
+        Framework::Text value;
+        calculate(gapPercentage, gapPixel, value);
+        result->setAttribute("gap", value);
+        result->setAttribute("display", "column");
+        return this;
+    }
+
+    UIMLContainerBuilder* setDisplayAsRow(int gapPercentage, int gapPixel)
+    {
+        Framework::Text value;
+        calculate(gapPercentage, gapPixel, value);
+        result->setAttribute("gap", value);
+        result->setAttribute("display", "row");
+        return this;
+    }
+
+    UIMLContainerBuilder* enableVerticalScrollbar()
+    {
+        this->result->setAttribute("vScroll", "auto");
+        return this;
+    }
+
+    UIMLContainerBuilder* enableHorizontalScrollbar()
+    {
+        this->result->setAttribute("hScroll", "auto");
+        return this;
+    }
+};
+
+class UIMLListSelectionBuilder
+    : public UIMLElementBuilder<UIMLListSelectionBuilder>
+{
+public:
+    UIMLListSelectionBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("listView");
+    }
+
+    UIMLListSelectionBuilder* addItem(
+        const char* id, const char* text, bool selected)
+    {
+        Framework::XML::Element* item = new Framework::XML::Element();
+        item->setName("listItem");
+        item->setAttribute("id", id);
+        item->setText(text);
+        if (selected)
+        {
+            item->setAttribute("selected", "");
+        }
+        result->addChild(item);
+        return this;
+    }
+
+    UIMLListSelectionBuilder* setOnSelectNotification(
+        const char* targetDialogName, char messageID)
+    {
+        Framework::Text value;
+        value += targetDialogName;
+        value += ";";
+        value += (int)messageID;
+        result->setAttribute("onSelectMessage", value);
+        return this;
+    }
+
+    UIMLListSelectionBuilder* setItemHeight(int height)
+    {
+        result->setAttribute("member-height", Framework::Text() += height);
+        return this;
+    }
+};
+
+class UIMLCraftingGridBuilder
+    : public UIMLElementBuilder<UIMLCraftingGridBuilder>
+{
+public:
+    UIMLCraftingGridBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("craftingGrid");
+    }
+
+    UIMLCraftingGridBuilder* setRows(int rows)
+    {
+        result->setAttribute("rowSize", Framework::Text() += rows);
+        return this;
+    }
+
+    UIMLCraftingGridBuilder* setColumns(int columns)
+    {
+        result->setAttribute("colSize", Framework::Text() += columns);
+        return this;
+    }
+
+    UIMLCraftingGridBuilder* setOutputSize(int slotSize)
+    {
+        result->setAttribute("numOutputSlots", Framework::Text() += slotSize);
+        return this;
+    }
+
+    UIMLCraftingGridBuilder* setEntitySource(int entityId)
+    {
+        result->setAttribute("target", Framework::Text() += entityId);
+        return this;
+    }
+
+    UIMLCraftingGridBuilder* setBlockSource(
+        int dimensionId, int x, int y, int z)
+    {
+        Framework::Text value;
+        value.append() << dimensionId << "," << x << "," << y << "," << z;
+        result->setAttribute("target", value);
+        return this;
+    }
+
+    UIMLCraftingGridBuilder* setBlockSource(
+        int dimensionId, int x, int y, int z, int componentIndex)
+    {
+        Framework::Text value;
+        value.append() << dimensionId << "," << x << "," << y << "," << z << ":"
+                       << componentIndex;
+        result->setAttribute("target", value);
+        return this;
+    }
+};
+
+class UIMLInventoryBuilder : public UIMLElementBuilder<UIMLInventoryBuilder>
+{
+public:
+    UIMLInventoryBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("inventory");
+    }
+
+    UIMLInventoryBuilder* setEntitySource(int entityId)
+    {
+        result->setAttribute("target", Framework::Text() += entityId);
+        return this;
+    }
+
+    UIMLInventoryBuilder* setBlockSource(int dimensionId, int x, int y, int z)
+    {
+        Framework::Text value;
+        value.append() << dimensionId << "," << x << "," << y << "," << z;
+        result->setAttribute("target", value);
+        return this;
+    }
+
+    UIMLInventoryBuilder* setRowSize(int rowSize)
+    {
+        result->setAttribute("rowSize", Framework::Text() += rowSize);
+        return this;
+    }
+
+    UIMLInventoryBuilder* setSlotNameFilter(const char* filter)
+    {
+        result->setAttribute("slotNameFilter", filter);
+        return this;
+    }
+
+    UIMLInventoryBuilder* setSlotCount(int count)
+    {
+        result->setAttribute("numSlots", Framework::Text() += count);
+        return this;
+    }
+};
+
+class UIMLCraftingProgressBuilder
+    : public UIMLElementBuilder<UIMLCraftingProgressBuilder>
+{
+public:
+    UIMLCraftingProgressBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("craftingProgress");
+    }
+
+    UIMLCraftingProgressBuilder* setTargetBlock(
+        int dimensionId, int x, int y, int z, int componentIndex)
+    {
+        Framework::Text value;
+        value.append() << dimensionId << "," << x << "," << y << "," << z << ":"
+                       << componentIndex;
+        result->setAttribute("target", value);
+        return this;
+    }
+
+    UIMLCraftingProgressBuilder* setBackgroundImage(const char* imagePath)
+    {
+        result->setAttribute("backgroundImagePath", imagePath);
+        return this;
+    }
+
+    UIMLCraftingProgressBuilder* setForegroundImage(const char* imagePath)
+    {
+        result->setAttribute("foregroundImagePath", imagePath);
+        return this;
+    }
+
+    UIMLCraftingProgressBuilder* setDirectionTOP()
+    {
+        result->setAttribute("direction", "TOP");
+        return this;
+    }
+
+    UIMLCraftingProgressBuilder* setDirectionBOTTOM()
+    {
+        result->setAttribute("direction", "BOTTOM");
+        return this;
+    }
+
+    UIMLCraftingProgressBuilder* setDirectionLEFT()
+    {
+        result->setAttribute("direction", "LEFT");
+        return this;
+    }
+};
+
+class UIMLFuelStateBuilder : public UIMLElementBuilder<UIMLFuelStateBuilder>
+{
+public:
+    UIMLFuelStateBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("fuelState");
+    }
+
+    UIMLFuelStateBuilder* setTargetBlock(
+        int dimensionId, int x, int y, int z, int componentIndex)
+    {
+        Framework::Text value;
+        value.append() << dimensionId << "," << x << "," << y << "," << z << ":"
+                       << componentIndex;
+        result->setAttribute("target", value);
+        return this;
+    }
+
+    UIMLFuelStateBuilder* setBackgroundImage(const char* imagePath)
+    {
+        result->setAttribute("backgroundImagePath", imagePath);
+        return this;
+    }
+
+    UIMLFuelStateBuilder* setForegroundImage(const char* imagePath)
+    {
+        result->setAttribute("foregroundImagePath", imagePath);
+        return this;
+    }
+
+    UIMLFuelStateBuilder* setDirectionTOP()
+    {
+        result->setAttribute("direction", "TOP");
+        return this;
+    }
+
+    UIMLFuelStateBuilder* setDirectionBOTTOM()
+    {
+        result->setAttribute("direction", "BOTTOM");
+        return this;
+    }
+
+    UIMLFuelStateBuilder* setDirectionLEFT()
+    {
+        result->setAttribute("direction", "LEFT");
+        return this;
+    }
+};
+
+class UIMLItemBarBuilder : public UIMLElementBuilder<UIMLItemBarBuilder>
+{
+public:
+    UIMLItemBarBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("itemBar");
+    }
+
+    UIMLItemBarBuilder* setEntitySource(int entityId)
+    {
+        result->setAttribute("target", Framework::Text() += entityId);
+        return this;
+    }
+
+    UIMLItemBarBuilder* setRowSize(int rowSize)
+    {
+        result->setAttribute("rowSize", Framework::Text() += rowSize);
+        return this;
+    }
+
+    UIMLItemBarBuilder* setSlotNameFilter(const char* filter)
+    {
+        result->setAttribute("slotNameFilter", filter);
+        return this;
+    }
+};
+
+class UIMLStatusBarsBuilder : public UIMLElementBuilder<UIMLStatusBarsBuilder>
+{
+public:
+    UIMLStatusBarsBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("statusBars");
+    }
+
+    UIMLStatusBarsBuilder* setEntitySource(int entityId)
+    {
+        result->setAttribute("target", Framework::Text() += entityId);
+        return this;
+    }
+};
+
+class UIMLTooltipBuilder : public UIMLElementBuilder<UIMLTooltipBuilder>
+{
+public:
+    UIMLTooltipBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("tip");
+    }
+
+    UIMLTooltipBuilder* addElement(Framework::XML::Element* element)
+    {
+        result->addChild(element);
+        return this;
+    }
+};
+
+class UIMLItemStackBuilder : public UIMLElementBuilder<UIMLItemStackBuilder>
+{
+public:
+    UIMLItemStackBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("itemStack");
+    }
+
+    UIMLItemStackBuilder* setItemTypeID(int itemTypeId)
+    {
+        result->setAttribute("type", Framework::Text() += itemTypeId);
+        return this;
+    }
+
+    UIMLItemStackBuilder* setAmount(int amount)
+    {
+        result->setAttribute("count", Framework::Text() += amount);
+        return this;
+    }
+
+    UIMLItemStackBuilder* setQuantity(int quantity)
+    {
+        result->setAttribute("quantity", Framework::Text() += quantity);
+        return this;
+    }
+
+    UIMLItemStackBuilder* setToolTip(UIMLTooltipBuilder* builder)
+    {
+        result->addChild(builder->build());
+        return this;
+    }
+};
+
+class UIMLQuestNodeBuilder : public UIMLElementBuilder<UIMLQuestNodeBuilder>
+{
+public:
+    UIMLQuestNodeBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("questGraphItem");
+    }
+
+    UIMLQuestNodeBuilder* setQuestName(const char* name)
+    {
+        result->setAttribute("name", name);
+        return this;
+    }
+
+    UIMLQuestNodeBuilder* setDescription(const char* description)
+    {
+        result->setAttribute("description", description);
+        return this;
+    }
+
+    UIMLQuestNodeBuilder* setImagePath(const char* imagePath)
+    {
+        result->setAttribute("image", imagePath);
+        return this;
+    }
+
+    UIMLQuestNodeBuilder* setFinished(bool finished)
+    {
+        result->setAttribute("finished", finished ? "1" : 0);
+        return this;
+    }
+
+    UIMLQuestNodeBuilder* setRewarded(bool rewarded)
+    {
+        result->setAttribute("rewarded", rewarded ? "1" : "0");
+        return this;
+    }
+
+    UIMLQuestNodeBuilder* setMainQuest(bool mainQuest)
+    {
+        result->setAttribute("mainQuest", mainQuest ? "1" : "0");
+        return this;
+    }
+
+    UIMLQuestNodeBuilder* setRequirements(const char* requirements)
+    {
+        result->setAttribute("requirements", requirements);
+        return this;
+    }
+};
+
+class UIMLQuestGraphBuilder : public UIMLElementBuilder<UIMLQuestGraphBuilder>
+{
+public:
+    UIMLQuestGraphBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("questGraph");
+    }
+
+    UIMLQuestGraphBuilder* setCollectionName(const char* collectionName)
+    {
+        result->setAttribute("collectionName", collectionName);
+        return this;
+    }
+
+    UIMLQuestGraphBuilder* addQuestNode(UIMLQuestNodeBuilder* questNode)
+    {
+        result->addChild(questNode->build());
+    }
+};
+
+class UIMLCraftingRecipiesBuilder
+    : public UIMLElementBuilder<UIMLCraftingRecipiesBuilder>
+{
+public:
+    UIMLCraftingRecipiesBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("craftingRecipies");
+    }
+
+    UIMLCraftingRecipiesBuilder* addRecipieGroup(const char* groupName,
+        const char* iconItemType,
+        const Framework::RCArray<Recipie>& recipies)
+    {
+        Framework::XML::Element* groupElement = new Framework::XML::Element();
+        groupElement->setName("craftingRecipieGroup");
+        groupElement->setAttribute("name", groupName);
+        groupElement->setAttribute("iconItemType", iconItemType);
+        for (const Recipie* recipie : recipies)
+        {
+            groupElement->addChild(recipie->getRecipieUIML());
+        }
+        result->addChild(groupElement);
+        return this;
+    }
+};
+
+class UIMLItemFilterBuilder
+{
+private:
+    Framework::XML::Element* result;
+
+protected:
+    UIMLItemFilterBuilder(Framework::XML::Element* result)
+        : result(result) {};
+
+public:
+    ~UIMLItemFilterBuilder()
+    {
+        if (result)
+        {
+            result->release();
+        }
+    }
+
+    Framework::XML::Element* build()
+    {
+        Framework::XML::Element* r = result;
+        result = 0;
+        delete this;
+        return r;
+    }
+
+    friend class UIMLItemAttributeFilterBuilder;
+    friend class UIMLAnyItemFilterBuilder;
+    friend class UIMLOperatorItemFilterBuilder;
+};
+
+class UIMLItemAttributeFilterBuilder
+{
+private:
+    Framework::XML::Element* result;
+
+public:
+    UIMLItemAttributeFilterBuilder()
+        : result(new Framework::XML::Element())
+    {
+        result->setName("attribute");
+    }
+
+    ~UIMLItemAttributeFilterBuilder()
+    {
+        if (result)
+        {
+            result->release();
+        }
+    }
+
+    UIMLItemAttributeFilterBuilder* requireAttributeEquals(
+        const char* attributeName, const char* attributeValue)
+    {
+        result->setAttribute("operator", "=");
+        result->setAttribute("name", attributeName);
+        result->setAttribute("value", attributeValue);
+        return this;
+    }
+
+    UIMLItemAttributeFilterBuilder* requireAttributeNotEquals(
+        const char* attributeName, const char* attributeValue)
+    {
+        result->setAttribute("operator", "!=");
+        result->setAttribute("name", attributeName);
+        result->setAttribute("value", attributeValue);
+        return this;
+    }
+
+    UIMLItemAttributeFilterBuilder* requireAttributeGreater(
+        const char* attributeName, const char* attributeValue)
+    {
+        result->setAttribute("operator", ">");
+        result->setAttribute("name", attributeName);
+        result->setAttribute("value", attributeValue);
+        return this;
+    }
+
+    UIMLItemAttributeFilterBuilder* requireAttributeGreaterOrEquals(
+        const char* attributeName, const char* attributeValue)
+    {
+        result->setAttribute("operator", ">=");
+        result->setAttribute("name", attributeName);
+        result->setAttribute("value", attributeValue);
+        return this;
+    }
+
+    UIMLItemAttributeFilterBuilder* requireAttributeLower(
+        const char* attributeName, const char* attributeValue)
+    {
+        result->setAttribute("operator", "<");
+        result->setAttribute("name", attributeName);
+        result->setAttribute("value", attributeValue);
+        return this;
+    }
+
+    UIMLItemAttributeFilterBuilder* requireAttributeLowerOrEquals(
+        const char* attributeName, const char* attributeValue)
+    {
+        result->setAttribute("operator", "<=");
+        result->setAttribute("name", attributeName);
+        result->setAttribute("value", attributeValue);
+        return this;
+    }
+
+    UIMLItemFilterBuilder* build()
+    {
+        UIMLItemFilterBuilder* builder = new UIMLItemFilterBuilder(result);
+        result = 0;
+        delete this;
+        return builder;
+    }
+};
+
+class UIMLAnyItemFilterBuilder
+{
+private:
+    Framework::XML::Element* result;
+
+public:
+    UIMLAnyItemFilterBuilder()
+        : result(new Framework::XML::Element())
+    {
+        result->setName("anyItem");
+    }
+
+    ~UIMLAnyItemFilterBuilder()
+    {
+        if (result)
+        {
+            result->release();
+        }
+    }
+
+    UIMLItemFilterBuilder* build()
+    {
+        UIMLItemFilterBuilder* builder = new UIMLItemFilterBuilder(result);
+        result = 0;
+        delete this;
+        return builder;
+    }
+};
+
+class UIMLOperatorItemFilterBuilder
+{
+private:
+    Framework::XML::Element* result;
+
+public:
+    UIMLOperatorItemFilterBuilder()
+        : result(new Framework::XML::Element())
+    {
+        result->setName("operator");
+    }
+
+    ~UIMLOperatorItemFilterBuilder()
+    {
+        if (result)
+        {
+            result->release();
+        }
+    }
+
+    UIMLOperatorItemFilterBuilder* setOperator(
+        std::function<bool(bool, bool)> operatorFunction)
+    {
+        result->setAttribute(
+            "result_0_0", Framework::Text() += (int)operatorFunction(0, 0));
+        result->setAttribute(
+            "result_0_1", Framework::Text() += (int)operatorFunction(0, 1));
+        result->setAttribute(
+            "result_1_0", Framework::Text() += (int)operatorFunction(1, 0));
+        result->setAttribute(
+            "result_1_1", Framework::Text() += (int)operatorFunction(1, 1));
+        return this;
+    }
+
+    UIMLOperatorItemFilterBuilder* setOperands(
+        UIMLItemFilterBuilder* leftOperand, UIMLItemFilterBuilder* rightOperand)
+    {
+        result->addChild(leftOperand->build());
+        result->addChild(rightOperand->build());
+        return this;
+    }
+
+    UIMLItemFilterBuilder* build()
+    {
+        UIMLItemFilterBuilder* builder = new UIMLItemFilterBuilder(result);
+        result = 0;
+        delete this;
+        return builder;
+    }
+};
+
+class UIMLRecipieIngredientBuilder
+    : public UIMLElementBuilder<UIMLRecipieIngredientBuilder>
+{
+public:
+    UIMLRecipieIngredientBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("ingredient");
+    };
+
+    UIMLRecipieIngredientBuilder* setAmount(int amount)
+    {
+        result->setAttribute("amount", Framework::Text() += amount);
+        return this;
+    };
+
+    UIMLRecipieIngredientBuilder* setFilter(UIMLItemFilterBuilder* filter)
+    {
+        Framework::XML::Element* filterElement = filter->build();
+        filterElement->setName("logic");
+        filterElement->addChild(filter->build());
+        result->addChild(filterElement);
+        return this;
+    };
+};
+
+class UIMLRecipieOutputBuilder
+    : public UIMLElementBuilder<UIMLRecipieOutputBuilder>
+{
+public:
+    UIMLRecipieOutputBuilder()
+        : UIMLElementBuilder()
+    {
+        result->setName("output");
+    };
+
+    UIMLRecipieOutputBuilder* setItemTypeID(int itemTypeId)
+    {
+        result->setAttribute("itemType", Framework::Text() += itemTypeId);
+        return this;
+    };
+
+    UIMLRecipieOutputBuilder* setAmount(int amount)
+    {
+        result->setAttribute("amount", Framework::Text() += amount);
+        return this;
+    };
+
+    UIMLRecipieOutputBuilder* setHP(float hp)
+    {
+        result->setAttribute("hp", Framework::Text() += hp);
+        return this;
+    };
+
+    UIMLRecipieOutputBuilder* setMaxHP(float hp)
+    {
+        result->setAttribute("maxHp", Framework::Text() += hp);
+        return this;
+    };
+
+    UIMLRecipieOutputBuilder* setDurability(float durability)
+    {
+        result->setAttribute("durability", Framework::Text() += durability);
+        return this;
+    }
+
+    UIMLRecipieOutputBuilder* setMaxDurability(float durability)
+    {
+        result->setAttribute("maxDurability", Framework::Text() += durability);
+        return this;
+    }
+
+    UIMLRecipieOutputBuilder* setToolTip(UIMLTooltipBuilder* tooltip)
+    {
+        result->addChild(tooltip->build());
+        return this;
+    }
+};
+
+class UIMLShapedRecipieBuilder
+    : public UIMLElementBuilder<UIMLShapedRecipieBuilder>
+{
+private:
+    Framework::XML::Element* ingredients;
+    Framework::XML::Element* outputs;
+
+public:
+    UIMLShapedRecipieBuilder()
+        : UIMLElementBuilder(),
+          ingredients(0)
+    {
+        result->setName("recipie");
+        result->setAttribute("type", "shaped");
+    };
+
+    UIMLShapedRecipieBuilder* setWidth(int width)
+    {
+        result->setAttribute("width", Framework::Text() += width);
+        return this;
+    };
+
+    UIMLShapedRecipieBuilder* setHeight(int height)
+    {
+        result->setAttribute("height", Framework::Text() += height);
+        return this;
+    };
+
+    UIMLShapedRecipieBuilder* addIngredient(
+        UIMLRecipieIngredientBuilder* ingredient)
+    {
+        if (!ingredients)
+        {
+            ingredients = new Framework::XML::Element();
+            ingredients->setName("ingredients");
+            result->addChild(ingredients);
+        }
+        ingredients->addChild(ingredient->build());
+        return this;
+    };
+
+    UIMLShapedRecipieBuilder* addOutput(UIMLRecipieOutputBuilder* output)
+    {
+        if (!outputs)
+        {
+            outputs = new Framework::XML::Element();
+            outputs->setName("outputs");
+            result->addChild(outputs);
+        }
+        outputs->addChild(output->build());
+        return this;
+    };
+};
+
+class UIMLUnshapedRecipieBuilder
+    : public UIMLElementBuilder<UIMLUnshapedRecipieBuilder>
+{
+private:
+    Framework::XML::Element* ingredients;
+    Framework::XML::Element* outputs;
+
+public:
+    UIMLUnshapedRecipieBuilder()
+        : UIMLElementBuilder(),
+          ingredients(0)
+    {
+        result->setName("recipie");
+        result->setAttribute("type", "unshaped");
+    };
+
+    UIMLUnshapedRecipieBuilder* addIngredient(
+        UIMLRecipieIngredientBuilder* ingredient)
+    {
+        if (!ingredients)
+        {
+            ingredients = new Framework::XML::Element();
+            ingredients->setName("ingredients");
+            result->addChild(ingredients);
+        }
+        ingredients->addChild(ingredient->build());
+        return this;
+    };
+
+    UIMLUnshapedRecipieBuilder* addOutput(UIMLRecipieOutputBuilder* output)
+    {
+        if (!outputs)
+        {
+            outputs = new Framework::XML::Element();
+            outputs->setName("outputs");
+            result->addChild(outputs);
+        }
+        outputs->addChild(output->build());
+        return this;
+    };
+};
+
+class UIMLDialogBuilder
+{
+private:
+    Framework::XML::Element* result;
+
+public:
+    UIMLDialogBuilder(const char* id)
+        : result(new Framework::XML::Element())
+    {
+        result->setAttribute("id", id);
+    }
+
+    ~UIMLDialogBuilder()
+    {
+        if (result)
+        {
+            result->release();
+        }
+    }
+
+    UIMLDialogBuilder* setTitle(const char* title)
+    {
+        result->setAttribute("title", title);
+        return this;
+    };
+
+    UIMLDialogBuilder* setWidth(int width)
+    {
+        result->setAttribute("width", Framework::Text() += width);
+        return this;
+    };
+
+    UIMLDialogBuilder* setHeight(int height)
+    {
+        result->setAttribute("height", Framework::Text() += height);
+        return this;
+    };
+
+    UIMLDialogBuilder* addElement(Framework::XML::Element* element)
+    {
+        result->addChild(element);
+        return this;
+    };
+
+    Framework::XML::Element* build()
+    {
+        Framework::XML::Element* r = result;
+        result = 0;
+        delete this;
+        return r;
+    }
+};
+
+class UIMLBuilder
+{
+public:
+    static UIMLTextBuilder* createText(const char* content)
+    {
+        return (new UIMLTextBuilder())->setText(content);
+    }
+
+    static UIMLTextBuilder* createTextAuto(const char* content)
+    {
+        return (new UIMLTextBuilder())
+            ->setText(content)
+            ->setHeightAuto()
+            ->setWidthAuto();
+    }
+
+    static UIMLTextInputBuilder* createTextInput(const char* content)
+    {
+        return (new UIMLTextInputBuilder())->setText(content);
+    }
+
+    static UIMLTextAreaBuilder* createTextArea(const char* content)
+    {
+        return new UIMLTextAreaBuilder();
+    }
+
+    static UIMLButtonBuilder* createButton(const char* content)
+    {
+        return (new UIMLButtonBuilder())->setText(content);
+    }
+
+    static UIMLCheckboxBuilder* createCheckbox(const char* content)
+    {
+        return (new UIMLCheckboxBuilder())->setText(content);
+    }
+
+    static UIMLTableBuilder* createTable()
+    {
+        return new UIMLTableBuilder();
+    }
+
+    static UIMLContainerBuilder* createContainer()
+    {
+        return new UIMLContainerBuilder();
+    }
+
+    static UIMLListSelectionBuilder* createListSelection()
+    {
+        return new UIMLListSelectionBuilder();
+    }
+
+    static UIMLCraftingGridBuilder* createCraftingGrid()
+    {
+        return new UIMLCraftingGridBuilder();
+    }
+
+    static UIMLInventoryBuilder* createInventory()
+    {
+        return new UIMLInventoryBuilder();
+    }
+
+    static UIMLCraftingProgressBuilder* createCraftingProgress()
+    {
+        return new UIMLCraftingProgressBuilder();
+    }
+
+    static UIMLFuelStateBuilder* createFuelState()
+    {
+        return new UIMLFuelStateBuilder();
+    }
+
+    static UIMLItemBarBuilder* createItemBar()
+    {
+        return new UIMLItemBarBuilder();
+    }
+
+    static UIMLStatusBarsBuilder* createStatusBars()
+    {
+        return new UIMLStatusBarsBuilder();
+    }
+
+    static UIMLItemStackBuilder* createItemStack()
+    {
+        return new UIMLItemStackBuilder();
+    }
+
+    static UIMLTooltipBuilder* createTooltip()
+    {
+        return new UIMLTooltipBuilder();
+    }
+
+    static UIMLQuestGraphBuilder* createQuestGraph()
+    {
+        return new UIMLQuestGraphBuilder();
+    }
+
+    static UIMLQuestNodeBuilder* createQuestNode()
+    {
+        return new UIMLQuestNodeBuilder();
+    }
+
+    static UIMLCraftingRecipiesBuilder* createCraftingRecipies()
+    {
+        return new UIMLCraftingRecipiesBuilder();
+    }
+
+    static UIMLItemAttributeFilterBuilder* createItemAttributeFilter()
+    {
+        return new UIMLItemAttributeFilterBuilder();
+    }
+
+    static UIMLAnyItemFilterBuilder* createAnyItemFilter()
+    {
+        return new UIMLAnyItemFilterBuilder();
+    }
+
+    static UIMLOperatorItemFilterBuilder* createOperatorItemFilter()
+    {
+        return new UIMLOperatorItemFilterBuilder();
+    }
+
+    static UIMLRecipieIngredientBuilder* createRecipieIngredient()
+    {
+        return new UIMLRecipieIngredientBuilder();
+    }
+
+    static UIMLRecipieOutputBuilder* createRecipieOutput()
+    {
+        return new UIMLRecipieOutputBuilder();
+    }
+
+    static UIMLShapedRecipieBuilder* createShapedRecipie()
+    {
+        return new UIMLShapedRecipieBuilder();
+    }
+
+    static UIMLUnshapedRecipieBuilder* createUnshapedRecipie()
+    {
+        return new UIMLUnshapedRecipieBuilder();
+    }
+
+    static UIMLDialogBuilder* createDialog(const char* id)
+    {
+        return new UIMLDialogBuilder(id);
+    }
+};

+ 1 - 0
Windows Version/Windows Version.vcxproj

@@ -409,6 +409,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\UIElement.h" />
     <ClInclude Include="..\FactoryCraft\UIFuelState.h" />
     <ClInclude Include="..\FactoryCraft\UIInventory.h" />
+    <ClInclude Include="..\FactoryCraft\UIMLBuilder.h" />
     <ClInclude Include="..\FactoryCraft\UIObservable.h" />
     <ClInclude Include="..\FactoryCraft\UIReference.h" />
     <ClInclude Include="..\FactoryCraft\UIText.h" />

+ 6 - 0
Windows Version/Windows Version.vcxproj.filters

@@ -127,6 +127,9 @@
     <Filter Include="world\generator\biom\plants">
       <UniqueIdentifier>{a0c4e992-95df-42f1-8e50-bc332ce9f179}</UniqueIdentifier>
     </Filter>
+    <Filter Include="UI\Builder">
+      <UniqueIdentifier>{c98c24ed-2295-480b-a68a-0c119cf6ade4}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\FactoryCraft\Server.cpp">
@@ -887,5 +890,8 @@
     <ClInclude Include="..\FactoryCraft\PlantConfig.h">
       <Filter>world\generator\biom\plants</Filter>
     </ClInclude>
+    <ClInclude Include="..\FactoryCraft\UIMLBuilder.h">
+      <Filter>UI\Builder</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>

+ 38 - 1
Windows Version/data/quests/quests.json

@@ -35,7 +35,11 @@
                 "questName": "Inventory",
                 "description": "Your inventory shows you all the items you currently have.\nYou can open it by pressing the tab key on your keyboard.\nIn your inventory you can also combine items to to create new once.\n",
                 "imagePath": "data/images/gui_icons.ltdb/questdialog.png",
-                "requiredQuestIds": [ [ "tutorial_1" ] ],
+                "requiredQuestIds": [
+                    [
+                        "tutorial_1"
+                    ]
+                ],
                 "requirements": [
                     {
                         "id": "1",
@@ -60,5 +64,38 @@
                 ]
             }
         ]
+    },
+    {
+        "name": "Stone Age",
+        "quests": [
+            {
+                "questId": "wood_sticks",
+                "questName": "Wooden Sticks",
+                "description": "You can get some wooden sticks by harvesting tree leaves.",
+                "imagePath": "data/images/gui_icons.ltdb/questdialog.png",
+                "requirements": [
+                    {
+                        "id": "1",
+                        "description": "Open the quest dialog",
+                        "type": "open_dialog",
+                        "dialogId": "quests"
+                    }
+                ],
+                "rewards": [
+                    {
+                        "rewardId": "1",
+                        "type": "give_items",
+                        "items": [
+                            {
+                                "item": {
+                                    "type": "Flint"
+                                },
+                                "count": 10
+                            }
+                        ]
+                    }
+                ]
+            }
+        ]
     }
 ]