PDA

View Full Version : Window Controls with sub-elements.



Ken L
December 12th, 2017, 00:18
Is there a way to access sub-elements within a window control?

In the toolbar template, it utilizes the toolbar_30 template which is a frame. Nested within this frame are several buttons (paint/unmask/erase) whose controls I want to access. Frames as far as the ruleset documentation states, isn't a unique kind of window control, therefore it's working off the base WindowControl. Unlike window I can't Window.getControls() to get at their sub-elements, unless I'm missing something here.

The fact that CoreRPG is stuffing buttons inside of a frame definition tells me that it's a container of some kind, and a way to get at them, but I can't find any concrete definition to proceed here.


For reference:


<toolbar_30 name="toolbar_draw">
<anchored to="toolbar_anchor">
<top />
<left anchor="right" relation="relative" />
</anchored>
<button name="unmask_button">
<id>unmask</id>
<icon>tool_mask_30</icon>
<tooltipres>image_tooltip_toolbarmask</tooltipres>
</button>

...

</toolbar_30>




<framedef name="toolbar_30">
<bitmap file="graphics/toolbar/toolbar_30.png"/>
<topleft rect="0,0,4,3" />
<top rect="4,0,32,3" />
<topright rect="62,0,4,3" />
<left rect="0,3,4,28" />
<middle rect="4,3,32,28" />
<right rect="62,3,4,28" />
<bottomleft rect="0,31,4,3" />
<bottom rect="4,31,32,3" />
<bottomright rect="62,31,4,3" />
</framedef>

ElementalAjah
December 12th, 2017, 01:31
I'm not an expert, but one thing you might be missing is that when you insert your <toolbar_30 /> control into your windowclass, you aren't referencing the <framedef> defined in on line 51 of template_toolbar.xml of the Core RPG ruleset, instead you are referencing a template with the same name defined on line 78 of the same file.



<template name="toolbar_30">
<genericcontrol>
<parameters>
<horzmargin>2</horzmargin>
<vertmargin>2</vertmargin>
<buttonsize>30</buttonsize>
</parameters>
<frame name="toolbar_30" />
<button mergerule="resetandadd" />
<script file="common/scripts/toolbar.lua" />
</genericcontrol>
</template>


Notice how the template include a <frame> tag. This is what invokes the framedef you cited. As I understand it, a framedef isn't a control, just a graphic that a control can use.

As to your original question, are you trying to get a script reference to a control contained in a windowinstance? This would basically be a property of the windowinstance object, for example window.toolbar_draw.

EDIT: As for the buttons beneath your toolbar_draw control, what you're seeing in the control definition isn't actually a sub control, it's just a set of properties of the control itself. You can access them as properties of the control, although the properties themselves are stored as tables, even if there's only one tag. For example:



if window.toolbar_draw.button and window.toolbar_draw.button[1] then
local button1 = window.toolbar_draw.button[1];
--doStuff with button1.
end


Usually you'd probably want to handle this with some kind of loop, but I'm not sure if this is actually what you want. Actually these properties are processed in the onInit function of common/scripts/toolbar.lua.


if button and type(button[1]) == "table" then
for k, v in ipairs(button) do
if v.id and v.icon then
local sID = v.id[1];
local sIcon = v.icon[1];

local sTooltip = "";
if v.tooltipres then
sTooltip = Interface.getString(v.tooltipres[1]);
elseif v.tooltip then
sTooltip = v.tooltip[1];
end

addButton(sID, sIcon, sTooltip);
end
end
end


addButton in turn goes and actually creates the button controls you want to access via script


function addButton(sID, sIcon, sTooltip)
local bToggle = false;
if toggle then
bToggle = true;
end

local button = window.createControl("toolbar_button", "");
if button then
local x = nButtonHorzMargin + (nButtons * (nButtonSize + nButtonHorzMargin));
nButtons = nButtons + 1;

local nBarWidth = x + nButtonSize + nButtonHorzMargin;
setAnchoredWidth(nBarWidth);
setAnchoredHeight(nButtonSize + (2 * nButtonVertMargin));
local w,h = getSize();

button.setAnchor("left", getName(), "left", "absolute", x);
button.setAnchor("top", getName(), "top", "absolute", nButtonVertMargin);
button.setAnchoredWidth(nButtonSize);
button.setAnchoredHeight(nButtonSize);

button.configure(self, sID, sIcon, sTooltip, bToggle);

aButtons[sID] = button;

if isVisible() then
button.setVisible(true);
end
end
end


From a cursory reading of this script I'm not sure how you'd access these dynamically created button controls at runtime, but you can try toolbar_draw["<buttonId>"], where buttonId is a value defined in the <id> tag beneath a <button> tag, for example toolbar_draw["unmask"], or maybe toolbar_draw.unmask.

Sorry I can't be more specific but maybe this will get you on the right track.

Ken L
December 12th, 2017, 02:13
As to your original question, are you trying to get a script reference to a control contained in a windowinstance? This would basically be a property of the windowinstance object, for example window.toolbar_draw.

It would technically be window.toolbar_30.unmask_button which isn't pulling anything. I then tried to work through Window.getControls() and walking towards the ButtonControl but the inability to walk the elements inside the WindowControl of the Frame stopped that.

ElementalAjah
December 12th, 2017, 02:16
Sorry, I did a ninja edit with more information above at about the same time you posted your response. Let me know if there's anything useful in there.

I don't think window.toolbar_30 is going to be correct though. toolbar_30 is the name of the template your control references, but not the control instance. I do mention trying window.toolbar_draw.unmask or window.toolbar_draw["unmask"] in my edited example above, give that a try.

Ken L
December 12th, 2017, 02:27
That's a big edit there.

The play off the window.toolbar_30's table entries is interesting, reminds me of java reflection hacks.

The addButton I believe to be a dynamic option as the buttons I reference are actually built into the window definition (campaign/record_image.xml to be exact).

Ken L
December 12th, 2017, 02:44
type(window.toobar_draw["unmask_button"]) is nil which I kinda expected from a WindowControl which toolbar_draw is. It's a container with no access to its elements which is a kinda weird framework design.

ElementalAjah
December 12th, 2017, 02:50
Okay, I just noticed something strange. The definition of toolbar_draw that I'm seeing in my version of the coreRPG ruleset looks different from what you posted above — I'd been assuming they were the same and was working off of what I had on my own machine, which may explain why it sounds like we're talking about two different things.. Mine looks like this:



<toolbar_30 name="toolbar_draw">
<anchored to="toolbar_anchor">
<top />
<left anchor="right" relation="relative" />
</anchored>
<button>
<id>unmask</id>
<icon>tool_mask_30</icon>
<tooltipres>image_tooltip_toolbarmask</tooltipres>
</button>
<button>
<id>paint</id>
<icon>tool_paint_30</icon>
<tooltipres>image_tooltip_toolbardraw</tooltipres>
</button>
<button>
<id>erase</id>
<icon>tool_erase_30</icon>
<tooltipres>image_tooltip_toolbarerase</tooltipres>
</button>
[...a few more tags]
</toolbar_30>


The buttons in my version don't look like full controls, compared to yours which has a "name" property. Also both of these are defined with a <button> tag, whereas a real button control is defined with <buttoncontrol>.

ElementalAjah
December 12th, 2017, 03:00
It's a container with no access to its elements

This is a good point. toolbar_draw is a control so shouldn't be able to contain other controls. I guess they're getting created somewhere else, probably the same window that contains toolbar_draw. If you're iterating window.getControls() and not seeing them show up though I'm not sure how to access them.

Ken L
December 12th, 2017, 03:02
The buttons in my version don't look like full controls, compared to yours which has a "name" property. Also both of these are defined with a <button> tag, whereas a real button control is defined with <buttoncontrol>.

I added the name in a custom extension to override it so I can access it. It's a moot point if I can't even see or reach the element to manipulate it.

Trenloe
December 12th, 2017, 03:05
Do a find in files in CoreRPG for toolbar_draw - you'll see the toolbar can be reached with window.toolbar.subwindow.toolbar_draw

Now that you have button names in your extension, try window.toolbar.subwindow.toolbar_draw.unmask_butto n

Ken L
December 12th, 2017, 03:16
This is all within windowclass "imagewindow_toolbar" which has no control named "toolbar" or any definition of a subwindow. I know there's some funny subwindow shenanigans that can occur (as it does on the desktop panels) but this appears pretty clear cut unless I"m missing something.

Trenloe
December 12th, 2017, 03:55
This is all within windowclass "imagewindow_toolbar" which has no control named "toolbar" or any definition of a subwindow. I know there's some funny subwindow shenanigans that can occur (as it does on the desktop panels) but this appears pretty clear cut unless I"m missing something.
Err... yes... but windowclasses can be used within other controls.

Like withing a subwindow called "toolbar":


<template name="sub_record_toolbar_image_step">
<subwindow name="toolbar">
<class>imagewindow_toolbar</class>
<activate />
</subwindow>
</template>

The above referenced template is the only place imagewindow_toolbar is used.

Hence why the GUI hierarchy I referenced exists within LUA code. Did you try this complete window reference I suggested?

Trenloe
December 12th, 2017, 04:06
Or, if you don't believe me, throw some Debug commands in looking at the FG window and subwindow script references and see what they refer to.

Output to the console window.getName() and subwindow.getName() (which may return a nil value, depending where you're checking for it - remove the code if it raises an error).

Outputting the name of key GUI references when your scripts are running can really help you understand where the code is running and where you can start traversing the FG GUI hierarchy.

Also, doing "find in files" see where control names and windowclasses are being used can help a lot as well.

ElementalAjah
December 12th, 2017, 05:09
Okay I've been doing some digging — here's what I've found.

1. As far as I can tell your name="unmask_button" attribute on the <button> tag doesn't seem to do anything at all. As I said earlier, these button tags are accessible in script as table-based properties on the control object, but however they get parsed, attributes defined in that way do not seem to get picked up by the scripting engine.

2. The button controls that are dynamically generated in the onInit and addButton functions of common/scripts/toolbar.lua DO show up when you iterate all the controls of the windowinstance object using window.getControls() that also contains toolbar_draw, BUT they do not have any names assigned to them. This is because the addButton function explicitly creates them this way.


local button = window.createControl("toolbar_button", "");

The second parameter of window.createControl() is the name to be assigned to the created control. No matter what you define in your template, it won't assign a name to the generated control. The name is necessary to identify the control. A control with a name can be accessed as a property of the containing window, for example if your control is named "unmask_button" you can use window.unmask_button to get a reference to it, but remember that the script we're using never assigns names to controls, leaving us with little option to access them at runtime. At best you can iterate window.getControls() and look for an unnamed control, but you won't have any idea WHICH unnamed control you have when you find one.

3. Technically, you could override/replace the toolbar_30 template and use your own script that does add names to the button controls as they are created, but that's a whole other can of worms. My question then is what exactly do you want to do with these buttons? Is it something that really needs to be done at runtime?

Bidmaron
December 12th, 2017, 10:59
Great detective work, Elemental.

Ken, why won't you ever post the results of what you are working? A lot of it sounds very useful. You get a lot of help on these boards, but no one gets to benefit from your work.

Ken L
December 12th, 2017, 22:20
I actually figured it out at lunch (i pushed the entire coreRPG rulset on my personal git hub), there was several initial problems here. Tren's scouting just points to the parent window which is moot as once in the subwindow, window.toolbar_draw.<element> is still correct.

1. toolbar_30 is both the name of a frame as well as a template, I linked the frame. But it was still stuffing a window control (a generic control at that) with elements.
2. The elements aren't actually stuffed into window controls which is good.
3. As Element stated, toolbar.lua as well as toolbar_button.lua are where the buttons are actually created, I was incorrect in my earlier analysis. His earlier posts were on the money. His recent post now is also correct, I pulled that away while poking at my salad (yea i'm a light weight).

The <button> element is just an XML entry... a poor use of name as I at a quick glance thought buttoncontrol. Toolbar.lua then finds these XML entries, extracts their tables, then generates actual button controls using the data stored in the <button</button> xml entry, an extremely strange choice.

To get the desired effect of access to the created button entries, I simply changed:


local button = window.createControl("toolbar_button", "");

to


local button = window.createControl("toolbar_button", sID);


in toolbar.lua

Then window.unmask for instance would return a solid value. Steering around the code base with grep is really a crappy way of getting around, especially with all the nested templates.

ElementalAjah
December 12th, 2017, 23:26
Glad to hear you got it figured out.