GUI Window Tutorial

From HEWIKI
(Difference between revisions)
Jump to: navigation, search
(now categorized under 'G' instead of 'C')
(added a tutorial for creating a new GUI Control using the GUI Editor)
Line 1: Line 1:
{{tocright}}
+
{{tocright}} {{intermediate}}  
{{intermediate}}
+
  
 +
== Overview  ==
  
== Overview ==
+
This is a step by step tutorial on how to create a custom GUI Control - a popup window which says, "Hello World". There is a tutorial for creating a custom GUI Control using the [[GUI Editor]] and another tutorial to create the same GUI Control using [[GUIXML]].
  
This is a step by step tutorial on how to create a simple GUIControl - a popup window which says, "Hello World."
+
<br>
  
It is important to note that this is procedural (that is, script-based) way of creating a GUIControl. This system uses a script to set the various attributes of the control, by using pre-created prototypes, creating GUIControl nodes based on those prototypes, and then modifying the nodes' various attributes individually.  Another way is to use the [[GUI Editor|GUI Editor]], which allows for a temporary Control to be created and/or configured in a visual manner.
+
== Prerequisites ==
  
 +
Before going any further, you should already have worked through at least the following tutorials:
  
 +
*[[Starting HeroBlade|Starting HeroBlade]]
 +
*[[How to write a script|How to write a script]]
 +
*[[GUI Editor|Using the GUI Editor]]
  
== Prerequisites ==
+
You should have <nowiki>HeroBlade</nowiki> open, and the script editor. Either create a new client-side script, or use one of your existing client-side work scripts where you can add the necessary function. Whichever script name you use, should be inserted in the place of &lt;script-name&gt; below.
  
Before going any further, you should already have worked through at least the following tutorials:
+
This tutorial has been written in a "cookbook" fashion so that it is not necessary to understand each GUIControl attribute. If you want though, there is a detailed line by line explanation of the modifications, farther down on this page.
  
* [[Starting HeroBlade|Starting HeroBlade]]
+
To learn more about the details of other GUIControl attributes which were not modified in this tutorial, please see the comprehensive list of Base Fields on the [[Technical:Graphical Controls|GUIControls]] page. The documentation there also includes a wealth of other information about the different Controls, including the default and potential values for each of their fields.
* [[How to write a script|How to write a script]]
+
  
You should have <nowiki>HeroBlade</nowiki> open, and the script editor.  Either create a new client-side script, or use one of your existing client-side work scripts where you can add the necessary function.  Whichever script name you use, should be inserted in the place of &lt;script-name&gt; below.
+
<br>  
  
This tutorial has been written in a "cookbook" fashion so that it is not necessary to understand each GUIControl attribute. If you want though, there is a detailed line by line explanation of the modifications, farther down on this page.
+
== GUI Editor Tutorial ==
  
To learn more about the details of other GUIControl attributes which were not modified in this tutorial, please see the comprehensive list of Base Fields on the [[Technical:Graphical_Controls| GUIControls]] page.  The documentation there also includes a wealth of other information about the different Controls, including the default and potential values for each of their fields.
+
This tutorial will show how to create a custom GUI Control using the [[GUI Editor]].  
  
 +
<br>
  
 +
=== Create the Prototype  ===
  
== Tutorial ==
+
[[Image:GUIWindowTutorial NewControlPrototype.png|right|Create the Prototype]]
  
 +
*Open the [[Organizer Panel]] is a tab marked GUIXML. If you do not have the Organizer visible, select it from the [[Panels menu]].
 +
*Click the '''Create New''' link at the bottom of the [[Organizer Panel#GUIXML_tab|GUIXML tab]]. This should open a window. It will have four inputs on it:
 +
**'''Prototype Name''' will be the name of the window as it appears in the [[Organizer Panel#GUIXML_tab|GUIXML tab]].
 +
**'''Description''' is a textual description of the purpose of the control.
 +
**'''Inherit From''' is what base control to use to create the control.
 +
**'''Class''' is the class (as defined in the [[DOM]]) that provides script functionality to the GUI Control. It is advisable to create one base class for each type of control that will be used, and create new classes to inherit from that as necessary. You should ensure that any classes you create for GUI Controls use the guicontrol archetype, as opposed to data. For more information on creating a class, see the [[Dom Editor]].
 +
*Enter "MyTestWindow" for the '''Prototype Name'''.
 +
*Enter a description for "MyTestWindow".
 +
*Enter "_movePanel" in the '''Inherit From''' input or select it from the GUI Control prototype selector by pressing the ellipsis button.
 +
**The class will be automatically selected as "GUIMovePanel".
 +
**In order to create a _movePanel using a custom Class, the class must exist in the Client [[DOM]]. It's archetype must be guicontrol and it must have GUIMovePanel as a parent class.
 +
*Click the Okay button. The new GUI Control will open in the GUI Editor.
 +
*Set the new Control's '''size''' to a width of 300 (the x value) and a height of 100 (the y value), which is in pixels.
  
=== Tutorial Overview ===
+
[[Image:GUIWindowTutorial MovePanel.png|700x700px|MyTestWindow GUI Control]]
  
The following function will create a new GUIControl called <code>myTestWindow</code>, based on the prototype <code>window_vscrollable</code>.  This new <nowiki>TestWindow</nowiki> will already have several necessary subcontrols, such as the ones necessary for creating a window titlebar, and a work (client) area within the body of the window. 
+
<br>  
  
The code in this function modifies the attributes of the subcontrols directly. It also creates an additional new GUIControl, called <code>myTestDataLabel</code>, based on the <code>label</code> prototype.  The new label will have text added to it, and then be connected to the client area of <code>myTestWindow</code> for display.
+
=== Add a Titlebar ===
  
When the function is run, the window and associated text will appear in the center of the viewport.
+
*Select "MyTestWindow" in the [[GUI Editor#GUI_Control_Tree_View|GUI Control Tree View]].
 +
*Open the [[Organizer Panel#GUIXML_tab|GUIXML tab]] of the [[Organizer Panel]].
 +
*Type "titlebar" in the search portion of the [[Organizer Panel]].
 +
*Double click on the "_titlebar" GUI Control prototype, which will add it to "MyTestWindow"'s list of children GUI Controls.
 +
*Change the name of the _titlebar to "titlebar" by editing the '''name''' field in the [[GUI Controls#Data|Data]] category of the GUI Control properties.
 +
**All GUIControls must have a name, so that they can be referenced by the GUI Engine and by HSL. The name can include spaces and different kinds of capitalization. Note that a '''name''' is usually different from the '''text''' of a control. In most cases, a Control's name is not seen by the user, it's strictly for internal use. To add something that is actually visible on the screen, this usually involves modifying a "text" field.
 +
*Expand the list of children control's for "titlebar". It has a child control named "title" which is a "_label" type. Select it in the GUI Control Tree View and change the value of the '''text''' field to "My Test Window". Notice the title bar now displays the text "My Test Window".
 +
**Something to note about the "title" GUIControl, it's a specialized form of Control, called <code>GUILabel</code>. The GUILabel Class inherits most of its fields from the base GUIControl, but also has a couple specialized fields, such as '''text'''. There are about a dozen different Classes that inherit from GUIControl, such as <code>GUIRadioButton</code>, <code>GUITextInputBox</code>, <code>GUINumericUpDownButton</code>, and so forth. For a complete list of the classes, plus details on the fields of each of them, please see the section on [[Technical:Graphical Controls|GUIControls]].
  
 +
[[Image:GUIWindowTutorial Titlebar.png|700x700px|MyTestWindow with a title bar]]
  
=== Create the function ===
+
<br>
  
A detailed line-by-line analysis of this code is available further down on this page. For now though, it can suffice to simply type in the following, or copy/paste this function into your client-side work script:
+
=== Add a Scrollable Panel  ===
<hsl>
+
 
function MakeTestWindow()
+
*Add the "_scrollableparent" GUI Control prototype as a child control of "MyTestWindow".
 +
*Change the '''name''' to "scrollable".
 +
*Notice that the "scrollableParent" filled up the rest of the space in "MyTestWindow". That is because the '''dockMode''' is set to FILL by default. A child control must be located somewhere on the parent control. It can be positioned by specifying its exact x,y coordinates, or it can be "docked" to the parent, so it will stretch and position itself automatically. There are six dock modes:
 +
**NONE (the default): the child control stays where you position it, in relation to the parent, at the size you tell it
 +
**TOP: same as left, but on top. The child control stretches horizontally, overriding size.x, but respects size.y
 +
**BOTTOM: same as top, but lower
 +
**LEFT: the child control takes up all available space on left edge of parent. Its position will be 0,0 in respect to the parent, and then its size will stretch (or tile, etc) vertically to become the same height as the parent. The child's horizontal size won't change.
 +
**RIGHT: same as left, but on right
 +
**FILL: takes up as much space as possible, stretching whatever way it needs to
 +
 
 +
[[Image:GUIWindowTutorial ScrollableParent.png|700x700px|MyTestWindow with a scrollable panel]]
 +
 
 +
<br>
 +
 
 +
=== Save MyTestWindow  ===
 +
 
 +
*To save your changes, press the XML button on the [[GUI Editor Toolbar|GUI Editor Toolbar]] to create the [[GUIXML]] code. The language will appear in the console window, along with a message that it has been copied to the clipboard. This is purely informational, however, as your GUIXML will have been automatically written to an .xml file in the repository.
 +
*Exit the GUI Editor by clicking on the button in the [[GUI Editor Toolbar|GUI Editor Toolbar]] that says "Close Editor".
 +
 
 +
[[Image:GUIEditorToolbar.png|GUIEditorToolbar.png]]
 +
 
 +
<br>  
 +
 
 +
== Invoking the GUI Control  ==
 +
 
 +
=== Overview  ===
 +
 
 +
The following function will create a node from the new GUIControl Prototype called "MyTestWindow".
  
                                        // This creates a window GUIControl from a prototype
+
The code in this function modifies the attributes of the subcontrols directly. It also creates an additional new GUIControl, called "myTestDataLabel", based on the "_label" prototype. The new label will have text added to it, and then be connected to the client area of MyTestWindow for display.
  
  myTestWindow as NodeRef of Class GUIControl = createNodeFromPrototype("_window")
+
When the function is run, the window and associated text will appear in the center of the viewport.
  
   myTestWindow.build = true              // Make the new window renderable in the screen
+
<br>
   myTestWindow.name = "A Test Window"
+
 
  myTestWindow.size.x = 300
+
=== Create the function  ===
   myTestWindow.size.y = 100
+
 
                                        // Configure the window's position in the viewport
+
A detailed line-by-line analysis of this code is available further down on this page. For now though, it can suffice to simply type in the following, or copy/paste this function into your client-side work script: <hsl>
 +
function MakeMyTestWindow()
 +
  // This creates a window GUIControl from a prototype
 +
 +
   myTestWindow as NodeRef of Class GUIControl = createNodeFromPrototype("MyTestWindow")
 +
 +
  // Make the new window renderable in the screen
 +
   myTestWindow.build = true
 +
 +
   // Configure the window's position in the viewport
 
   screen as Vector3 = getViewPortSize()
 
   screen as Vector3 = getViewPortSize()
 
   myTestWindow.position.x = (screen.x - myTestWindow.size.x) / 2
 
   myTestWindow.position.x = (screen.x - myTestWindow.size.x) / 2
 
   myTestWindow.position.y = (screen.y - myTestWindow.size.y) / 2
 
   myTestWindow.position.y = (screen.y - myTestWindow.size.y) / 2
 
                                        // Find the titlebar text control on the window, and modify it
 
 
  myTitle as NodeRef of Class GUILabel = findGUIControlByName(myTestWindow, "titlebar.title")
 
  myTitle.text = "The Amazing Test Window"
 
  myTitle.textformat.center  = true
 
 
   
 
   
                                        // Create the Label where the main window text will appear
+
  // Create the Label where the main window text will appear
 
+
 
   myTestDataLabel as NodeRef of Class GUILabel = createNodeFromPrototype("_label")
 
   myTestDataLabel as NodeRef of Class GUILabel = createNodeFromPrototype("_label")
 
   myTestDataLabel.name = "My Test Window's Data Label"
 
   myTestDataLabel.name = "My Test Window's Data Label"
 
   myTestDataLabel.text = "Hello World!"
 
   myTestDataLabel.text = "Hello World!"
 
   myTestDataLabel.autoSetHeight = true
 
   myTestDataLabel.autoSetHeight = true
 
+
                                        // Find the clientarea on the window control, and connect
+
  // Find the clientarea on the window control, and connect
                                        //  the new text label control to it.
+
  //  the new text label control to it.
 
+
   clientArea as NodeRef of Class GUIControl = findGUIControlByName(myTestWindow, "scrollable.clientarea")
   clientArea as NodeRef of Class GUIControl = myTestWindow.getClientarea()
+
 
   add back myTestDataLabel to clientArea.children
 
   add back myTestDataLabel to clientArea.children
 
   myTestDataLabel.dockMode = TOP
 
   myTestDataLabel.dockMode = TOP
 
+
   myTestDataLabel.build = true        // This makes the new label renderable in the screen
+
   // This makes the new label renderable in the screen
 +
  myTestDataLabel.build = true
 
.
 
.
</hsl>
+
</hsl>  
  
 +
*Compile and Submit the modified script
  
* Compile and Submit the modified script
+
*Run the script by typing into the Console:
 +
**<code>call &lt;script-name&gt; MakeMyTestWindow</code>
  
* Run the script by typing into the Console:
+
*The new window should pop up with the message, "Hello World!"
** <code>call &lt;script-name&gt; MakeTestWindow</code>
+
***If it doesn't, please run through the above steps again, or seek help from another scripter.
 +
***It may also be worth double-checking to ensure that you created a client-side script, and not a server one.
  
** The new window should pop up with the message, "Hello World!"
+
*Modify the script
*** If it doesn't, please run through the above steps again, or seek help from another scripter.
+
**Close the new window control, switch back to the script editor, and try modifying various parameters in the function that was created. Then compile, submit, and run the script again, and see how changing each parameter modified the appearance of the window.
*** It may also be worth double-checking to ensure that you created a client-side script, and not a server one.
+
***To quickly enter the <code>call script</code> line again, just use the Up-arrow to recover the last line typed.  
 +
***Note that with this kind of rapid back and forth edit/run methodology, that you may get ahead of the server. If your change didn't seem to "take", be sure to check the Console Window after you submit a script, to ensure that it was properly compiled (<code>Got compiled script &lt;name&gt;</code>). This may take several seconds.
 +
**Try making the following changes, one at a time:
 +
***Set the MyTestWindow's <code>size.y</code> value to 400
 +
***Change <code>myTestDataLabel.text</code> to say something different
 +
***Change the <code>dockMode</code> to another value, such as BOTTOM or RIGHT
 +
***Set <code>MyTestWindow</code> x,y position to 0,0
 +
***Set <code>MyTestWindow</code> x,y position to 50,200
 +
***Figure out how to change the text in the title bar of the window
 +
***Feel free to experiment! For example, read up on all the other GUIControl fields that can be modified, and try modifying one of them to see what happens.
  
* Modify the script
+
<br>  
** Close the new window control, switch back to the script editor, and try modifying various parameters in the function that was created.  Then compile, submit, and run the script again, and see how changing each parameter modified the appearance of the window.
+
*** To quickly enter the <code>call script</code> line again, just use the Up-arrow to recover the last line typed.
+
*** Note that with this kind of rapid back and forth edit/run methodology, that you may get ahead of the server.  If your change didn't seem to "take", be sure to check the Console Window after you submit a script, to ensure that it was properly compiled (<code>Got compiled script &lt;name&gt;</code>).  This may take several seconds.
+
  
** Try making the following changes, one at a time:
+
=== Detailed Explanations of the Function's Code ===
*** Set the testwindow's <code>size.y</code> value to 400
+
*** Change <code>myTestDataLabel.text</code> to say something different
+
*** Change the <code>dockMode</code> to another value, such as ~BOTTOM or ~RIGHT
+
*** Set <code>myTestWindow</code> x,y position to 0,0
+
*** Set <code>myTestWindow</code> x,y position to 50,200
+
*** Figure out which one of these will change the text in the title bar of the window:
+
**** Change <code>myTestWindow.name</code> to something different
+
**** Change <code>myTitle.text</code> to something different
+
*** Feel free to experiment! For example, read up on all the other GUIControl fields that can be modified, and try modifying one of them to see what happens.
+
  
 +
Detailed explanation of these steps is below:
  
 +
<br>
  
== Detailed Explanations of the Function's Code ==
+
==== Create the GUIControl Window Node ====
  
The function takes the following steps:
+
There are many pre-made prototypes that exist for creating a window. For example: A basic window, a scrollable window, a resizeable window, etc. For this example, the "MyTestWindow" prototype was used.
  
* Create the window control
+
Each GUI control prototype has its own [[GUIXML]] file. The available prototypes for GUI controls are listed in the [[Organizer Panel#GUIXML_tab|GUIXML tab]] of the [[Organizer Panel]].
* Build it (make it renderable)
+
* Name it
+
* Define the Control's position on the screen
+
* Put text in the titlebar label
+
* Define the area where the window's content will go
+
* Create a label to hold the content
+
* Make the label renderable (build it)
+
* Name the label
+
* Put some content in the label
+
* Set the size of the label
+
* Glue the label control to the window control
+
  
Detailed explanation of these steps is below:
 
 
 
=== Create the GUIControl Window Node ===
 
 
<hsl>
 
<hsl>
myTestWindow as NodeRef of Class GUIControl = createNodeFromPrototype("_window")
+
myTestWindow as NodeRef of Class GUIControl = createNodeFromPrototype("MyTestWindow")
</hsl>
+
</hsl>  
  
 +
<br>
  
There are many pre-made prototypes that exist for creating a window.  For example:  A basic window, a scrollable window, a resizeable window, etc.  For this example, the <code>_window</code> prototype was used. This prototype is for a window that can be scrolled vertically, and also resized.  If it was desired to use a prototype which was scrollable but not resizeable, then a different prototype could have been used. 
+
==== Make the GUIControl Renderable ====
  
Each GUI control prototype has its own XML file. The available prototypes for GUI controls are listed in the Organizer under the GUIXML tab.
+
When the <code>build</code> flag is set to TRUE, that tells the Hero's Journey engine that this Control is okay to render on the screen. If the Control were still in a half-finished state, this flag would probably be kept at FALSE so that the Control wouldn't be rendered yet.
  
=== Make the GUIControl Renderable ===
 
 
<hsl>
 
<hsl>
 
myTestWindow.build = true
 
myTestWindow.build = true
</hsl>
+
</hsl>  
  
 +
<br>
  
When the <code>build</code> flag is set to ~TRUE, that tells the Hero's Journey engine that this Control is okay to render on the screen.  If the Control were still in a half-finished state, this flag would probably be kept at ~FALSE so that the Control wouldn't be rendered yet.
+
==== Position the Control on the screen ====
  
 +
If a position is not specified, the Control will be positioned at 0,0, which means that its upper left corner will be at the far upper left of the viewport (the game screen). The '''position''' fields in this case are merely to determine the Control's starting location.
  
=== Name it ===
+
To center the Control, first determine the current size of the Viewport, with <code>getViewPortSize()</code>. This returns a value in vector3 format, where the x and y values are the current width and height of the Viewport. A simple calculation between the size of the Control and the size of the Viewport (divided by two) provides the perfect location at which to position the Control.
  
 
<hsl>
 
<hsl>
myTestWindow.name = "Test Window"
+
screen as Vector3 = getViewPortSize()
</hsl>
+
myTestWindow.position.x = (screen.x - myTestWindow.size.x) / 2
 +
myTestWindow.position.y = (screen.y - myTestWindow.size.y) / 2
 +
</hsl>  
  
 
+
However, the Control could also be positioned anywhere else in the Viewport as well. For example:  
All GUIControls must have a name, so that they can be referenced by the GUI Engine and by HSL.  The name can include spaces and different kinds of capitalization.  Note that a "name" is usually different from the "text" of a control.  In most cases, a Control's name is not seen by the user -- it's strictly for internal use.  To add something that is actually visible on the screen, this usually involves modifying a "text" field.
+
 
+
 
+
=== Give it a size ===
+
<hsl>
+
  myTestWindow.size.x = 300
+
  myTestWindow.size.y = 100
+
</hsl>
+
 
+
 
+
This sets the new Control's width (the x value) and height (the y value), in pixels.
+
 
+
 
+
=== Position the Control on the screen ===
+
                       
+
<hsl>
+
  screen as Vector3 = getViewPortSize()
+
  myTestWindow.position.x = (screen.x - myTestWindow.size.x) / 2
+
  myTestWindow.position.y = (screen.y - myTestWindow.size.y) / 2
+
</hsl>
+
 
+
 
+
If a position is not specified, the Control will be positioned at 0,0, which means that its upper left corner will be at the far upper left of the viewport (the game screen).
+
 
+
To center the Control, first determine the current size of the Viewport, with <code>getViewPortSize()</code>.  This returns a value in vector3 format, where the x and y values are the current width and height of the Viewport.  A simple calculation between the size of the Control and the size of the Viewport (divided by two) provides the perfect location at which to position the Control.  However, the Control could also be positioned anywhere else in the Viewport as well. For example:
+
  
 
<hsl>
 
<hsl>
 
myTestWindow.position.x = 300
 
myTestWindow.position.x = 300
 
myTestWindow.position.y = 300
 
myTestWindow.position.y = 300
</hsl>
+
</hsl>  
  
Note that the position will change automatically if the user decides to drag the window around or resize it.  The <code>position</code> fields in this case are merely to determine the Control's starting location.
+
Note that the position will change automatically if the user decides to drag the window around.  
  
 +
<br>
  
=== Put text in the title label ===
+
==== Create a label to hold your content ====
+
This particular prototype that has been used, <code>window_vscrollable</code>, already has several necessary child controls, some of which have their own children.  For example, the window has a child control <code>titlebar</code>, which has a child <code>titlebar_body</code>, which has a child Control label <code>text</code>, which has a subfield "text", which is what actually displays as the name of the titlebar to the user.
+
  
In order for the script to change the label, it's necessary to know the node reference for that Control.  A handy function for this is <code>findGUIControlByName()</code>, which takes a parent Control to search through, and the name of the Control that it's looking for, and then returns a Node reference if it is found.
+
In this step, the function creates a new GUILabel Control, based on the <code>_label</code> prototype.  
<hsl>
+
  
myTitle as noderef of class GUILabel = findGUIControlByName(myTestWindow, "titlebar.title")
 
</hsl>
 
 
Once the noderef has been found, the Control can be modified:
 
 
<hsl>
 
<hsl>
myTitle.text = "The Test Window"
+
myTestDataLabel as NodeRef of Class GUILabel = createNodeFromPrototype("_label")
</hsl>
+
myTestDataLabel.name = "My Test Window's First Data Label"
 +
</hsl>  
  
 +
<br>
  
The text can also be centered:
+
==== Put some data in the new label ====
<hsl>
+
myTitle.textformat.center  = true
+
</hsl>
+
 
+
 
+
This will attempt to center the text within the confines of the Label Control.
+
 
+
Another thing to note about this GUIControl, is that we're using a specialized form of Control, called <code>GUILabel</code>.  The GUILabel Class inherits most of its fields from the base GUIControl, but also has a couple specialized fields, such as "text".  There are about a dozen different Classes that inherit from GUIControl, such as <code>GUIRadioButton</code>, <code>GUITextInputBox</code>, <code>GUINumericUpDownButton</code>, and so forth.  For a complete list of the classes, plus details on the fields of each of them, please see the section on [[Technical:Graphical_Controls| GUIControls]].
+
 
+
 
+
=== Create a label to hold your content ===
+
 
+
In this step, the function creates a new GUILabel Control, based on the <code>_label</code> prototype. 
+
 
+
<hsl>
+
  myTestDataLabel as NodeRef of Class GUILabel = createNodeFromPrototype("_label")
+
  myTestDataLabel.name = "My Test Window's First Data Label"
+
</hsl>
+
 
+
  
=== Put some data in the new label ===
+
This code will set the text that is displayed by this GUILabel.
  
 
<hsl>
 
<hsl>
 
myTestDataLabel.text = "Hello World!"
 
myTestDataLabel.text = "Hello World!"
</hsl>
+
</hsl>  
  
 +
<br>
  
=== Set the size of the label ===
+
==== Set the size of the label ====
  
It's possible to set the size to a specific value, or it can be automatically determined. In the case of this tutorial, the size is being set automatically:
+
It's possible to set the size to a specific value, or it can be automatically determined. In the case of this tutorial, the size is being set automatically:  
  
 
<hsl>
 
<hsl>
 
myTestDataLabel.autoSetHeight = true
 
myTestDataLabel.autoSetHeight = true
</hsl>
+
</hsl>  
  
This automatically make the size of the label large enough to accomodate however much text is in it.
+
This automatically make the size of the label large enough to accomodate however much text is in it.  
  
Note: <code>autoSetHeight</code> does not modify the size of the font -- only the size of the Control that contains the font. Though it's possible to make a larger font by scaling a Control to a larger size (which scales the font along with it), this does not look very clean. As of this writing, there is not any way to elegantly change font size or type.
+
Note: '''autoSetHeight''' does not modify the size of the font, only the size of the Control that contains the font. Though it's possible to make a larger font by scaling a Control to a larger size (which scales the font along with it), this does not look very clean. As of this writing, there is not any way to elegantly change font size or type.  
  
 +
<br>
  
=== Dock it ===
+
==== Find the Client Area Control ====
  
A child control must be located somewhere on the parent control.  It can be positioned by specifying its exact x,y coordinates, or it can be "docked" to the parent, so it will stretch and position itself automatically.  For example a child control that is "Dock Left" will match its left edge to the left edge of the parent, and stretch itself vertically so that it is the same vertical size of the parent.
+
This is a control that's already a child of myTestWindow. To manipulate it though, we need a node reference to it. So we need to "find" it on the parent, using the [[GUI_functions#Find_GUI_Control_By_Name|FindGUIControlByName]] function.  
 
+
Note that in a subsequent step we are going to set this label's parent to be the clientarea, so in the case of this window, you can read "parent" to mean "clientarea" in the descriptions above.
+
 
+
There are six dock modes:
+
 
+
* NONE (the default): the child control stays where you position it, in relation to the parent, at the size you tell it
+
* LEFT: the child control takes up all available space on left edge of parent. Its position will be 0,0 in respect to the parent, and then its size will stretch (or tile, etc) vertically to become the same height as the parent. The child's horizontal size won't change.
+
* RIGHT: same as left, but on right
+
* TOP: same as left, but on top.  The child control stretches horizontally, overriding size.x, but respects size.y
+
* BOTTOM: same as top, but lower
+
* FILL: takes up as much space as possible, stretching whatever way it needs to
+
 
+
Since our child control window is vertically scrollable, it works best to set its dockmode to TOP.  We know how wide it is, but we don't want to have to know how high the window needs to be.  That's why we made it scrollable.
+
 
+
The FILL option would not work as well.  True, it will take up as much space as it needs, but it would not scroll because its size would be defined by the visible size of the clientarea.  We want to have access to areas beyond the visible boundaries of the clientarea if we need it.
+
 
+
Note:  At some point in the future, this may be handled differently, and a Dock Mode of ~FILL might allow a child control to still progress beyond the bottom of the parent control if it needs to.
+
  
 
<hsl>
 
<hsl>
myTestDataLabel.dockMode = TOP
+
clientArea as NodeRef of Class GUIControl = findGUIControlByName(myTestWindow, "scrollable.clientarea")
</hsl>
+
</hsl>  
  
 +
This control defines the panel that will hold the things that you want to display. It's what's left of the window after taking account of the resize bars, title bars, etc. The clientarea fills up all the spaces between all these things.
  
=== Find the Client Area Control ===
+
<br>
  
This is a control that's already a child of myTestWindow.  To manipulate it though, we need a node reference to it.  So we need to "find" it on the parent, using the <code>getClientArea()</code> method (optionally we could have used <code>FindGUIControlByName()</code> function).
+
==== Add the Label to the List of Client Area ====
  
<hsl>
+
This adds the new Label to the end of the list of children of clientArea. If other labels are created, they can be added in behind this one.
clientArea as NodeRef of Class GUIControl = myTestWindow.getClientArea()
+
</hsl>
+
 
+
 
+
This control defines the panel that will hold the things that you want to display.  It's what's left of the window after taking account of the resize bars, title bars, etc. The clientarea fills up all the spaces between all these things.
+
 
+
 
+
=== Add the Label to the List of Client Area Children ===
+
  
 
<hsl>
 
<hsl>
 
 
add back myTestDataLabel to clientArea.children
 
add back myTestDataLabel to clientArea.children
</hsl>
+
</hsl>  
  
 +
<br>
  
This adds the new Label to the end of the list of children of ~clientArea.  If other labels are created, they can be added in behind this one.
+
==== Make the Label Renderable ====
  
 +
Since "myTestDataLabel" was created by the script and then linked in, its '''build''' flag needs to be toggled TRUE.
  
=== Build it ===
 
 
This step was not necessary for the <code>myTitle</code> label, as it was already a direct child of the window.  In other words, we "found" it, we didn't create it.  Since <code>myTestDataLabel</code> was created by the script though, and then linked in, its Build flag still needs to be toggled true:
 
 
<hsl>
 
<hsl>
 
 
myTestDataLabel.build = true
 
myTestDataLabel.build = true
</hsl>
+
</hsl>  
 
+
  
 +
<br>
  
== Additional information ==
+
== Additional information ==
  
* [[Technical:Graphical_Controls|GUIControls]]
+
*[[Technical:Graphical Controls|GUIControls]]  
* [[Technical:Graphical_Editor| GUIEditor]]
+
*[[Technical:Graphical Editor|GUIEditor]]
  
[[Category:GUI|GUI Window Tutorial]]
+
[[Category:GUI]] [[Category:Tutorials]]
[[Category:Tutorials|GUI Window Tutorial]]
+

Revision as of 20:43, 9 November 2011

Contents

He intermediate.png

Overview

This is a step by step tutorial on how to create a custom GUI Control - a popup window which says, "Hello World". There is a tutorial for creating a custom GUI Control using the GUI Editor and another tutorial to create the same GUI Control using GUIXML.


Prerequisites

Before going any further, you should already have worked through at least the following tutorials:

You should have HeroBlade open, and the script editor. Either create a new client-side script, or use one of your existing client-side work scripts where you can add the necessary function. Whichever script name you use, should be inserted in the place of <script-name> below.

This tutorial has been written in a "cookbook" fashion so that it is not necessary to understand each GUIControl attribute. If you want though, there is a detailed line by line explanation of the modifications, farther down on this page.

To learn more about the details of other GUIControl attributes which were not modified in this tutorial, please see the comprehensive list of Base Fields on the GUIControls page. The documentation there also includes a wealth of other information about the different Controls, including the default and potential values for each of their fields.


GUI Editor Tutorial

This tutorial will show how to create a custom GUI Control using the GUI Editor.


Create the Prototype

Create the Prototype

MyTestWindow GUI Control


Add a Titlebar

MyTestWindow with a title bar


Add a Scrollable Panel

MyTestWindow with a scrollable panel


Save MyTestWindow

GUIEditorToolbar.png


Invoking the GUI Control

Overview

The following function will create a node from the new GUIControl Prototype called "MyTestWindow".

The code in this function modifies the attributes of the subcontrols directly. It also creates an additional new GUIControl, called "myTestDataLabel", based on the "_label" prototype. The new label will have text added to it, and then be connected to the client area of MyTestWindow for display.

When the function is run, the window and associated text will appear in the center of the viewport.


Create the function

A detailed line-by-line analysis of this code is available further down on this page. For now though, it can suffice to simply type in the following, or copy/paste this function into your client-side work script:

function MakeMyTestWindow()
  // This creates a window GUIControl from a prototype
 
  myTestWindow as NodeRef of Class GUIControl = createNodeFromPrototype("MyTestWindow")
 
  // Make the new window renderable in the screen
  myTestWindow.build = true
 
  // Configure the window's position in the viewport
  screen as Vector3 = getViewPortSize()
  myTestWindow.position.x = (screen.x - myTestWindow.size.x) / 2
  myTestWindow.position.y = (screen.y - myTestWindow.size.y) / 2
 
  // Create the Label where the main window text will appear
  myTestDataLabel as NodeRef of Class GUILabel = createNodeFromPrototype("_label")
  myTestDataLabel.name = "My Test Window's Data Label"
  myTestDataLabel.text = "Hello World!"
  myTestDataLabel.autoSetHeight = true
 
  // Find the clientarea on the window control, and connect
  //   the new text label control to it.
  clientArea as NodeRef of Class GUIControl = findGUIControlByName(myTestWindow, "scrollable.clientarea")
  add back myTestDataLabel to clientArea.children
  myTestDataLabel.dockMode = TOP
 
  // This makes the new label renderable in the screen
  myTestDataLabel.build = true
.


Detailed Explanations of the Function's Code

Detailed explanation of these steps is below:


Create the GUIControl Window Node

There are many pre-made prototypes that exist for creating a window. For example: A basic window, a scrollable window, a resizeable window, etc. For this example, the "MyTestWindow" prototype was used.

Each GUI control prototype has its own GUIXML file. The available prototypes for GUI controls are listed in the GUIXML tab of the Organizer Panel.

myTestWindow as NodeRef of Class GUIControl = createNodeFromPrototype("MyTestWindow")


Make the GUIControl Renderable

When the build flag is set to TRUE, that tells the Hero's Journey engine that this Control is okay to render on the screen. If the Control were still in a half-finished state, this flag would probably be kept at FALSE so that the Control wouldn't be rendered yet.

myTestWindow.build = true


Position the Control on the screen

If a position is not specified, the Control will be positioned at 0,0, which means that its upper left corner will be at the far upper left of the viewport (the game screen). The position fields in this case are merely to determine the Control's starting location.

To center the Control, first determine the current size of the Viewport, with getViewPortSize(). This returns a value in vector3 format, where the x and y values are the current width and height of the Viewport. A simple calculation between the size of the Control and the size of the Viewport (divided by two) provides the perfect location at which to position the Control.

screen as Vector3 = getViewPortSize()
myTestWindow.position.x = (screen.x - myTestWindow.size.x) / 2
myTestWindow.position.y = (screen.y - myTestWindow.size.y) / 2

However, the Control could also be positioned anywhere else in the Viewport as well. For example:

myTestWindow.position.x = 300
myTestWindow.position.y = 300

Note that the position will change automatically if the user decides to drag the window around.


Create a label to hold your content

In this step, the function creates a new GUILabel Control, based on the _label prototype.

myTestDataLabel as NodeRef of Class GUILabel = createNodeFromPrototype("_label")
myTestDataLabel.name = "My Test Window's First Data Label"


Put some data in the new label

This code will set the text that is displayed by this GUILabel.

myTestDataLabel.text = "Hello World!"


Set the size of the label

It's possible to set the size to a specific value, or it can be automatically determined. In the case of this tutorial, the size is being set automatically:

myTestDataLabel.autoSetHeight = true

This automatically make the size of the label large enough to accomodate however much text is in it.

Note: autoSetHeight does not modify the size of the font, only the size of the Control that contains the font. Though it's possible to make a larger font by scaling a Control to a larger size (which scales the font along with it), this does not look very clean. As of this writing, there is not any way to elegantly change font size or type.


Find the Client Area Control

This is a control that's already a child of myTestWindow. To manipulate it though, we need a node reference to it. So we need to "find" it on the parent, using the FindGUIControlByName function.

clientArea as NodeRef of Class GUIControl = findGUIControlByName(myTestWindow, "scrollable.clientarea")

This control defines the panel that will hold the things that you want to display. It's what's left of the window after taking account of the resize bars, title bars, etc. The clientarea fills up all the spaces between all these things.


Add the Label to the List of Client Area

This adds the new Label to the end of the list of children of clientArea. If other labels are created, they can be added in behind this one.

add back myTestDataLabel to clientArea.children


Make the Label Renderable

Since "myTestDataLabel" was created by the script and then linked in, its build flag needs to be toggled TRUE.

myTestDataLabel.build = true


Additional information

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox