Understanding Frame Visibility - meldavy/ipf-documentation GitHub Wiki
As with my other pages, I like to write about my findings in an educational way. This page is also an educational writeup about things I was running into and how I tested and found out about how things worked. For those more interested in a pure documentation writeup, I'll follow up this article with a documentation once I better understand the UI framework.
After completing the Banderilla Addon, which was a learning exercise for me to get familiar with some of the more simple concepts of the TOS UI framework, my next big ambitious project was the AutoAwakening Addon. Here, I wanted to make some big modifications to an existing UI frame (the itemdungeon frame, which is the equip awakening window) and add some custom elements and controls.

I'd say I was pretty successful at achieving what I wanted to achieve. But along the way, I was banging my head against the wall on one small issue. I wanted to use a timer control to perform the awakening every 1 second.
<?xml version="1.0" encoding="UTF-8"?>
<uiframe name="autoawakening" x="0" y="0" width="0" height="0">
<controls>
<timer name="addontimer" rect="0 0 10 10"/>
</controls>
</uiframe>... somewhere inside my code
function MyFunc()
local frame = ui.GetFrame('autoawakening');
local timer = frame:GetChild('addontimer');
AUTO_CAST(timer)
timer:Start(1);
endEverything looked incredibly fine. My Function was getting a timer control named addontimer from the autoawakening frame, which was exactly how it was defined in my xml.
However, the timer would only execute the UpdateScript once, and would never tick, even if I never stopped the timer.
While debugging, I removed the timer from the autoawakening xml, and instead programatically added a timer to the itemdungeon frame (the awakening window) instead like so:
function SomeInitFunc()
local frame = ui.GetFrame('itemdungeon');
local addontimer = frame:CreateOrGetControl("timer", "addontimer", 10, 10);
endAnd surprisingly, my timer code started working as expected. To ship my addon, I decided to use this solution, and after completing the addon development, I decided to jump back into this issue to really understand what was going on.
My assumption was that this was probably something that either had to do with:
- Frame visibility
- Frame lifecycle
Looking at the xml file of the Banderilla addon to see some of the more obvious differences:
<uiframe name="banderilla" x="470" y="30" width="233" height="60" hud="true">
<option visible="true" hideable="false" closebutton="false" alwaysVisible="false"/>
...
</uiframe>- The banderilla addon had
visible="true"option enabled - The banderilla addon's timer was coded so that it only ran when the frame's visibility == 1.
So those were some of my leads.
This lead me to think about "opening" and "closing" of frames:
ui.OpenFrame(uiName);
ui.CloseFrame(uiName);
ui.ToggleFrame(uiName);What is the difference between Open, Close, and setting a frame's visibility, and setting a frame's ShowWindow?
frame:SetVisible(1);
frame:SetVisible(0);
frame:ShowWindow(1);
frame:ShowWindow(0);ui.OpenFrame(uiName); and ui.CloseFrame(uiName); is indeed EXACTLY THE SAME as frame:ShowWindow(1) and frame:ShowWindow(0). Simply use ShowWindow() if you already have a reference to the frame. use OpenFrame() and CloseFrame() if you don't have a reference to the frame.
SetVisible() is slightly different. While SetVisible(0) has very similar action to CloseFrame(), SetVisible(1) works a little differently.
- Calling
SetVisible(1)on a frame that has been hidden throughCloseFrame()orShowWindow(0)does NOT become visible. - After a frame is closed, the only way to make it visible again is through
OpenFrame()orShowWindow(1)
However, there is a strange behavior with the timer control.
The timer control only ticks when the frame is visible. However, it can also tick when:
- Frame is hidden through
CloseFrame()orShowWindow(0), and thenSetVisible(1)is called. When this happens, the frame stays invisible, but the timer resumes ticking.
I think this is a trick that can be used to create timers attached to invisible frames.