PDA

View Full Version : getSelection/setSelection in FormattedTextField?



Nose66
July 23rd, 2019, 00:51
In any textbasecontrol, you can get the selection location and set it, using getSelectionPosition() and setSelectionPosition() https://www.fantasygrounds.com/refdoc/textbasecontrol.xcp

But formmatedtextfields don't seem to respond to those messages, and the documentation doesn't offer any solution. https://www.fantasygrounds.com/refdoc/formattedtextcontrol.xcp

Is there no way to programmatically read and set the position in a formatted text field?

Bidmaron
July 23rd, 2019, 02:45
It has been on the wish list a long time but there is no capability to manipulate the selection for formattedtext.

Nose66
July 23rd, 2019, 06:43
Well fudge.... fudge, fudge, fudge.

I have implemented embedded dice rolling for StringTextFields, useful for the GURPS Ruleset. For example, certain Disadvantages have a "Control Roll". A number that you must roll under or that disadvantage triggers, for example:
28031

And when you hover, it will highlight the "actionable" section, and allow you to double click, which will perform the roll:
28032

And I had planned on adding it to the FormattedTextField, since this contains the descriptions. Certain magic systems in GURPS don't use the standard Spell data structure, and instead implement the magic as a "power" (an advantage with modifiers). In most cases, this is very free form, and there is no standard way to determine what must be rolled. If I could port the StringTextFields code to the FormatedTextField, the author of the "power", could embed the various rolls that are required in the description.

What is the likelihood that enhancements to FormatedTextField would happen? (I am a Unity backer... in case that adds any clout :p )

Moon Wizard
July 23rd, 2019, 07:51
There are no plans at this point to add additional APIs to any controls other than the image controls for initial FGU development. There's already a ton of work for our small team with all the other library replacements we did as part of Unity, as well as completely rewritten image controls.

Regards,
JPG

Nose66
July 23rd, 2019, 16:12
As a long time developer (since '85) and the sole developer on a mission critical application (that has a 4-9s uptime requirement), I COMPLETELY understand about "a ton of work". And, I understand the complexity of dealing with a selection point, vs a selection index, it is not an "easy" fix. It just would have looked cool ;)

I've already dreamed up a "hack-around". I am going to scan the text and add buttons to the bottom of the window for each section of text that would have been highlight-able. It won't look as cool, but it will get the job done, which is to make the players lives easier.

Moon Wizard
July 23rd, 2019, 19:02
Good idea. Might be an interesting idea for me to look at eventually; especially if they can be manually specified/overwritten to deal with natural language not easily parsed.

Regards,
JPG

Nose66
July 23rd, 2019, 19:41
Ok, here is my next problem. I am a pretty good backend developer... but GUIs are not my thing.

I want to add buttons to the bottom of the "charnote" window class. As you can see from the picture, it creates 4 buttons ([ST6], [DX-2], [CR:12] & [2d-1]), all on top of each other ;) . The text [Attractive, +4] does not match any of the "actionable" patterns, so it isn't included.

28037


<windowclass name="charnote">
<frame>storybox</frame>
<placement>
<size width="300" height="300" />
</placement>
<sizelimits>
<minimum width="300" height="300" />
<dynamic />
</sizelimits>
<minimize>minimized_note</minimize>
<playercontrol />
<nodelete />
<tooltip field="name" />
<sheetdata>

<link_story>
<class>charnote</class>
</link_story>

<genericcontrol name="rightanchor">
<anchored height="0" width="0">
<top offset="28" />
<right offset="-14" />
</anchored>
</genericcontrol>

<stringfield name="name">
<anchored to="rightanchor" height="24">
<top offset="-4" />
<left parent="" offset="45" />
<right anchor="left" relation="relative" offset="-5" />
</anchored>
<font>reference-h</font>
<nodrag />
</stringfield>

<ft_record name="text">
<bounds>25,85,-25,-15</bounds>
<multilinespacing>16</multilinespacing>
<font>reference-r</font>
<selectioncolor>#FFD296</selectioncolor>
<script file="campaign/scripts/noteshovercheck.lua" />
</ft_record>

<scrollbar>
<anchored to="text" />
<target>text</target>
</scrollbar>

<resize_storybox />
<close_storybox />
</sheetdata>
</windowclass>

So what is the best way to programmatically add buttons? I have been trying a script (the poorly named "noteshovercheck.lua") in the "ft_record" that iterates over the text, determines which things should be "actionable" and stores them in "aAbilities", and tries to create buttons:


function buildButtons()
if #aAbilities == 0 then return; end
local parent = "text";
for i, a in pairs(aAbilities) do
local bn = "b"..i;
Debug.console("Button", bn, a.orig);

buttons[i] = window.createControl("notes_actions", bn);
buttons[i].setAnchor("top", parent, "bottom");
parent = bn;
buttons[i].setText(a.orig);
end
end

Where "notes_actions" is:


<template name="notes_actions">
<buttoncontrol>
<anchored to="text" position="insidebottomleft">
<right parent="text" anchor="right" relation="relative" />
</anchored>
</buttoncontrol>
</template>


It reports:

Runtime Notice: s'Button' | s'b1' | s'ST6'
Runtime Notice: s'Button' | s'b2' | s'DX-2'
Runtime Notice: s'Button' | s'b3' | s'CR:12'
Runtime Notice: s'Button' | s'b4' | s'2d-1'

But that just smashes all of the buttons on top of each other. I assume there is a way to get one button to build below the other, but I couldn't figure it out (and I resorted to trying to use each successive button as the anchor for the next... which failed, of course).

So any help would be greatly appreciated. I even thought of creating 10 or so invisible buttons in the XML, and just making visible the ones I use, but that is a last (hacky) resort.

Once I get them laid out, I can hook them all up.... it is just that the layout stuff is hard (and my search-fu not so good, I guess).

Trenloe
July 23rd, 2019, 20:20
In the .setAnchor command you're no longer using the "relative" relation, so each new control will just use basic anchoring - they won't be able to align themselves relative to each other.

Nose66
July 23rd, 2019, 21:27
Unfortunately, nothing changed. I tried:


function buildButtons()
if #aAbilities == 0 then return; end
local parent = "text";
for i, a in pairs(aAbilities) do
local bn = "b"..i;
Debug.console("Button", bn, a.orig);

buttons[i] = window.createControl("notes_actions", bn);
buttons[i].setAnchor("top", parent, "bottom", "relative");
parent = bn;
buttons[i].setText(a.orig);
end
end

And then I tried basing it all from "text" (and not changing the parent, hoping the relative keyword would do some magic):


function buildButtons()
if #aAbilities == 0 then return; end
local parent = "text";
for i, a in pairs(aAbilities) do
local bn = "b"..i;
Debug.console("Button", bn, a.orig);

buttons[i] = window.createControl("notes_actions", bn);
buttons[i].setAnchor("top", parent, "bottom", "relative");
--parent = bn;
buttons[i].setText(a.orig);
end
end

Same results. The button text appears, but it is all overlaied on top of each other.

Trenloe
July 23rd, 2019, 21:32
You need to check on exactly how relative anchoring works. Some info in the section here: https://www.fantasygrounds.com/wiki/index.php/Developer_Guide_-_Rulesets_-_Interface#Anchoring

To have the buttons align next to each other horizontally you'll need to use relative anchoring on the left/right side of the control, to the side of an anchor on the edge of the window. Then you line the controls out from that anchor, with the side edge of each control being relative to the side anchor.

It's a really powerful piece of functionality that allows controls to dynamically align based off other controls being added (or removed).

celestian
July 23rd, 2019, 21:43
You need to check on exactly how relative anchoring works. Some info in the section here: https://www.fantasygrounds.com/wiki/index.php/Developer_Guide_-_Rulesets_-_Interface#Anchoring

To have the buttons align next to each other horizontally you'll need to use relative anchoring on the left/right side of the control, to the side of an anchor on the edge of the window. Then you line the controls out from that anchor, with the side edge of each control being relative to the side anchor.

It's a really powerful piece of functionality that allows controls to dynamically align based off other controls being added (or removed).

From the sounds of it the buttons are appearing over the top of each other all stacked as one.

Looking at the code I'd expect it to build them one under the other like a column with each button visible.

Unless there is something odd with the anchor "text" I'm not seeing... I dunno why it doesn't work.

Nose66
July 26th, 2019, 06:11
Ok, still not working well. I guess I just need some basic layout help.

Given that I have a textfield named "text" that is correctly positioned in the window (it is inset from the borders and centered), what do I need to do to layout 3 buttons below the textfield that would look something like this:


+---------------------------------+
! !
! Textfield "text" !
+---------------------------------+
+---------+ +---------+ +---------+
!Button 1 ! !Button 2 ! !Button 3 !
+---------+ +---------+ +---------+

I have tried all kinds of combinations of anchors, and can't seem to get it right.

What would I need to do If I wanted them to be stacked vertically, instead of horizontally?


+---------------------------------+
! !
! Textfield "text" !
+---------------------------------+
+---------------------------------+
! Button 1 !
+---------------------------------+
! Button 2 !
+---------------------------------+
! Button 3 !
+---------------------------------+

celestian
July 26th, 2019, 06:43
If you want to get them side by side try something like...

buttons[i].setAnchor("top", "text", "bottom", "absolute",5);
buttons[i].setAnchor("left", "text", "right", "relative",-SomeValueBasedYoullhavetoFigureout);

"SomeValueBasedYoullhavetoFigureout" = You'll have to just figure out what the offset will need to be to actually be on the bottom left. If you try and use relative on the left/left alignment it wont do what you want.

That "should" place them under the text field left to right as your first layout is going for.

buttons[i].setAnchor("top", "text", "bottom", "relative",5);
buttons[i].setAnchor("left", "text", "left", "absolute");

That should stack them one on top of the other aligned to the left corner of the "Text" field.

Moon Wizard
July 27th, 2019, 01:35
When I do 3 buttons like that, I usually anchor bottom and left for the 1st button, bottom and right for the 3rd button, and bottom and center for the 2nd button.

In that way, the buttons will be positioned correctly, even if I change the window size later.

Regards,
JPG

damned
July 27th, 2019, 01:40
I think in the OPs use case he has a variable number of buttons so needs to anchor the first and each following one would be relative?

Nose66
August 22nd, 2019, 03:33
Since I was unable to insert my buttons into the view correctly, I did the next best thing... when the user hovers over the middle of the Notes view, a series of buttons pop up indicating the various rolls that can be made. The buttons disappear if the user moves the mouse away, or click in the Notes view to edit.

My only problem now is that I would like the buttons to be variable width, based on the text in the button field, and at the moment, I am forced to define a left and a right anchor. As you can see from this:

28593

The last button's label "Click to roll [Sex Appeal+1]" is too large for the button.

Is there a way to define a left/right anchor that is "in the middle", and have the button grow horizontally to fit it's label?

Trenloe
August 22nd, 2019, 03:54
Is there a way to define a left/right anchor that is "in the middle", and have the button grow horizontally to fit it's label?
Not sure about buttons. But for string controls, if the left anchor is defined, but the right anchor isn't, then the string field will expand to fit the text. I don't know if such an approach would work with buttons. You may need to assign a minimum width in the sizelimits parameter. Here's what I used for a stringcontrol that has a minimum width, but will resize horizontally beyond that based on the contents of the control:


<anchored to="label_price" position="righthigh" offset="5,2">
<sizelimits>
<minimum width="30" />
</sizelimits>
</anchored>

Nose66
August 22nd, 2019, 05:05
Not sure about buttons

Yeah, it doesn't seem to resize the buttons based on their text. At least not the way I am building the buttons:


buttons[i] = window.createControl("notes_actions", bn);
buttons[i].setText("Click to roll ["..a.orig.."]", "Rolling ["..a.orig.."]!");
buttons[i].setFrame("buttonup");
buttons[i].setVisible(false);
buttons[i].setAnchor("left", parent, "left", "absolute", q1x);
buttons[i].setAnchor("top", parent, "top", "absolute", top);
buttons[i].setAnchor("bottom", parent, "top", "absolute", top + buttonH);



<template name="notes_actions">
<buttoncontrol>
<anchored to="text" position="insideleft" >
<sizelimits>
<minimum width="30" />
</sizelimits>
</anchored>
<script>
function onButtonPress()
window.text.buttonPressed(self);
end
function onClickDown()
setFrame("buttondown");
end
function onClickRelease()
setFrame("buttonup");
end
</script>
</buttoncontrol>
</template>

Also, is there a better way to show a button press? Sometimes it misses a click down or click release event and then the frame isn't correct.

Moon Wizard
August 22nd, 2019, 17:52
You need to return true for all of those event functions to indicate to the client code that you want to capture those events, and not use the default processing. Also, you might consider only using the onButtonPress event; and setting the frames using "state" tags. You can also set tags in the template to mirror starting state (i.e. "invisible" tag, instead of calling setVisible(false)).
https://www.fantasygrounds.com/refdoc/buttoncontrol.xcp

For layout, if left or right anchor is defined and the other horizontal anchor is not defined and the width is not defined, then the control should resize to fit the text inside (plus any frame offset).

Regards,
JPG

Nose66
August 22nd, 2019, 19:33
and setting the frames using "state" tags.

That sounds promising... how do you do that? Looking at the setStateFrame API it reads:
A string identifying the state for which the frame is to be set. This value should be one of "hover", "drophilight", "drophover", or "keyedit". And none of those states seemed to be what I am looking for.

I was looking for was a way to show the button as being pressed down, and then pop back up. Unfortunately, onButtonPress won't allow me to show when the button is pressed down, since it only fires when the button is released.

Moon Wizard
August 22nd, 2019, 19:47
In the notes_actions template, you could add these tags:
<state frame="buttonup" />
<state frame="buttondown" />

Then, use the setStateText/setStateFrame/etc. APIs, instead of the setText/setFrame/etc. APIs. When you use the latter, it resets the button states.

Regards,
JPG

Nose66
August 27th, 2019, 22:55
I didn't want to bother you, but I have been trying and trying... and I still can't get it to work. :confused:

When I remove all of my coding, and just use:

<template name="notes_actions">
<buttoncontrol>
<anchored to="text" position="insideleft" />
<state frame="buttonup" />
<state frame="buttondown" />
<invisible />
<script>
function onButtonPress()
window.text.buttonPressed(self);
end
</script>
</buttoncontrol>
</template>


The button doesn't show as depressed when I click on it.

When I add code:

buttons[i].setStateText(0, "Click me!, "I'm being clicked!");


The text will change as I click on the button, but the frame does not. Instead, when I am done with the click, the button switches to the second "state", and now it shows the depressed (buttondown) frame. So now the button behaves (visually) as some kind of toggle button. And that isn't what I wanted.

I wanted the button to visually work like a standard push button. It would show as depressed when the user clicks on it, and it show as "up" when the user lets go of the click. I had this (sort of) working by changing the frame using the onClickDown/onClickRelease methods, but if the user moved the mouse away while holding down the button, it would get out of sync. I can solve this by watching the onHover event, but dang... I was hoping that I could just build some standard push buttons (and not have to reinvent the wheel, so to speak :) )

Moon Wizard
August 28th, 2019, 04:56
Where's the example of using the template?

You need the whole chain from base control through implementation in the window class, in order to know what the final XML looks like and be able to see any problems. (i.e. show the part where "notes_actions" used.)

Regards,
JPG