PDA

View Full Version : Can't anchor to bottom of window... makes creating scrollbar impossible.



celestian
July 8th, 2019, 08:39
I've been trying to figure this out for a while. I am prototyping a different window view for a CT (this is primitive).

I am listing 2 subwindows within a windowclass that is created as a entry for a windowlist called from another windowclass.

I started using frame background colors (yup, this is really ugly) to try and figure out whats up. You can see here what I'm talking about. The key problem is there should be a green panel that is all the way to the bottom of the window from below the header (you can't even see it in this shot). Because of this (I am speculating) it won't create scrollbar on the subwindows.

https://i.imgur.com/8NaatCj.png



<windowclass name="cta_main_selected_host">
<frame name="field-red" />
<sheetdata>
<subwindow name="header">
<anchored>
<top offset="35" />
<left offset="13" />
<right offset="-5" />
</anchored>
<activate />
<fastinit />
<class>selected_entry_header</class>
<frame name="headergray" offset="5,5,5,5" />
</subwindow>

<!-- anchor target for the subwindows in tabs -->
<genericcontrol name="subwindow_target">
<frame name="field-yellow" />
<anchored to="header">
<top anchor="bottom" relation="relative" />
<right />
<left />
</anchored>
<disabled />
</genericcontrol>

<subwindow name="actions">
<frame name="field-green" />
<anchored to="subwindow_target" >
<top anchor="bottom" offset="5" />
<left parent="" anchor="left" offset="5"/>
<right parent="" anchor="right" offset="-45"/>
<bottom parent="" anchor="bottom" offset="-5"/>
</anchored>
<activate />
<fastinit />
<class>cta_actions_host</class>
</subwindow>
<scrollbar>
<anchored to="actions" />
<target>actions</target>
</scrollbar>

<subwindow name="stats">
<frame name="field-blue" />
<anchored to="subwindow_target" >
<top anchor="bottom" offset="5" />
<left parent="" anchor="left" offset="5"/>
<right parent="" anchor="right" offset="-45"/>
<bottom parent="" anchor="bottom" />
</anchored>
<class>cta_stats_host</class>
<activate />
<fastinit />
</subwindow>
<scrollbar>
<anchored to="stats" />
<target>stats</target>
</scrollbar>

<tabs_cta>
<tab>
<icon>htab_actions_icon</icon>
<subwindow>actions</subwindow>
<tooltiptext>Actions</tooltiptext>
</tab>
<tab>
<icon>htab_stats_icon</icon>
<subwindow>stats</subwindow>
<tooltiptext>Effects, Ability Scores and Saves</tooltiptext>
</tab>
</tabs_cta>
</sheetdata>
</windowclass>


Now if I remove the "<bottom parent="" anchor="bottom" offset="-5"/>" completely from the subwindow entries the windows WILL show but will not give a scrollbar. I can put a scrollbar on the windowclass calling the windowlist and it will place a scrollbar for the entire window but I want just the subwindows to scroll, NOT the header.

Moon Wizard
July 8th, 2019, 23:43
The subwindow must have a top and bottom anchor or a height, and the embedded window must be larger than the subwindow, in order for the scrollbar to appear.

I can't see exactly what the problem is from your code, but this is similar to how the character sheets with tabs are built. The main difference is that you are trying to make the header dynamically size. You might try working with a static size header first, and then explore dynamically resizing header.

When I've run into similar situations, I'll had handlers to onSizeChanged for the window, and query the position/size of the controls I'm interested in to make sure they are in the right place.

Regards,
JPG

celestian
July 9th, 2019, 05:22
The subwindow must have a top and bottom anchor or a height, and the embedded window must be larger than the subwindow, in order for the scrollbar to appear.

I can't see exactly what the problem is from your code, but this is similar to how the character sheets with tabs are built. The main difference is that you are trying to make the header dynamically size. You might try working with a static size header first, and then explore dynamically resizing header.

When I've run into similar situations, I'll had handlers to onSizeChanged for the window, and query the position/size of the controls I'm interested in to make sure they are in the right place.

Regards,
JPG

(let me try this again, the forum just ate my post... sigh)

What do you mean embedded window?

I've tried various combinations based on your suggestions but still no luck. I can't get any subwindow or genericcontrol to allow me to use <bottom> at all and actually work. They just truncate right below the header or where ever I start them. Even with parent set to "nil".

Is there some special case for using windowlist that might be causing this? This windowclass is created by the windowlist.
Here is the code I use for the windowlist that creates each entry of windowclass "cta_main_selected_host".



<!-- template for windowlist of selected_entry -->
<template name="list_cta_selected_host">
<windowlist>
<script file="cta/scripts/cta_selected_host.lua" />
<anchored>
<top anchor="top" relation="relative" offset="3" />
<left anchor="left" offset="1" />
<right anchor="right" offset="-15" />
<bottom anchor="bottom" offset="-3" />
</anchored>
<child></child>
<child><backcolor>1A40301E</backcolor></child>
<!-- <noscroll /> -->
<class>cta_main_selected_host</class>
<frame name="field-initiative" offset="0,0,0,0" />
</windowlist>
</template>


I've tried using the noscroll option but that doesn't seem to do anything but block all scroll in the windowlist entry as best I can tell. I thought with that enabled I could create the scrollbar and it would function.

It might be worth noting that this windowlist never shows more than one entry? I've a filter set to only show the one flagged selected.
cta/scripts/cta_selected_host.lua


function onFilter(win)
--Debug.console("cta_selected_host.lua","onFilter","win",win);
-- we only show the entry that is "selected" == 1;
local node = win.getDatabaseNode();
local bSelected = (DB.getValue(node,"selected",0) == 1);
return bSelected;
end



I've tried to emulate the windowclass "npc" since it does something like this and works but using all the same configuration steps it doesn't work. I've tossed that out and begun testing another method that should work but doesn't.



<!-- main selected window, actions/saves/etc, right side with all the fun stuff -->
<windowclass name="cta_main_selected_host">
<frame name="field-red" />
<sheetdata>

<subwindow name="header">
<anchored>
<top offset="35" />
<left offset="13" />
<right offset="-10" />
</anchored>
<activate />
<fastinit />
<class>selected_entry_header</class>
<frame name="headergray" offset="5,5,5,5" />
</subwindow>

<genericcontrol name="contentanchor">
<anchored height="0">
<top parent="header" anchor="bottom" offset="25" />
<left parent="" anchor="left" offset="0" />
<right parent="" anchor="right" offset="0" />
</anchored>
<disabled />
<frame name="field-yellow" />
</genericcontrol>

<subwindow name="actions">
<frame name="field-green" />
<anchored to="contentanchor" >
<top anchor="top" offset="0" />
<left parent="" anchor="left" offset="5"/>
<right parent="" anchor="right" offset="-45"/>
<!-- <bottom parent="" anchor="bottom" offset="-5"/> -->
</anchored>
<activate />
<fastinit />
<class>cta_actions_host</class>
</subwindow>
<scrollbar>
<anchored to="actions" >
<top offset="5" />
<bottom offset="5" />
<left parent="" anchor="right" offset="-5" />
</anchored>
<target>actions</target>
</scrollbar>

</sheetdata>
</windowclass>



(ignore the garish looks, I am using bright frames to figure out where things are landing).

The above looks like this when <bottom parent="" anchor="bottom" offset="-5"/> is commented out. Note, lack of scrollbar. The mouse wheel DOES scroll it but it does the entire window, not the actions subwindow.

https://i.imgur.com/IBmgV3U.png


When I uncomment the "bottom" line it looks like this.

https://i.imgur.com/bmQDQwH.png

Moon Wizard
July 10th, 2019, 01:43
I think I might know what's happening. Your window is embedded within a list (embedded = child window), and you are setting up everything inside the embedded list window. However, embedded list windows only grow to fit the controls that are inside them (i.e. with defined positions and static height/width). In this case, your "selected window" is empty size to start with (before layout to add controls), and the actions subwindow anchors to that empty size. If top and bottom anchor defined on a control, it doesn't have any inherent height of it's own, so doesn't expand the parent window.

A couple options:

* Implement the details area as two subwindows. One with summary (name, link, etc.); and another with details (actions, spells, etc.). When selecting an entry in the CT list, then use subwindow.setValue to change the detail windows. Of course, this means that those windows are rebuilt each time.

* Dynamically set the height of the actions control using setAnchoredHeight, based on parentcontrol.window.getSize(); and capture the onSizeChanged event for the top level CT to pass down to each list child window to resize that control. Then, the whole list knows which size it should be.

Regards,
JPG

celestian
July 10th, 2019, 04:36
I think I might know what's happening. Your window is embedded within a list (embedded = child window), and you are setting up everything inside the embedded list window. However, embedded list windows only grow to fit the controls that are inside them (i.e. with defined positions and static height/width). In this case, your "selected window" is empty size to start with (before layout to add controls), and the actions subwindow anchors to that empty size. If top and bottom anchor defined on a control, it doesn't have any inherent height of it's own, so doesn't expand the parent window.

A couple options:

* Implement the details area as two subwindows. One with summary (name, link, etc.); and another with details (actions, spells, etc.). When selecting an entry in the CT list, then use subwindow.setValue to change the detail windows. Of course, this means that those windows are rebuilt each time.

* Dynamically set the height of the actions control using setAnchoredHeight, based on parentcontrol.window.getSize(); and capture the onSizeChanged event for the top level CT to pass down to each list child window to resize that control. Then, the whole list knows which size it should be.

Regards,
JPG

I was wondering if there was a way to replace a window with values w/o rebuilding it programmatically (your suggestion?). I couldn't figure one out and was why I went with a windowlist and only one visible. When you say "subwindow.setValue()" do you mean walk through every control in the subwindow and set values or is there a undocumented way to set a database source for a subwindow.setValue()?

I tried the second suggestion by getting size of the windowlist's parent and when it changes and have had some success although I went a little different route this time (tried something similar yesterday). This time I adjusted the anchoredHeight/Width for a control, not trying to set the windowlist window (it wouldn't let me do that). Once I set the genericcontrol depth and then put the "bottom" for the subwindows it worked. I'm fine tuning it now and see how it works.

I do want to know if I can set a database for a subwindow tho... if I could simply update the node that the subwindow is pointing at and update that would be a lot easier than maintaining a windowlist. The windowlist mode does keep control creation between selections so it might be a little more responsive if the other method re-creates controls each time.

celestian
July 10th, 2019, 07:59
This is what I managed to get working so far. I am happy with it's functionality. Lot more work on other aspects but this was something that was bothering me and glad to check it off the list.

https://i.imgur.com/T5c1Xjy.gif

celestian
July 10th, 2019, 21:19
* Implement the details area as two subwindows. One with summary (name, link, etc.); and another with details (actions, spells, etc.). When selecting an entry in the CT list, then use subwindow.setValue to change the detail windows. Of course, this means that those windows are rebuilt each time.


I did want to follow up on this. I am not sure this is what you meant but it's what I was thinking you might have been meaning... After I got the other method working I wanted to try and see if I could get this working but... it seems the createControl() doesn't support it. I used this.



-- load the selected combatant control
-- if not nodeCT then unselect if it exists;
function onSelectCombatant(nodeCT)
Debug.console("cta.lua","onSelectCombatant","nodeCT",nodeCT);
if nodeCT then
local win = createControl("subwindow_cta_selected","selected",nodeCT);
if win then selectedControl = win; end;
else
-- didn't select, clearing
if selectedControl then
selectedControl.destroy();
end
selectedControl = nil;
end
end


And while it did create the template/control when I did a "getDatabaseNode()" within the created control all I got back was "combattracker" not "combattracker.list.id-XXXXXX" so it wouldn't build out the subwindow properly.

Fortunately the windowlist mode does work (local newWindow = selectedWindowlist.createWindow(nodeCT)) tho it's a bit kludgy perhaps with having to filter all the others but the selected one. It does mean that the controls don't have to be destroyed/rebuilt every selection (using windowlist).

Moon Wizard
July 11th, 2019, 00:18
subwindow.setValue(<class>, <recordpath>) was added in v3.3.7; though the docs have not been updated.

Don't use createControl. Just have 2 separate subwindows there, and use setValue(<class>, <recordpath>) to set to a specific value and setValue() to clear.

Regards,
JPG

celestian
July 11th, 2019, 06:57
subwindow.setValue(<class>, <recordpath>) was added in v3.3.7; though the docs have not been updated.

Don't use createControl. Just have 2 separate subwindows there, and use setValue(<class>, <recordpath>) to set to a specific value and setValue() to clear.

Regards,
JPG

Ah! ok good to know. I knew about the createControl() updates in that regard just not the subwindow updates. I'll tinker with it and see what I can come up with. Removing the windowlist will make things a little less cumbersome.

Thanks!

celestian
July 11th, 2019, 18:17
subwindow.setValue(<class>, <recordpath>) was added in v3.3.7; though the docs have not been updated.

Don't use createControl. Just have 2 separate subwindows there, and use setValue(<class>, <recordpath>) to set to a specific value and setValue() to clear.

Regards,
JPG

Got it working, this was perfect. I've got a little bit more tweaking to go but have one final issue I'll have to tinker with to try and resolve.

When scrolling using the bar I noticed it wouldn't go to the bottom unless I added a "bottom" offset equal to the size of the header that doesn't scroll. The upside is that worked but if you use the mouse wheel to scroll down and "go past" the bottom of the scroll section is slides through that "buffer".

The way I got around this with the windowlist was to use "noscroll" which didn't allow scrolling except for the scroll bar section. I tried this on the subwindow and doesn't seem to have an effect. Is it possible there is a way to lock the non-scroll bar section to not scroll like the windowlist option?

Here is example. In the beginning I click and use the scrollbar to move the window. At the end I use mouse wheel to scroll down.

https://i.imgur.com/bKbbyp1.gif

celestian
July 11th, 2019, 18:49
So, ignore the scroll issue mentioned above, all sorted. Turns out the previous options I needed (maintaining the contentframe bottom anchor) was unnecessary for a non-windowlist.

Everything seems to be working!

I'll clean up the code and post the important bits incase anyone is interested after a bit.

Moon Wizard
July 11th, 2019, 22:31
And celestian solved it before I made it back from lunch. ;)

JPG

Bidmaron
July 12th, 2019, 22:06
Congrats, Celestian. Will probably come in handy

celestian
July 13th, 2019, 04:36
So here is the parts of the code that matter here.

This is the xml for the window. I tried not to template anything so folks could more easily see what was going on but there are bits like tabs/etc that are but those are "standard" of sorts.



<!-- main selected window, actions/saves/etc, right side with all the fun stuff -->
<windowclass name="cta_main_selected_host">
<!-- <frame name="field-red" /> -->

<script file="cta/scripts/cta_selected.lua" />
<sheetdata>

<subwindow name="header">
<anchored>
<top offset="35" />
<left offset="13" />
<right offset="-10" />
</anchored>
<activate />
<fastinit />
<noscroll />
<class>selected_entry_header</class>
<frame name="headergray" offset="5,5,5,5" />
</subwindow>

<genericcontrol name="contentframe">
<anchored>
<top parent="header" anchor="bottom" offset="0" />
<left offset="0" />
<bottom parent="" anchor="bottom" offset="0" />
</anchored>
<disabled />
<!-- <frame name="groupbox" offset="0,0,0,0" /> -->
</genericcontrol>

<genericcontrol name="contentanchor">
<anchored height="0">
<top parent="header" anchor="bottom" offset="0" relation="relative"/>
<left parent="" anchor="left" offset="0" />
<right parent="" anchor="right" offset="0" />
</anchored>
<disabled />
<!-- <frame name="field-yellow" /> -->
</genericcontrol>

<subwindow name="actions">
<!-- <frame name="field-green" /> -->
<anchored to="contentanchor" >
<top anchor="top" offset="5" />
<left parent="" anchor="left" offset="5"/>
<right parent="" anchor="right" offset="-20"/>
<bottom parent="contentframe" anchor="bottom" offset="-5"/>
</anchored>
<activate />
<fastinit />
<class>cta_actions_host</class>
</subwindow>
<cta_selected_scrollbar>
<anchored to="actions" />
<target>actions</target>
</cta_selected_scrollbar>


<subwindow name="effects">
<!-- <frame name="field-green" /> -->
<anchored to="contentanchor" >
<top anchor="top" offset="5" />
<left parent="" anchor="left" offset="5"/>
<right parent="" anchor="right" offset="-20"/>
<bottom parent="contentframe" anchor="bottom" offset="-5"/>
</anchored>
<activate />
<fastinit />
<class>cta_effects_host</class>
</subwindow>
<cta_selected_scrollbar>
<anchored to="effects" />
<target>effects</target>
</cta_selected_scrollbar>

<subwindow name="skills">
<!-- <frame name="field-green" /> -->
<anchored to="contentanchor" >
<top anchor="top" offset="5" />
<left parent="" anchor="left" offset="5"/>
<right parent="" anchor="right" offset="-20"/>
<bottom parent="contentframe" anchor="bottom" offset="-5"/>
</anchored>
<activate />
<fastinit />
<class>cta_skills_host</class>
</subwindow>
<cta_selected_scrollbar>
<anchored to="skills" />
<target>skills</target>
</cta_selected_scrollbar>

<subwindow name="stats">
<!-- <frame name="field-blue" /> -->
<anchored to="contentanchor" >
<top anchor="top" offset="5" />
<left parent="" anchor="left" offset="5"/>
<right parent="" anchor="right" offset="-20"/>
<bottom parent="contentframe" anchor="bottom" offset="-5"/>
</anchored>
<class>cta_stats_host</class>
<activate />
<fastinit />
</subwindow>
<cta_selected_scrollbar>
<anchored to="stats" />
<target>stats</target>
</cta_selected_scrollbar>

<tabs_cta name="tabs_cta">
<tab>
<icon>htab_actions_icon</icon>
<subwindow>actions</subwindow>
</tab>
<tab>
<icon>htab_effects_icon</icon>
<subwindow>effects</subwindow>
</tab>
<tab>
<icon>htab_stats_icon</icon>
<subwindow>stats</subwindow>
</tab>
<tab>
<icon>htab_skills_icon</icon>
<subwindow>skills</subwindow>
</tab>
</tabs_cta>

</sheetdata>
</windowclass>



Once I stopped using the windowlist it made things a lot easier. I could set the contentframe to the bottom of parent="" and that solved all the issues. When it was in a windowlist I had to watch for window resizing and manually set it.

I did also have to create a horizontal tab system. I took the existing vertical one and tweaked it to support horizontal. If/when I get the chance I'm going to see if I can merge them and you just set a flag within the xml to determine which one to use.

Moon Wizard
July 13th, 2019, 04:55
Let me know when you do this, and I can merge into CoreRPG.

Regards,
JPG