GUI Scripting: GUI:: Parameters: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
Geep (talk | contribs)
Add "Gui_Parm" material
Geep (talk | contribs)
→‎Bound In a Property List: fix & expand gui::BriefingVideoMaterial info
 
(17 intermediate revisions by the same user not shown)
Line 2: Line 2:


==What and Why of GUI:: Parameters==
==What and Why of GUI:: Parameters==
"GUI:: Parameters" are different from standard GUI properties and GUI user variables. But just like user variables, you invent their names. They can take on float values (including representing boolean and integer values) or string values, but not vector values such as color.
"GUI:: Parameters" are different from standard GUI properties and GUI user variables. But just like user variables, you invent their names. They can easily take on float values (including representing boolean and integer values) or string values. Vector values such as color can handled not as a whole, but by passing any given component as a float.


If you have an entity with both a .gui and .script, a GUI:: Parameter provides a channel to pass a value in either direction. This will be potentially "instantaneous", in that values could be re-evaluated on every frame. In the GUI file, the GUI:: Parameter is always prefixed with "gui::". That prefix is NOT used in the .script file.
If you have an entity with both a .gui and .script, a GUI:: Parameter provides a channel to pass a value in either direction. This will be potentially "instantaneous", in that values could be re-evaluated on every frame. In the GUI file, the GUI:: Parameter is always prefixed with "gui::". That prefix is NOT used in the .script file.
Besides these custom GUI:: Parameters, there are also predefined ones associated with certain system CVars. These are global, in the sense that they can be accessed in your .gui without mention in your .script. They are not covered here; see [[GUI Scripting: Getting System CVars]].


==The Magic Prefix "Gui_Parm"==
==The Magic Prefix "Gui_Parm"==
Line 12: Line 14:
then when the entity and its GUI are spawned, gui:: parameters with the gui_parm names will be created and initialized from the spawnargs values, and can be used immediately in the GUI. The usual naming convention is "gui_parm" alone or followed by a digit, but any suffix string will do.
then when the entity and its GUI are spawned, gui:: parameters with the gui_parm names will be created and initialized from the spawnargs values, and can be used immediately in the GUI. The usual naming convention is "gui_parm" alone or followed by a digit, but any suffix string will do.


This is most useful for entities that don't need a .script file. If the overlay is created (or replaced) in a script, then spawnargs will NOT be consulted for gui:: parameter creation and initialization. Also, if an updatable spawnarg value is so updated by a script, that change is not automatically propagated to the gui:: parameter. However, in both those cases, script code can be written as needed to get the spawnarg value and send it to the gui:: parameter, as indicated next.
If a gui_parm has an i18n string value (i.e., a #str value), the corresponding gui:: parameter is automatically initialized with the correct language string.
 
The magic prefix naming is particularly useful for entities that don't need a .script file, as shown next.
 
===Usage with Standard Assets that Need No .Script File===
Decals for sign text with various fonts are provided as prefabs (in \tdm_prefabs01.pk4\prefabs\readables\sign_text_decals\). They all use "gui_parm1" with default hint "put text here". For example, for the regular size of Andrew font, sign_text_andrew.pfb (reformatted slightly here) is simply:
Version 2
// entity 0
{
    "classname" "func_static"
    "name" "sign_text"
    "gui" "guis/readables/sign_text_decals/sign_text_andrew.gui"
    "gui_parm1" "put text here"
    "model" "sign_text"
    "origin" "0 0 -320"
    // primitive 0
    {
        patchDef3  {
            "textures/darkmod/decals/signs/decal_gui"
            ... // not shown: coordinates of patch
        }
    }
}
The referenced GUI, "sign_text_andrew.gui", is:
//Suitable for signposts, graffiti text, etc.
windowDef Desktop {
    rect 0, 0, 640, 480
    backcolor 0, 0, 0, 0
    windowDef SignText {
      rect 0, 0, 640,480
      backcolor 0, 0, 0, 0
      text "gui::gui_parm1"
      font "fonts/andrew_script"
      textscale 2.5
      forecolor 0, 0, 0, 0.66
      visible 1
    }
}
===Cautions when a .Script File is Involved===
Be aware: if a GUI is created (or replaced) in a script (which is the norm for overlays), then during that process NO spawnargs will be consulted for gui:: parameter creation and initialization. Also, if an "gui_parm..." spawnarg value is updated by a script, that change is not automatically propagated to the gui:: parameter. However, in both those cases, script code can be written as needed to get the spawnarg value and send it to the gui:: parameter, as indicated next.


==Important Use: Spawnarg -> .Script -> .Gui==
==Important Use: Any Spawnarg -> .Script -> .Gui==
Except for the magic prefix initialization, a .gui attached to an entity cannot read or access the entity’s spawnargs directly. Instead, a .script function acts as the intermediary. The usual dance is:
Except for the magic prefix initialization, a .gui attached to an entity cannot read or access the entity's spawnargs directly. Instead, a .script function acts as the intermediary. The usual dance is:
* The mapper sets a key/value spawnarg on the entity (with key and default value often predefined in an entityDef).
* The mapper sets a key/value spawnarg on the entity (with key and default value often predefined in an entityDef).
* An attached script (say, specified in a "scriptobject" spawnarg) fetches the spawnarg value, with:
* An attached script (say, specified in a "scriptobject" spawnarg) fetches the spawnarg value, with:
Line 23: Line 65:
* The script can then pass that on the GUI in a desired form, as discussed next.
* The script can then pass that on the GUI in a desired form, as discussed next.


As mentioned above, gui:: parameters do not involve or affect entity spawnargs (other than magic prefix initialization). Internally, gui:: parameters are stored in separate "dictionary" data structures. You create them by referencing them in your .gui and .script.
As mentioned above, gui:: parameters do not involve or affect entity spawnargs (other than magic prefix initialization). Internally, a GUI's gui:: parameters are stored in a separate "dictionary" data structure. You create gui:: parameters in the dictionary by referencing them in your .gui and .script. If a GUI can access multiple script functions (e.g., both a frob_action_script and script object functions) , then each function can potentially access the gui:: parameters. Just the correct handle number and use of the appropriate names/types is needed.


==In a GUI File – Syntax and Use==
==In a GUI File – Syntax and Use==
Line 29: Line 71:


===Bound In a Property List===
===Bound In a Property List===
A gui:: parameter can be "bound" to a standard float property (not a user variable or vector). For example, in the property list of a "windowDef SignText":
A gui:: parameter can be "bound" to a standard float or string property (not a user variable or vector). For example, in the property list of a "windowDef SignText":
  text "gui::gui_parm1"
  text "gui::gui_parm1"


Another string example, from the mainmenu_briefing.gui:
CAUTION: No example was found of a gui_parm or more broadly any gui:: parameter being bound to a non-register property... so possibly that's not legal. [Someone please test!]
 
Another string example, from the mainmenu_briefing_video.gui:
  background "gui::BriefingVideoMaterial"
  background "gui::BriefingVideoMaterial"


For a more dynamic use, see [[GUI Scripting: On Entity’s Surface]], where it is important that the boolean value of the bound property...
The value here is a path to a custom video material shader. It is set at runtime by the engine, based on information the FM author provided in mainmenu_custom_defs.gui as, e.g.:
#define MM_BRIEFING_VIDEO_MATERIAL_1 "video/tdm_briefing_video"
(In older FMs, the video was chopped into parts, in which case the engine updates the value just-in-time. See comments in mainmenu_custom_defs.gui for details.)
 
For a more dynamic use, see [[GUI Scripting: On Entity's Surface]], where it is important that the boolean value of the bound property...
  visible "gui::is_visible"
  visible "gui::is_visible"


... is automatically re-evaluated every frame.
... is automatically re-evaluated every frame. Similarly, one could have an expression with changing value:
  visible 1-"gui::is_visible"
 
But in any case, be aware that automatic re-evaluation of a particular property (like "visible" in these examples) can become deactivated/disabled...
* prior to TDM 2.11, if you include ANY reference to that property in an event handler body. Deactivation happens at startup [or perhaps right after property's first initialization].
* In TDM 2.11, if you manually assign to that property using the "set" command. [Probably doesn't apply to "transition"]. Deactivation happens when "set" is executed.
Careful programming can avoid unwanted deactivation.


===In Event Block’s Set Command===
===In Event Block’s Set Command===
Usages are either sources or sinks for "set" commands (involving floats, not vectors).
Usages are either sources or sinks for "set" commands (involving strings or floats, not vectors).


Consider this readable example. In one of the onTime  handlers, strings are copied from two gui:: parameters to the text property of the two other windowDefs named "title" and "body":
Consider some scripting from readable entities. As source examples, in one of the onTime  handlers, strings are copied from two gui:: parameters to the text property of the two other windowDefs named "title" and "body":
  set "title::text" "$gui::title";
  set "title::text" "$gui::title";
  set "body::text" "$gui::body";
  set "body::text" "$gui::body";


As usual with "set", a "$" on the source indicates that the value is to be copied, not a literal string such as "gui::title".
As usual with "set", a "$" on the source indicates that the value is to be copied, not a literal string such as "gui::title".
See the example at this article’s end for more.
 
Here's a sink example, where information is being passed from the .gui to the .script file:
set "gui::InteractionState" "3";
 
See also the example at this article’s end for more.


===In Event Block’s "If" Statement===
===In Event Block’s "If" Statement===
Line 60: Line 118:


==In a SCRIPT File – Syntax, and Available Functions for GUI:: Parameters==
==In a SCRIPT File – Syntax, and Available Functions for GUI:: Parameters==
In the body of a SCRIPT function, use a double-quoted parameter name that matches that in the GUI file, but without the "gui::" prefix. Pass that name in a SetGui… or GetGui… function call whose type (bool, int, string) matches the usage in the GUI file. You must specify a handle with these functions, as discussed in [[GUI Scripting: Handles]].
In the body of a SCRIPT function, use a double-quoted parameter name that matches that in the GUI file, but without the "gui::" prefix. Pass that name in a SetGui… or GetGui… function call whose type - float, int (also used for bool), or string - matches the usage in the GUI file. You must specify a handle with these functions, as discussed in [[GUI Scripting: Handles]].


===GetGui… Functions===
===GetGui… Functions===
Line 82: Line 140:
  $player1.setGuiStringFromKey(myhandle, "myGuiParamName", self, "mySpawnArgName");
  $player1.setGuiStringFromKey(myhandle, "myGuiParamName", self, "mySpawnArgName");


==An Example: Number Wheel==
==For More==
TDM number wheels are used for combination locks. A typical lock has 3 wheels, each with edge digits 0 to 9. The gamer frobs a particular wheel to indicate interest in it, then uses mouse actions or keystrokes to rotate it.
* [[GUI Scripting: Number Wheel Example]] shows how a GUI can detect a user action, then originate a change to a gui:: parameter in order to pass it on to a script object for processing.
 
* [[GUI Scripting: Flashbomb Example]] also is relevant. In particular, it shows how to use a gui:: parameter to control color transitions, even though the GUI language parser will not accept a gui:: parameter embedded into a color vector.
Turning to the implementation, in tdm_numberwheel.script, a "numberwheel" script object is defined. Its main function body is called (via Stim/Response) when frobbed. In the function body, a custom overlay is first created (about which see [[GUI Scripting: Handles]]). Then the code enters an "eachFrame" loop to do processing, where it remains until the gamer frobs something else.
 
The overlay (instantiated from "guis/numberwheel_handler.gui" and shown next) catches the events raised by the standard player actions to go to previous or next thing (i.e., weapon, inventory item, or inventory group). It then uses those events to (also) manipulate the number wheel. Note that this overlay has no visual aspect:


windowDef Desktop {
{{GUI}}
  rect      0, 0, 640, 480
  nocursor 1
  onNamedEvent prevWeapon {
    set "gui::nextPos" "1";
  }
  onNamedEvent nextWeapon {
    set "gui::prevPos" "1";
  }
  onNamedEvent inventoryPrevItem {
    set "gui::nextPos" "1";
  }
  onNamedEvent inventoryNextItem {
    set "gui::prevPos" "1";
  }
  onNamedEvent inventoryPrevGroup {
    set "gui::nextPos" "1";
  }
  onNamedEvent inventoryNextGroup {
    set "gui::prevPos" "1";
  }
}
 
Clearly, "prevPos" and "nextPos" are booleans, set to 1 when the user makes a request to go to the previous or next position on the number wheel. The .script then manages what digit is shown on the wheel. For gui:: parameters, the salient portions in the script are:
 
''Did we get a request?''
 
float prevPos = $player1.getGuiFloat(overlayHandle,"prevPos");
float nextPos = $player1.getGuiFloat(overlayHandle,"nextPos");
 
''If so, process it and rotate the wheel (code not shown), then reset and wait for next request:''
 
$player1.setGuiFloat(overlayHandle,"prevPos",0);
$player1.setGuiFloat(overlayHandle,"nextPos",0);
 
(There is a separate script that combines the values of each number wheel to determine if the lock should open. This is beyond the scope here.)
==For More==
[[GUI Scripting: Flashbomb Example]] also is relevant. In particular, it shows how to use a gui:: parameter to control color transitions, even though the GUI language parser will not accept a gui:: parameter embedded into a color vector.

Latest revision as of 16:03, 13 November 2023

This page is part of a series. See GUI Scripting Language for overview.

What and Why of GUI:: Parameters

"GUI:: Parameters" are different from standard GUI properties and GUI user variables. But just like user variables, you invent their names. They can easily take on float values (including representing boolean and integer values) or string values. Vector values such as color can handled not as a whole, but by passing any given component as a float.

If you have an entity with both a .gui and .script, a GUI:: Parameter provides a channel to pass a value in either direction. This will be potentially "instantaneous", in that values could be re-evaluated on every frame. In the GUI file, the GUI:: Parameter is always prefixed with "gui::". That prefix is NOT used in the .script file.

Besides these custom GUI:: Parameters, there are also predefined ones associated with certain system CVars. These are global, in the sense that they can be accessed in your .gui without mention in your .script. They are not covered here; see GUI Scripting: Getting System CVars.

The Magic Prefix "Gui_Parm"

If you have an entity with:

  • a "gui" spawnarg of valid value, and
  • one or more spawnargs with name prefix "gui_parm".

then when the entity and its GUI are spawned, gui:: parameters with the gui_parm names will be created and initialized from the spawnargs values, and can be used immediately in the GUI. The usual naming convention is "gui_parm" alone or followed by a digit, but any suffix string will do.

If a gui_parm has an i18n string value (i.e., a #str value), the corresponding gui:: parameter is automatically initialized with the correct language string.

The magic prefix naming is particularly useful for entities that don't need a .script file, as shown next.

Usage with Standard Assets that Need No .Script File

Decals for sign text with various fonts are provided as prefabs (in \tdm_prefabs01.pk4\prefabs\readables\sign_text_decals\). They all use "gui_parm1" with default hint "put text here". For example, for the regular size of Andrew font, sign_text_andrew.pfb (reformatted slightly here) is simply:

Version 2
// entity 0
{
   "classname" "func_static"
   "name" "sign_text"
   "gui" "guis/readables/sign_text_decals/sign_text_andrew.gui"
   "gui_parm1" "put text here"
   "model" "sign_text"
   "origin" "0 0 -320"
   // primitive 0
   {
       patchDef3  {
           "textures/darkmod/decals/signs/decal_gui"
           ... // not shown: coordinates of patch
       }
   }
}

The referenced GUI, "sign_text_andrew.gui", is:

//Suitable for signposts, graffiti text, etc.
windowDef Desktop {
   rect 0, 0, 640, 480
   backcolor 0, 0, 0, 0

   windowDef SignText {
      rect 0, 0, 640,480
      backcolor 0, 0, 0, 0
      text "gui::gui_parm1"
      font "fonts/andrew_script"
      textscale 2.5
      forecolor 0, 0, 0, 0.66
      visible 1
   }
}

Cautions when a .Script File is Involved

Be aware: if a GUI is created (or replaced) in a script (which is the norm for overlays), then during that process NO spawnargs will be consulted for gui:: parameter creation and initialization. Also, if an "gui_parm..." spawnarg value is updated by a script, that change is not automatically propagated to the gui:: parameter. However, in both those cases, script code can be written as needed to get the spawnarg value and send it to the gui:: parameter, as indicated next.

Important Use: Any Spawnarg -> .Script -> .Gui

Except for the magic prefix initialization, a .gui attached to an entity cannot read or access the entity's spawnargs directly. Instead, a .script function acts as the intermediary. The usual dance is:

  • The mapper sets a key/value spawnarg on the entity (with key and default value often predefined in an entityDef).
  • An attached script (say, specified in a "scriptobject" spawnarg) fetches the spawnarg value, with:
    • GetKey(spawnarg_name); // gets value in string form
    • GetIntKey(spawnarg_name);
    • GetFloatKey(spawnarg_name);
  • The script can then pass that on the GUI in a desired form, as discussed next.

As mentioned above, gui:: parameters do not involve or affect entity spawnargs (other than magic prefix initialization). Internally, a GUI's gui:: parameters are stored in a separate "dictionary" data structure. You create gui:: parameters in the dictionary by referencing them in your .gui and .script. If a GUI can access multiple script functions (e.g., both a frob_action_script and script object functions) , then each function can potentially access the gui:: parameters. Just the correct handle number and use of the appropriate names/types is needed.

In a GUI File – Syntax and Use

In the GUI file, use a "gui::" prefix, followed by a name, all in double quotes. A gui:: parameter can appear multiple times within a file and at any level of "guiDef" nesting.

Bound In a Property List

A gui:: parameter can be "bound" to a standard float or string property (not a user variable or vector). For example, in the property list of a "windowDef SignText":

text	"gui::gui_parm1"

CAUTION: No example was found of a gui_parm or more broadly any gui:: parameter being bound to a non-register property... so possibly that's not legal. [Someone please test!]

Another string example, from the mainmenu_briefing_video.gui:

background	"gui::BriefingVideoMaterial"

The value here is a path to a custom video material shader. It is set at runtime by the engine, based on information the FM author provided in mainmenu_custom_defs.gui as, e.g.:

#define MM_BRIEFING_VIDEO_MATERIAL_1 "video/tdm_briefing_video"

(In older FMs, the video was chopped into parts, in which case the engine updates the value just-in-time. See comments in mainmenu_custom_defs.gui for details.)

For a more dynamic use, see GUI Scripting: On Entity's Surface, where it is important that the boolean value of the bound property...

visible "gui::is_visible"

... is automatically re-evaluated every frame. Similarly, one could have an expression with changing value:

 visible 1-"gui::is_visible"

But in any case, be aware that automatic re-evaluation of a particular property (like "visible" in these examples) can become deactivated/disabled...

  • prior to TDM 2.11, if you include ANY reference to that property in an event handler body. Deactivation happens at startup [or perhaps right after property's first initialization].
  • In TDM 2.11, if you manually assign to that property using the "set" command. [Probably doesn't apply to "transition"]. Deactivation happens when "set" is executed.

Careful programming can avoid unwanted deactivation.

In Event Block’s Set Command

Usages are either sources or sinks for "set" commands (involving strings or floats, not vectors).

Consider some scripting from readable entities. As source examples, in one of the onTime handlers, strings are copied from two gui:: parameters to the text property of the two other windowDefs named "title" and "body":

set "title::text" "$gui::title";
set "body::text" "$gui::body";

As usual with "set", a "$" on the source indicates that the value is to be copied, not a literal string such as "gui::title".

Here's a sink example, where information is being passed from the .gui to the .script file:

set "gui::InteractionState" "3";

See also the example at this article’s end for more.

In Event Block’s "If" Statement

A gui:: parameter can be tested in a "if" conditional clauses. For example, when a readable fades out its background, it uses an onTime event handler containing:

if ("gui::numPages" > 1) {
  transition "backgroundmulti::matcolor" "1 1 1 1" "1 1 1 0" READABLE_FADE_TIME;
}
if ("gui::numPages" == 1) {
  transition "backgroundsingle::matcolor" "1 1 1 1" "1 1 1 0" READABLE_FADE_TIME;
}

In a SCRIPT File – Syntax, and Available Functions for GUI:: Parameters

In the body of a SCRIPT function, use a double-quoted parameter name that matches that in the GUI file, but without the "gui::" prefix. Pass that name in a SetGui… or GetGui… function call whose type - float, int (also used for bool), or string - matches the usage in the GUI file. You must specify a handle with these functions, as discussed in GUI Scripting: Handles.

GetGui… Functions

Each of these functions returns the value of the GUI:: Parameter given by "key":

  • getGuiFloat(float handle, string key); // returns a float
  • getGuiInt(float handle, string key); // returns a float with int value
  • getGuiString(float handle, string key); // returns a string

Don’t confuse that last one with this function:

  • getGui(float handle); // returns a string with the file currently loaded by the GUI.

SetGui… Functions

Similarly:

  • setGuiFloat(float handle, string key, float val);
  • setGuiInt(float handle, string key, float val);
  • setGuiString(float handle, string key, string val);

There is a 127 character size limit on script strings that can impede that last function. An alternative function gets around that, by copying a string value directly from an entity spawnarg to a gui:: parameter:

  • setGuiStringFromKey(float handle, string key, entity src, string srcKey);

So, for example, in the body of a script object function, it would typically take the form:

$player1.setGuiStringFromKey(myhandle, "myGuiParamName", self, "mySpawnArgName");

For More

  • GUI Scripting: Number Wheel Example shows how a GUI can detect a user action, then originate a change to a gui:: parameter in order to pass it on to a script object for processing.
  • GUI Scripting: Flashbomb Example also is relevant. In particular, it shows how to use a gui:: parameter to control color transitions, even though the GUI language parser will not accept a gui:: parameter embedded into a color vector.