03/14/19, 12:59 PM | #1 |
|
ApplyTemplateToControl question
Hey guys,
I have a TopLevelWindow that contains a header, a close button to the right and two buttons ("Sounds subcategory" and "Animations subcategory"): Code:
<TopLevelControl name="AuraMasteryAuraActionsWindow" clampedToScreen="true" mouseEnabled="true" movable="true" tier="2" layer="2" hidden="true"> <Dimensions x="800" y="600" /> <Anchor point="CENTER" relativeTo="GuiRoot" relativePoint="CENTER" /> <Controls> <Backdrop name="$(parent)_Backdrop" inherits="ZO_DefaultBackdrop" /> <Label name="$(parent)_Label" font="$(BOLD_FONT)|18|soft-shadow-thin" color="C5C29E" text="Trigger Events"> <Anchor point="TOP" relativeTo="$(parent)" anchorPoint="TOP" offsetY="6" /> </Label> <Button name="$(parent)_CloseButton" inherits="ZO_CloseButton"> <OnClicked>self:GetParent():SetHidden(true)</OnClicked> </Button> <Button name="$(parent)SubCategorySounds" inherits="ZO_DefaultButton" text="Animations"> <Anchor point="TOPLEFT" relativeTo="$(parent)" anchorPoint="TOPLEFT" offsetX="0" offsetY="42" /> <OnClicked> WINDOW_MANAGER:ApplyTemplateToControl(self:GetParent():GetNamedChild("_DisplayContainer"), "AM_TEMP_ANIMATIONS") </OnClicked> </Button> <Button name="$(parent)SubCategoryAnimations" inherits="ZO_DefaultButton" text="Sounds"> <Anchor point="TOPLEFT" relativeTo="$(parent)" anchorPoint="TOPLEFT" offsetX="120" offsetY="42" /> <OnClicked> WINDOW_MANAGER:ApplyTemplateToControl(self:GetParent():GetNamedChild("_DisplayContainer"), "AM_TEMP_SOUNDS") </OnClicked> </Button> <Control name="$(parent)_DisplayContainer"> <Anchor point="TOPLEFT" relativeTo="$(parent)" anchorPoint="TOPLEFT" offsetY="86" /> <Anchor point="BOTTOMRIGHT" relativeTo="$(parent)" anchorPoint="BOTTOMRIGHT" /> <Controls> <!-- <Backdrop name="$(parent)BG" centerColor="00000000" edgeColor="00FF00"> <AnchorFill /> <Edge edgeSize="1" /> </Backdrop> --> </Controls> </Control> </Controls> </TopLevelControl> I wanted to use ApplyTemplateToControl() to "attach" two different menues to "$(parent)_DisplayContainer", but the function probably works differently from what I expected. When hiting the "AnimationsButton" for the first time everything works perfectly, the DisplayContainer is filled with the "animations template". When hiting the "SoundsButton" the DisplayContainer is filled with the "sounds template", but the "animations template" is not removed. Is ApplyTemplateToControl() not working like a templating system in php or anything comparable? /edit: I have a suspicion: The function is used only to change data in two templates of the same structure and not to entirely replace template a) with template b), is that correct? If yes, is there another function or lib that does what I need? Thanks in advance! Last edited by Letho : 03/14/19 at 01:10 PM. |
03/14/19, 02:22 PM | #2 |
you need to use "overide = true" if you want to change the parameters of an existing object. I tried to do it with InventoryRowControl, but I could not get a fully working version. If you need to change the object that you created, then I would use XML only for creating the structure of objects, and all the remaining parameters would be assigned to the LUA.
|
|
03/14/19, 04:48 PM | #3 |
|
Ah no it's not about changing an existing objects parameters, it's about entirely replacing a template by another. Example:
Container C: << apply template A to this container (menu for animations) when a button is klicked. Once another button is klicked, apply template B to this container, with B having entirely different controls. Template A should be removed from C. I want to "load" menues into a container, like using templates in php. Until now I have always anchored the controls from A to a control pool element and set them to hidden. But swaping menues by reanchoring A to a hidden element + anchoring B to C does not feel elegant. |
03/14/19, 04:51 PM | #4 |
That's not possible. Controls are here to stay once they are created. There is no way to delete them. Not even with templates.
|
|
03/14/19, 05:16 PM | #5 | |
@Letho but as Siri said, a pool for saving objects for quick access. If you decide to completely replace the object in the pool, it will not be elegant, it will be terribly expensive in terms of resources. |
||
03/14/19, 06:45 PM | #6 | ||
|
https://cdn-eso.mmoui.com/preview/pvw6325.png A (De)Buff trigger has totally different configuration parameters than a combat event based trigger (the latter does not require a "Source Unit", but target and source parameters, actionResults that the aura should react to, etc.). So the "Trigger Settings" submenu totally changes if the user changes the trigger type form "(De)Buff" to "Combat Event" by using the appropriate combobox. I cannot think of a more elegant way to achieve this than just taking all relevant controls and reanchoring them to hidden pools. Last edited by Letho : 03/14/19 at 06:49 PM. |
||
03/14/19, 07:46 PM | #7 | |
|
|
|
03/14/19, 10:28 PM | #8 |
So as I understand it, you want to have the Source Unit line disappear if the player has a combat event trigger? An OnInitialized field in the virtual might work: You could change anchors + hide the source control in it.
But doing it yourself via anchors and SetHidden would probably be the easiest and simplest method. I think you could also use ApplyTemplateToControl for styling. I'm pretty sure controls created from Lua can handle OnUpdate. I haven't tried OnUpdate specifically but I have done OnClicked and some others, so I don't see why OnUpdate would be an exception. (control:SetHandler("OnUpdate", functionStuff) should work) |
|
03/15/19, 12:47 AM | #9 | |
@Siri, what do you say? |
||
03/15/19, 06:01 AM | #10 | |
|
||
03/15/19, 10:25 AM | #11 |
|
Thanks for all the answers, guys, much appreciated! I will dig myself into SetCustomAcquireBehavior() and see how I can implement it!
|
03/15/19, 10:45 AM | #12 |
|
I do remember having trouble with an OnUpdate event for a toplevel window created through lua but it was a very long time ago so maybe I did something wrong
|
03/15/19, 12:12 PM | #13 |
|
They do call <OnUpdate>. Virtual controls DO NOT call <OnInitialized> though, each child control of a virtual has to call the <OnInitialized> functions seperately. That is very strange...
|
03/15/19, 12:53 PM | #14 | |
|
A short excerpt from the control pool source:
So I will probably have to write a lib for it. Very time intense and I am not very experienced in writing performant code |
|
03/15/19, 02:08 PM | #15 | ||
|
However, control created via CreateControl() -- I've tested with CT_LABEL -- DOES NOT call handler set via control:SetHandler("OnUpdate", ...).
For example here: https://github.com/merlight/eso-merT...es.xml#L67-L69 Had the <OnInitialized> part not been called, I'd be getting "attempt to index a nil value" whenever I try to access control.label member. |
||
03/15/19, 02:36 PM | #16 | |
<OnInitialized> is called once when an object is created, any global function or Lua code can be placed here. Xml Code:
|
||
03/15/19, 06:38 PM | #17 |
|
Okay, this is the XML that contains the container ("$(parent)_DisplayContainer") where the templates should be applied to:
Code:
<TopLevelControl name="AuraMasteryAuraActionsWindow" clampedToScreen="true" mouseEnabled="true" movable="true" tier="1" layer="2" hidden="true"> <Dimensions x="800" y="600" /> <Anchor point="CENTER" relativeTo="GuiRoot" relativePoint="CENTER" /> <Controls> <Backdrop name="$(parent)_Backdrop" inherits="ZO_DefaultBackdrop" /> <Label name="$(parent)_Label" font="$(BOLD_FONT)|18|soft-shadow-thin" color="C5C29E" text="Trigger Events"> <Anchor point="TOP" relativeTo="$(parent)" anchorPoint="TOP" offsetY="6" /> </Label> <Button name="$(parent)_CloseButton" inherits="ZO_CloseButton"> <OnClicked>self:GetParent():SetHidden(true)</OnClicked> </Button> <Button name="$(parent)SubCategorySounds" inherits="ZO_DefaultButton" text="Animations"> <Anchor point="TOPLEFT" relativeTo="$(parent)" anchorPoint="TOPLEFT" offsetX="0" offsetY="42" /> <OnClicked> WINDOW_MANAGER:ApplyTemplateToControl(self:GetParent():GetNamedChild("_DisplayContainer"), "AM_TEMP_ANIMATIONS") </OnClicked> </Button> <Button name="$(parent)SubCategoryAnimations" inherits="ZO_DefaultButton" text="Sounds"> <Anchor point="TOPLEFT" relativeTo="$(parent)" anchorPoint="TOPLEFT" offsetX="120" offsetY="42" /> <OnClicked> WINDOW_MANAGER:ApplyTemplateToControl(self:GetParent():GetNamedChild("_DisplayContainer"), "AM_TEMP_SOUNDS") </OnClicked> </Button> <Control name="$(parent)_DisplayContainer" override="true"> <Anchor point="TOPLEFT" relativeTo="$(parent)" anchorPoint="TOPLEFT" offsetY="86" /> <Anchor point="BOTTOMRIGHT" relativeTo="$(parent)" anchorPoint="BOTTOMRIGHT" /> <Controls> <!-- <Backdrop name="$(parent)BG" centerColor="00000000" edgeColor="00FF00"> <AnchorFill /> <Edge edgeSize="1" /> </Backdrop> --> </Controls> </Control> </Controls> </TopLevelControl> This is Template A: Code:
<Control name="AM_TEMP_ANIMATIONS" virtual="true"> <!-- STRANGE: <OnInitialized> is not called for this control, only for it's child controls! Probably because it's a virtual? So we use the lastly initialized control's <OnInitialized>... --> <Controls> <Label name="$(parent)_LabelTrigger" font="$(BOLD_FONT)|18|soft-shadow-thin" color="C5C29E" text="On Trigger:"> <Anchor point="TOPLEFT" relativeTo="$(parent)" anchorPoint="TOPLEFT" offsetY="8" /> </Label> <Control name="$(parent)_TriggerAnimationEnabled" inherits="AM_TriggerControl" override="true"> <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetY="40" /> <Controls> <Button name="$(parent)_Checkbox" inherits="ZO_CheckButton" override="true"> <Anchor point="RIGHT" relativeTo="$(parent)" relativePoint="RIGHT" offsetX="-4" /> <OnInitialized> ZO_CheckButton_SetToggleFunction(self, AuraMastery.EditAuraTriggerAnimation) </OnInitialized> <OnEffectivelyShown> AuraMastery.UpdateTriggerAnimationCheckbox(self) </OnEffectivelyShown> </Button> </Controls> <OnInitialized> self:GetNamedChild("_Label"):SetText("Play Screen Flash Animation:") </OnInitialized> </Control> <Control name="$(parent)_TriggerAnimationColor" inherits="AM_TriggerControl" override="true"> <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetY="70" /> <OnInitialized> self:GetNamedChild("_Label"):SetText("Flash Color:") AuraMastery:InitAnimationColorColorSelect(self) </OnInitialized> </Control> <Control name="$(parent)_TriggerAnimationEndAlpha" inherits="AM_TriggerControl" override="true"> <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetY="100" /> <Controls> <Backdrop name="$(parent)_Editbox" inherits="AM_EditBox" override="true"> <Anchor point="RIGHT" relativeTo="$(parent)" relativePoint="RIGHT" offsetX="-4" /> <OnInitialized> local editbox = self:GetNamedChild("_Editbox") editbox:SetHandler("OnEnter", function() AuraMastery:EditAuraTriggerAnimationEndAlpha(editbox); end) </OnInitialized> </Backdrop> </Controls> <OnInitialized> self:GetNamedChild("_Label"):SetText("Max Flash Transparency:") </OnInitialized> </Control> <Control name="$(parent)_TriggerAnimationDuration" inherits="AM_TriggerControl" override="true"> <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetY="130" /> <Controls> <Backdrop name="$(parent)_Editbox" inherits="AM_EditBox" override="true"> <Anchor point="RIGHT" relativeTo="$(parent)" relativePoint="RIGHT" offsetX="-4" /> <OnInitialized> local editbox = self:GetNamedChild("_Editbox") editbox:SetHandler("OnEnter", function() AuraMastery:EditAuraTriggerAnimationDuration(editbox); end) </OnInitialized> </Backdrop> </Controls> <OnInitialized> self:GetNamedChild("_Label"):SetText("Duration per Flash:") </OnInitialized> </Control> <Control name="$(parent)_TriggerAnimationLoopCount" inherits="AM_TriggerControl" override="true"> <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetY="160" /> <Controls> <Backdrop name="$(parent)_Editbox" inherits="AM_EditBox" override="true"> <Anchor point="RIGHT" relativeTo="$(parent)" relativePoint="RIGHT" offsetX="-4" /> <OnInitialized> local editbox = self:GetNamedChild("_Editbox") editbox:SetHandler("OnEnter", function() AuraMastery:EditAuraTriggerAnimationLoopCount(editbox); end) </OnInitialized> </Backdrop> </Controls> <OnInitialized> self:GetNamedChild("_Label"):SetText("Number of Flashes:") -- -- ATTENTION: Always call "AuraMastery.UpdateTriggerAnimationCheckbox()" on the controlSet's control that ist INITIALIZED LASTLY!!! -- This is neccessary because controls are initialized one after another. If this was called on the checkbox's (first control) OnInitialized, the consecutively called update function for the whole control set -- would be called at a time, where the other, consecutive controls are not initialized yet and hence produce errors. This is a bit unlucky but for the time being the only solution that I can think of. -- Calling it OnInitialized on the whole controlSet does not work as the controlSet's parental control is of type virtual and hence does call OnInitialized... -- local checkbox = self:GetParent():GetNamedChild("_TriggerAnimationEnabled"):GetNamedChild("_Checkbox") AuraMastery.UpdateTriggerAnimationCheckbox(checkbox) </OnInitialized> </Control> </Controls> </Control> Code:
<!-- TEMPORARY!! --> <Control name="AM_TEMP_SOUNDS" virtual="true"> <Controls> <Label name="$(parent)_LabelTrigger" font="$(BOLD_FONT)|18|soft-shadow-thin" color="C5C29E" text="On Trigger:"> <Anchor point="TOPLEFT" relativeTo="$(parent)" anchorPoint="TOPLEFT" offsetY="8" /> </Label> <Control name="$(parent)_TriggerActions" inherits="AM_TriggerControl"> <Dimensions x="550" y="28" /> <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetY="36" /> <Controls> <Control name="$(parent)_ScrollableComboBox" inherits="AM_ScrollableComboBox" tier="2"> <Dimensions x="420" y="28" /> <Anchor point="RIGHT" relativeTo="$(parent)" relativePoint="RIGHT" offsetY="1" offsetX="1" /> </Control> </Controls> <OnInitialized> self:GetNamedChild("_Label"):SetText("Play Sound:") AuraMastery:InitTriggerSoundsComboBox() deb("OnInitialized called...") </OnInitialized> <OnEffectivelyShown> AuraMastery.UpdateTriggerSoundSelect() deb("OnEffectivelyShown called...") </OnEffectivelyShown> <OnEffectivelyHidden> deb("OnEffectivelyHidden called...") </OnEffectivelyHidden> </Control> <Label name="$(parent)_LabelUntrigger" font="$(BOLD_FONT)|18|soft-shadow-thin" color="C5C29E" text="On Untrigger:"> <Anchor point="TOPLEFT" relativeTo="$(parent)" anchorPoint="TOPLEFT" offsetY="96" /> </Label> <Control name="$(parent)_UntriggerActions" inherits="AM_TriggerControl"> <Dimensions x="550" y="28" /> <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetY="120" /> <Controls> <Control name="$(parent)_ScrollableComboBox" inherits="AM_ScrollableComboBox" tier="2"> <Dimensions x="420" y="28" /> <Anchor point="RIGHT" relativeTo="$(parent)" relativePoint="RIGHT" offsetY="1" offsetX="1" /> </Control> </Controls> <OnInitialized> self:GetNamedChild("_Label"):SetText("Play Sound:") AuraMastery:InitUntriggerSoundsComboBox() </OnInitialized> <OnEffectivelyShown> AuraMastery.UpdateUntriggerSoundSelect() deb("OnEffectivelyShown called...") </OnEffectivelyShown> <OnEffectivelyHidden> deb("OnEffectivelyHidden called...") </OnEffectivelyHidden> </Control> </Controls> </Control> When I hit the first button, template A gets applied to "_DisplayContainer". Whenever I hit the second button and template B gets applied to "_DisplayContainer" aswell, A and B are mixed together, override="true" does not change anything. Here is a screenshot of what happens after pressing both buttons: I want Template A to be entirely replaced by Template B and vice versa. I tested it with template A and template B having only one label control of the same structure just with different texts. It worked flawlessly. Override="true" was only neccessary if the header B had some other attributes, etc. As I see it, you cannot overwrite one control with a different control type. Last edited by Letho : 03/15/19 at 07:17 PM. |
03/15/19, 08:03 PM | #18 |
|
As for the comment "STRANGE: <OnInitialized> is not called for this control, ..."
ApplyTemplateToControl does not create the target control -- it must've been created previously (and its OnInitialized handler called, if it had any) -- I think that's why it doesn't call the template's top-level <OnInitialized> handler (it would be called if you used the template to CreateControlFromVirtual). The template's children that didn't exist on the target control actually do get created by ApplyTemplateToControl, so their <OnInitialized> get called. Anyway, I think you're trying to use ApplyTemplateToControl for something it's not been intended for. There's no way to remove a control from the UI once it's been created. It can be repurposed or hidden, but it's there until /reloadui. I suggest you create a distinct control container for each mode and switch between them by showing one and hiding the other. |
03/16/19, 12:45 AM | #19 | |
|
|
|
ESOUI » Developer Discussions » General Authoring Discussion » ApplyTemplateToControl question |
«
Previous Thread
|
Next Thread
»
|
Display Modes |
Linear Mode |
Switch to Hybrid Mode |
Switch to Threaded Mode |
|
|