PDA

View Full Version : onInit and subwindows



TarynWinterblade
May 3rd, 2007, 11:22
It seems that the subwindow field of a subwindow is nil at the time onInit is called.

The following code fails at the line that states l = w[target[1].list[1]] because the subwindow field of w is nil - "attempt to index global 'w' (a nil value)":


function onInit()
if target and target[1].list then
if target[1].subwindow then
w = window[target[1].subwindow[1]].subwindow
l = w[target[1].list[1]]
else
w = window[target[1].list[1]]
l = w
end

if l then
l.setUpdateFunction(update)
end
end
end


Normally, I'd have thought that I was doing something stupid (which I still may be...), but changing onInit to onHover caused it to work perfectly... but only after I had hovered over to frame to invoke the function.

My question is: is there a way to call a function after everything is setup (usually, when I was doing WoW UI design, you could get around this by putting all the stuff you needed delayed into an "onShow" function... I don't see anything resembling that in FG).


Also, I don't suppose there's a way to call a function after a set interval of time...?

Goblin-King
May 3rd, 2007, 11:42
The idea of the onInit function is to trigger after everything has been set up. This is indeed a bug, fixed in the next update.

Goblin-King
May 3rd, 2007, 12:10
Looking at this more carefully, there are probably two issues here.

First, the creation of the subwindow control, happening when the window containing the subwindow is created. I think you're actually talking about this one?

Second, the onInit of the window instance in the subwindow control. I was talking about this above.

The problem I found was that when the contained window's onInit was called, the subwindow control it didn't have the subwindow field set up. However, that doesn't seem to be that problematic, and probably is not the point of your message.

The window instance contained in the subwindow control is not created when the subwindow control is, to get a small performance boost. You can trigger the create by calling setVisible(true), but the effect is not instantaneous (as with most layout functions).

I'm thinking the best solution to this would be to add an onInstanceCreated event to subwindow controls, that would get fired after the instance in the control has been created and its onInit has been called. Would that work for your purposes and did I understand the situation correctly?

TarynWinterblade
May 3rd, 2007, 21:13
I'm thinking the best solution to this would be to add an onInstanceCreated event to subwindow controls, that would get fired after the instance in the control has been created and its onInit has been called. Would that work for your purposes and did I understand the situation correctly?

*scratches head* This is why I shouldn't post messages at 3 AM right before going to bed. :o

What I forgot to mention is that the code above was in a completely seperate control from the subwindow control, or the list that it's trying to access.

This update did allow me to accomplish my goal though, just with a slight workaround.


The code:

The controls (minus all of the anchors and parts that have no relevance to the code):

In the combat windowclass:


<subwindow name="weaponlist_window">
<!--positioning and other stuff here-->
<script>
setlist = nil

function setListFunction(sl)
setlist = sl
end

function onInstanceCreated()
if setlist then
setlist()
end
end
</script>
</subwindow>

<genericcontrol name="wl_scrollbar">
<!--positioning and other stuff here-->
<script file="scripts/charsheet_scrollbar.lua" />

<target>
<list>weaponlist</list>
<sw>weaponlist_window</sw>
</target>
</genericcontrol>


In the combat_weaponlist class (the subwindow):


<windowlist name="weaponlist">
<!--positioning and other stuff here-->
<script>
update = nil

function setUpdateFunction(u)
update = u
end

function onDrag()
if update then
update()
end
end

function onListRearranged()
if update then
update()
end
end
</script>
</windowlist>




Lastly, the scrollbar script:


w = nil
l = nil

function setScroll(pos, barwidth)
--resetAnchors()
setAnchor("left","wl_scrollbar_track","insideleft","absolute",pos)
setAnchoredWidth(barwidth)
end

function update()
local _, t = w.getPosition()
local _, h = l.getSize()

local windows = l.getWindows()
local th = 0

local offset = 0;

if windows[1] then
local _,t2 = windows[1].getPosition()
offset = (t - t2);
end

for k, v in pairs(windows) do
local _, h2 = v.getSize()
th = th + h2;
end

local barwidth = math.floor((h / th) * 55)

if barwidth > 55 then
barwidth = 55
elseif barwidth < 3 then
barwidth = 3
end

local pos = math.floor((offset / th) * 55)
if pos < 0 then
pos = 0
elseif pos > (55 - barwidth) then
pos = (55 - barwidth)
end

setScroll(pos,barwidth)
end

function setList()
if not l then
w = window[target[1].sw[1]].subwindow
l = w[target[1].list[1]]

if l then
l.setUpdateFunction(update)
update()
end
end
end

function onInit()
if target and target[1].list then
if target[1].sw then
window[target[1].sw[1]].setListFunction(setList)
else
w = window[target[1].list[1]]
l = w

if l then
l.setUpdateFunction(update)
update()
end
end
end
end




The reason why this works:

The scrollbar control calls it's onInit, which then sets up a callback function in the subwindow (the "setlist"). If that value is set when the subwindow gets instanciated, it will then call that function (I love LUA's ability to pass functions as variables).

At that point, the scrollbar control gets informed of the creation of the subwindow, and then proceeds to setup another callback on the list inside of it, this time the "update" function that's called whenever the list calls onDrag, or onListRearranged.

The scrollbar then does some neat math stuff that gets where it's position in the track, and it's size.


The end result:

The scrollbar works as you drag the list up and down, and changes itself based on adding or deleting records:

https://www.societyoflostsouls.com/images/scrollbar_example.jpg

https://www.societyoflostsouls.com/images/scrollbar_example2.jpg
(... I really should change the colors on it to make it more visible though. The scrollbar is that darker blue bar in the lighter blue stuff... which may not even be visible on lower contrast monitors... >.<)

As an interesting note: Normally, when you scroll a windowlist, it doesn't stop after it reaches the bottom element, it just kinda keeps going. When I put in the update function, it now snaps back to the bottom element (sadly, this produces a bouncing effect if you keep trying to go lower as the onDrag's update function just keeps snapping it back to the bottom)


To do:
- Make the controls into templates ("scrollbar","scrolltargetsubwindow", and "scrolledlist" or something) so that the code doesn't have to be setup each time.
- Change the scrollbar's graphics a bit.
- Allow the scrollbar to have multiple targets (only one active at a time, of course). This needs to be done to allow it to track both the weapons and ammo lists that are shown on the screenshots above.


Conclusion:
The onInstanceCreated function is very nice. Thank you guys once again for your very prompt updating of features as we discover new bugs and new wants for the engine. :)