Difference between revisions of "Manual:Geyser"

From Mudlet
Jump to navigation Jump to search
(→‎Geyser.Label: Addiing font size snippet)
(48 intermediate revisions by 9 users not shown)
Line 1: Line 1:
{{TOC right}}
 
 
{{TOC right}}
 
{{TOC right}}
  
= The Geyser Layout Manager =
+
= Introduction =
  
== Introduction ==
+
The Geyser Layout Manager is an object oriented framework for creating, updating and organizing GUI elements within Mudlet - it allows you to make your UI easier on Mudlet, and makes it easier for the UI to be compatible with different screen sizes.
  
Geyser is an object oriented framework for creating, updating and organizing GUI elements within Mudlet - it allows you to make your UI easier on Mudlet, and makes it easier for the UI to be compatible with different screen sizes.
+
=== Motivation ===
  
==== Motivation ====
+
Mudlet makes the creation of label, miniconsoles and gauges a quick and easy thing. Mudlet provides a nice signal when window resize events happen. To help with complex window management, Geyser steps in.
  
Mudlet makes the creation of label, miniconsoles and gauges a quick and easy thing. Mudlet provides a nice signal when window resize events happen. Mudlet does not provide a good framework for complex window management, which Geyser attempts to address.
+
=== Main Geyser Features ===
 
 
==== Main Geyser Features ====
 
  
 
Geyser is based on traditional GUI concepts and should feel similar to using Java's Swing. The biggest difference is in how positions are specified.
 
Geyser is based on traditional GUI concepts and should feel similar to using Java's Swing. The biggest difference is in how positions are specified.
Line 21: Line 18:
 
* However, there is always some overhead for automation systems and Geyser is no exception. Fortunately, most of the overhead is during window creation and resize events - not things that happen frequently.
 
* However, there is always some overhead for automation systems and Geyser is no exception. Fortunately, most of the overhead is during window creation and resize events - not things that happen frequently.
  
==== Constraints format ====
+
=== Getting pictures for your stuff ===
 +
You can find good, freely-available assets for your UI here:
 +
* [https://kenney.nl/assets?q=2d kenney.nl]
 +
* [https://opengameart.org/ opengameart.org]
 +
 
 +
=== Constraints format ===
  
 
Geyser position constraints are a string composed of a number and a format type. For example, "10px" means 10 pixels, either pixels from the origin (e.g. x or y) or a value for the width or height. A negative number indicates distance from a container's right or bottom border depending on whether is a constraint for x/width or y/height, respectively. Percentages for width and height are in terms of the container's dimensions and negative values are converted to the equivalent positive value. A 100% width subwindow with an x-coordinate of 10 will have part of itself displayed outside the confines of its container. There is no hard limit on maximum window size, just as with regular Mudlet windows. If a number, n, is passed as a constraint instead of a string, it is assumed to be equivalent to "npx". Any Lua table that contains entries for x, y, width and height in the proper format can be used for Geyser constructors and setting constraints. Just like in Mudlet, 0,0 coordinates mean the top-left corner.
 
Geyser position constraints are a string composed of a number and a format type. For example, "10px" means 10 pixels, either pixels from the origin (e.g. x or y) or a value for the width or height. A negative number indicates distance from a container's right or bottom border depending on whether is a constraint for x/width or y/height, respectively. Percentages for width and height are in terms of the container's dimensions and negative values are converted to the equivalent positive value. A 100% width subwindow with an x-coordinate of 10 will have part of itself displayed outside the confines of its container. There is no hard limit on maximum window size, just as with regular Mudlet windows. If a number, n, is passed as a constraint instead of a string, it is assumed to be equivalent to "npx". Any Lua table that contains entries for x, y, width and height in the proper format can be used for Geyser constructors and setting constraints. Just like in Mudlet, 0,0 coordinates mean the top-left corner.
Line 27: Line 29:
 
The following is a valid example for coordinates of a Geyser object:
 
The following is a valid example for coordinates of a Geyser object:
  
<lua>
+
<syntaxhighlight lang="lua">
 
{x = "20px", y = "-10c", width = "40%", height = 30}
 
{x = "20px", y = "-10c", width = "40%", height = 30}
</lua>
+
</syntaxhighlight>
  
== Geyser elements ==
+
= Geyser elements =
 
The purpose of this document is to go through every Geyser element and provide practical examples on how they are used. Read it from top to bottom, preferably doing all of the examples to understand how they work!
 
The purpose of this document is to go through every Geyser element and provide practical examples on how they are used. Read it from top to bottom, preferably doing all of the examples to understand how they work!
  
===[http://www.mudlet.org/geyser/files/geyser/GeyserContainer.html Geyser.Container]===
+
See also: https://www.mudlet.org/geyser/files/index.html for a brief and technical overview of all elements and their functions.
 +
 
 +
==[http://www.mudlet.org/geyser/files/geyser/GeyserContainer.html Geyser.Container]==
 
An invisible, organizing object in Geyser - use it to divide your screen and position elements accordingly. '''[http://www.mudlet.org/geyser/files/geyser/GeyserContainer.html See here]''' for all of the functions that are available to you to use.
 
An invisible, organizing object in Geyser - use it to divide your screen and position elements accordingly. '''[http://www.mudlet.org/geyser/files/geyser/GeyserContainer.html See here]''' for all of the functions that are available to you to use.
  
 
A container is also the base class - which means that everything (labels, miniconsoles and gauges) can use its functions, since everything else is at heart a container.
 
A container is also the base class - which means that everything (labels, miniconsoles and gauges) can use its functions, since everything else is at heart a container.
  
==== Creating a container ====
+
=== Creating a container ===
 
To get started with a container, here's an example that'll create a 200px border on the left side of Mudlet for you, and make a container cover all of it - so you can place other visual elements inside it:
 
To get started with a container, here's an example that'll create a 200px border on the left side of Mudlet for you, and make a container cover all of it - so you can place other visual elements inside it:
  
<lua>
+
<syntaxhighlight lang="lua">
 
setBorderLeft(200)
 
setBorderLeft(200)
 
left_container = Geyser.Container:new({
 
left_container = Geyser.Container:new({
Line 49: Line 53:
 
   width = 200, height="100%", -- with a width of 200, and a height of the full screen, hence 100%
 
   width = 200, height="100%", -- with a width of 200, and a height of the full screen, hence 100%
 
})
 
})
</lua>
+
</syntaxhighlight>
  
Right away, you'll see space appear on the left side. It'll be black, as the container is an invisible unit by itself. You can make sure it's there by making it flash. If necessary, obtain the [http://forums.mudlet.org/viewtopic.php?f=8&t=100 "Run Lua code" alias], then do:
+
Right away, you'll see space appear on the left side. It'll be black, as the container is an invisible unit by itself. You can make sure it's there by making it flash by doing this from the input line:
  
<lua>lua left_container:flash()</lua>
+
<syntaxhighlight lang="lua">lua left_container:flash()</syntaxhighlight>
  
 
The command will cause your container to flash for a moment for you, revealing itself.
 
The command will cause your container to flash for a moment for you, revealing itself.
  
==== Container within a container ====
+
=== Container within a container ===
 
You can place containers within other containers by specifying which "parent" the new container should have when you create one. Given our [[#Creating a container|previous example]], you can split the left side into two halves like this:
 
You can place containers within other containers by specifying which "parent" the new container should have when you create one. Given our [[#Creating a container|previous example]], you can split the left side into two halves like this:
  
<lua>
+
<syntaxhighlight lang="lua">
 
left_container_top = Geyser.Container:new({
 
left_container_top = Geyser.Container:new({
 
   name = "left_container_top",
 
   name = "left_container_top",
Line 72: Line 76:
 
   width = "100%", height="50%", -- and has the same half height of the original container
 
   width = "100%", height="50%", -- and has the same half height of the original container
 
}, left_container)               
 
}, left_container)               
</lua>
+
</syntaxhighlight>
  
==== Aligning relative to bottom or right sides ====
+
=== Aligning relative to bottom or right sides ===
 
The aligning point within Mudlet is the top-left corner, and it's the same for the elements they are aligned - the position you specify is used by the top-left corner of the element.
 
The aligning point within Mudlet is the top-left corner, and it's the same for the elements they are aligned - the position you specify is used by the top-left corner of the element.
  
 
Using Geyser, you can align to the opposite side as well, using the coordinates in negatives, while keeping the dimensions of the object in mind. For example, if you want to align a box that's 20px wide on the usual left side, you'd give it a width of 20 and an x value of 0. If you'd like to align it on the right side, then you'd give it an x value of -20. The box will spawn 20px away from the right side and "grow" to the right by 20px.
 
Using Geyser, you can align to the opposite side as well, using the coordinates in negatives, while keeping the dimensions of the object in mind. For example, if you want to align a box that's 20px wide on the usual left side, you'd give it a width of 20 and an x value of 0. If you'd like to align it on the right side, then you'd give it an x value of -20. The box will spawn 20px away from the right side and "grow" to the right by 20px.
  
<lua>
+
<syntaxhighlight lang="lua">
 
right_container = Geyser.Container:new({
 
right_container = Geyser.Container:new({
 
   name = "right_container",
 
   name = "right_container",
Line 85: Line 89:
 
   width = "20%", height="50%",      -- filling it up until the end
 
   width = "20%", height="50%",      -- filling it up until the end
 
})             
 
})             
</lua>
+
</syntaxhighlight>
  
 
Do make sure to account for the scrollbar, as Mudlet UI elements can overlap it. You can also move the scrollbar with [[Manual:UI_Functions#setBorderRight|setBorderRight()]].
 
Do make sure to account for the scrollbar, as Mudlet UI elements can overlap it. You can also move the scrollbar with [[Manual:UI_Functions#setBorderRight|setBorderRight()]].
  
===[http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html Geyser.Label]===
+
==[http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html Geyser.Label]==
 
Based on the Mudlet label, this allows you to use the labels functionality within Geyser. Labels allow you to use pictures in your interface, as well as nicely-formatted text.
 
Based on the Mudlet label, this allows you to use the labels functionality within Geyser. Labels allow you to use pictures in your interface, as well as nicely-formatted text.
  
==== Basic label ====
+
=== Basic label ===
  
 
Here's an example to get you started with:
 
Here's an example to get you started with:
  
<lua>
+
<syntaxhighlight lang="lua">
 
testlabel = Geyser.Label:new({
 
testlabel = Geyser.Label:new({
 
   name = "testlabel",
 
   name = "testlabel",
Line 105: Line 109:
 
   message = [[<center>heey</center>]]
 
   message = [[<center>heey</center>]]
 
})
 
})
</lua>
+
</syntaxhighlight>
  
 
This labels '''x''' coordinate is specified as 50% - and because it's not attached to any container, this implies that the window will start halfway at the main window. You can tell it's not attached to a container because there's nothing in between the last ''}'' and '')'', the place where the container goes.
 
This labels '''x''' coordinate is specified as 50% - and because it's not attached to any container, this implies that the window will start halfway at the main window. You can tell it's not attached to a container because there's nothing in between the last ''}'' and '')'', the place where the container goes.
Line 118: Line 122:
 
Playing around with the starting location and dimensions, we can also place it in the center of the screen with:
 
Playing around with the starting location and dimensions, we can also place it in the center of the screen with:
  
<lua>
+
<syntaxhighlight lang="lua">
 
testlabel = Geyser.Label:new({
 
testlabel = Geyser.Label:new({
 
   name = "testlabel",
 
   name = "testlabel",
Line 127: Line 131:
 
})
 
})
 
testlabel:setColor(0,255,0,150)
 
testlabel:setColor(0,255,0,150)
</lua>
+
</syntaxhighlight>
  
 
[[File:Simple_label_centered.png|center|600px]]
 
[[File:Simple_label_centered.png|center|600px]]
Line 133: Line 137:
 
To change the message on a label, you can use the ''mylabel:echo()'' function, where ''mylabel'' is the name of the label you gave it:
 
To change the message on a label, you can use the ''mylabel:echo()'' function, where ''mylabel'' is the name of the label you gave it:
  
<lua>
+
<syntaxhighlight lang="lua">
 
mylabel:echo("hello!")
 
mylabel:echo("hello!")
</lua>
+
</syntaxhighlight>
  
==== Setting the font size ====
+
=== Setting the font size ===
  
 
To set a different font size for your Label, use the ''setFontSize()'' method. For example:
 
To set a different font size for your Label, use the ''setFontSize()'' method. For example:
  
<lua>
+
<syntaxhighlight lang="lua">
testlabel:setFontSize( 14)
+
testlabel:setFontSize(14)
</lua>
+
</syntaxhighlight>
  
 
The font size is set in Pt, so anything above 30 will likely be too large to be useful.
 
The font size is set in Pt, so anything above 30 will likely be too large to be useful.
  
==== Label inside a container ====
+
=== Label inside a container ===
  
 
Once you've got your containers and mastered the basic labels, you can drop labels into your nicely-organized containers. Doing so is similar to nesting containers:
 
Once you've got your containers and mastered the basic labels, you can drop labels into your nicely-organized containers. Doing so is similar to nesting containers:
  
<lua>
+
<syntaxhighlight lang="lua">
 
testlabel = Geyser.Label:new({
 
testlabel = Geyser.Label:new({
 
   name = "testlabel",
 
   name = "testlabel",
Line 160: Line 164:
 
}, left_container_bottom) -- this is where we tell it what container to go into
 
}, left_container_bottom) -- this is where we tell it what container to go into
 
testlabel:setColor(0,255,0,150)
 
testlabel:setColor(0,255,0,150)
</lua>
+
</syntaxhighlight>
  
 
That label is exactly the same as the one above that goes across the screen, except it's in our bottom-left container - so it looks appropriately different:
 
That label is exactly the same as the one above that goes across the screen, except it's in our bottom-left container - so it looks appropriately different:
Line 166: Line 170:
 
[[File:Label in a container.png|center]]
 
[[File:Label in a container.png|center]]
  
==== Image on a label ====
+
=== Image on a label ===
 
One of the more amazing things labels allow you to do is put pictures anywhere on your Mudlet screen, that blend in very well. To do so, once the label is created, use the [http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html#Geyser.Label:setBackgroundImage setBackgroundImage()] function with the exact path to the image ([[File:Skullface.png]]):
 
One of the more amazing things labels allow you to do is put pictures anywhere on your Mudlet screen, that blend in very well. To do so, once the label is created, use the [http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html#Geyser.Label:setBackgroundImage setBackgroundImage()] function with the exact path to the image ([[File:Skullface.png]]):
  
<lua>
+
<syntaxhighlight lang="lua">
 
picture_label = Geyser.Label:new({
 
picture_label = Geyser.Label:new({
 
   name = "picture_label",
 
   name = "picture_label",
Line 176: Line 180:
 
})
 
})
 
picture_label:setBackgroundImage([[/home/vadi/Desktop/skullface.png]]) -- update location to actual image location on your computer
 
picture_label:setBackgroundImage([[/home/vadi/Desktop/skullface.png]]) -- update location to actual image location on your computer
</lua>
+
</syntaxhighlight>
  
 
This'll plop the picture to the bottom-left of your screen. To make the picture show, download the skullface picture above - save it to your desktop, and adjust the location of the image within [[]]'s to what it is on your computer. For example, if you saved this on your Windows 7 desktop, it would be:
 
This'll plop the picture to the bottom-left of your screen. To make the picture show, download the skullface picture above - save it to your desktop, and adjust the location of the image within [[]]'s to what it is on your computer. For example, if you saved this on your Windows 7 desktop, it would be:
  
<lua>
+
<syntaxhighlight lang="lua">
 
picture_label:setBackgroundImage([[C:/Users/<your user name>/Desktop/skullface.png]])
 
picture_label:setBackgroundImage([[C:/Users/<your user name>/Desktop/skullface.png]])
</lua>
+
</syntaxhighlight>
  
 
(yes, that's / and not \ - \ has been known not to work)
 
(yes, that's / and not \ - \ has been known not to work)
Line 188: Line 192:
 
If you saved this on your Mac desktop, it would be:
 
If you saved this on your Mac desktop, it would be:
  
<lua>
+
<syntaxhighlight lang="lua">
 
picture_label:setBackgroundImage([[/Users/<your user name>/Desktop/skullface.png]])
 
picture_label:setBackgroundImage([[/Users/<your user name>/Desktop/skullface.png]])
</lua>
+
</syntaxhighlight>
  
 
If you saved this on your Ubuntu desktop, it would be:
 
If you saved this on your Ubuntu desktop, it would be:
  
<lua>
+
<syntaxhighlight lang="lua">
 
picture_label:setBackgroundImage([[/home/<your user name>/Desktop/skullface.png]])
 
picture_label:setBackgroundImage([[/home/<your user name>/Desktop/skullface.png]])
</lua>
+
</syntaxhighlight>
  
 
Using this basic building block, you can work up to making yourself a UI!
 
Using this basic building block, you can work up to making yourself a UI!
  
==== Stretching an image on a label ====
+
=== Stretching an image on a label ===
 
If you'd like your image not to keep it's original size, but instead use up the available space of the label - you can use the [http://doc.qt.io/qt-5/stylesheet-reference.html#border-image border-image] stylesheet property to do so.
 
If you'd like your image not to keep it's original size, but instead use up the available space of the label - you can use the [http://doc.qt.io/qt-5/stylesheet-reference.html#border-image border-image] stylesheet property to do so.
  
<lua>
+
<syntaxhighlight lang="lua">
 
label = Geyser.Label:new({
 
label = Geyser.Label:new({
 
   name = "label",
 
   name = "label",
Line 215: Line 219:
 
   border-image: url(/home/vadi/Desktop/iso-avatar-draft_0.png);
 
   border-image: url(/home/vadi/Desktop/iso-avatar-draft_0.png);
 
]]
 
]]
</lua>
+
</syntaxhighlight>
 +
 
 +
{{note}} If you're on a Mudlet earlier than 3.15 and are having difficulty with the image coming up, it may be because of strange differences between Qt's CSS engine which does not affect mudlet's Lua. You may want to try appending :gsub("\\","/") to your string including getMudletHomeDir() (e.g. <code>getMudletHomeDir():gsub("\\","/")</code>). No longer necessary after Mudlet 3.15.
  
==== Aligning an image within a label ====
+
=== Aligning an image within a label ===
 
You can use background-image in combination with background-position to align an image within a label (if, say, the image is much smaller than the label).
 
You can use background-image in combination with background-position to align an image within a label (if, say, the image is much smaller than the label).
  
<lua>
+
<syntaxhighlight lang="lua">
 
-- this will set and align an image top-right of the label
 
-- this will set and align an image top-right of the label
 
if stunning then
 
if stunning then
Line 233: Line 239:
 
   ]])
 
   ]])
 
end
 
end
</lua>
+
</syntaxhighlight>
  
==== Showing / hiding a label ====
+
=== Showing / hiding a label ===
 
You can show and hide labels, as you can any container, miniconsole or a gauge in Geyser with [http://www.mudlet.org/geyser/files/geyser/GeyserContainer.html#Geyser.Container:show Geyser.Container:show()] and [http://www.mudlet.org/geyser/files/geyser/GeyserContainer.html#Geyser.Container:hide Geyser.Container:hide()]. Remember that since labels are a type of a container, all container functions work on them.
 
You can show and hide labels, as you can any container, miniconsole or a gauge in Geyser with [http://www.mudlet.org/geyser/files/geyser/GeyserContainer.html#Geyser.Container:show Geyser.Container:show()] and [http://www.mudlet.org/geyser/files/geyser/GeyserContainer.html#Geyser.Container:hide Geyser.Container:hide()]. Remember that since labels are a type of a container, all container functions work on them.
  
 
Hiding a label will allow you to click through on what is below the label, as well as free up the visual space for something else.
 
Hiding a label will allow you to click through on what is below the label, as well as free up the visual space for something else.
  
<lua>
+
<syntaxhighlight lang="lua">
 
testlabel = Geyser.Label:new({
 
testlabel = Geyser.Label:new({
 
   name = "testlabel",
 
   name = "testlabel",
Line 255: Line 261:
 
-- show the label with:
 
-- show the label with:
 
testlabel:show()
 
testlabel:show()
</lua>
+
</syntaxhighlight>
  
==== Clickable images ====
+
=== Clickable images ===
 
Tacking onto the fact that you can plop images anywhere on your Mudlet screen now, you can also make them react to your clicks. You can do so with the [http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html#Geyser.Label:setClickCallback setClickCallback()] function - by giving it a function to call when your label is clicked, you'll make it react.
 
Tacking onto the fact that you can plop images anywhere on your Mudlet screen now, you can also make them react to your clicks. You can do so with the [http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html#Geyser.Label:setClickCallback setClickCallback()] function - by giving it a function to call when your label is clicked, you'll make it react.
  
<lua>
+
<syntaxhighlight lang="lua">
 
picture_label = Geyser.Label:new({
 
picture_label = Geyser.Label:new({
 
   name = "picture_label",
 
   name = "picture_label",
Line 272: Line 278:
 
   send("say BOOM!")
 
   send("say BOOM!")
 
end
 
end
</lua>
+
</syntaxhighlight>
  
 
That's it! Pressing on the image will make the ''on_bomb_press()'' function go off, which will do its code of ''send("say BOOM!")''. Download the picture for use [http://opengameart.org/content/missile-rts-icon here].
 
That's it! Pressing on the image will make the ''on_bomb_press()'' function go off, which will do its code of ''send("say BOOM!")''. Download the picture for use [http://opengameart.org/content/missile-rts-icon here].
Line 278: Line 284:
 
[[File:Clickable_image.png|500px|center]]
 
[[File:Clickable_image.png|500px|center]]
  
==== Styling labels ====
+
=== Styling labels ===
 
Besides putting text or images on labels, you can also style them using Qt's stylesheets feature. Doing so allows you to create various graphics that make the label look more appealing:
 
Besides putting text or images on labels, you can also style them using Qt's stylesheets feature. Doing so allows you to create various graphics that make the label look more appealing:
  
Line 285: Line 291:
 
To set a stylesheet on a label, use the [http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html#Geyser.Label:setStyleSheet Geyser.Label:setStyleSheet()] function on your label, describing the stylesheet you'd like to give it. A stylesheet consists of properties you set - for example the background color, borders, padding, and so forth. You describe properties in the following format: ''property name''''':'''''values''''';'''. See here for a [http://doc.qt.io/qt-5/stylesheet-reference.html#list-of-properties list of all supported properties]. For example, to make your labels background be yellow, you'd use the background-color property:
 
To set a stylesheet on a label, use the [http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html#Geyser.Label:setStyleSheet Geyser.Label:setStyleSheet()] function on your label, describing the stylesheet you'd like to give it. A stylesheet consists of properties you set - for example the background color, borders, padding, and so forth. You describe properties in the following format: ''property name''''':'''''values''''';'''. See here for a [http://doc.qt.io/qt-5/stylesheet-reference.html#list-of-properties list of all supported properties]. For example, to make your labels background be yellow, you'd use the background-color property:
  
<lua>
+
<syntaxhighlight lang="lua">
 
mylabel = Geyser.Label:new({
 
mylabel = Geyser.Label:new({
 
   x = "50%", y = "50%",
 
   x = "50%", y = "50%",
Line 294: Line 300:
 
   background-color: yellow;
 
   background-color: yellow;
 
]])
 
]])
</lua>
+
</syntaxhighlight>
  
 
[[File:Basic_stylesheet.png|center]]
 
[[File:Basic_stylesheet.png|center]]
Line 302: Line 308:
 
Scrolling down the list of properties, you'll come along a border one. Plopping it into our stylesheet nets the following:
 
Scrolling down the list of properties, you'll come along a border one. Plopping it into our stylesheet nets the following:
  
<lua>
+
<syntaxhighlight lang="lua">
 
mylabel:setStyleSheet([[
 
mylabel:setStyleSheet([[
 
   background-color: yellow;
 
   background-color: yellow;
 
   border: 5px solid white;
 
   border: 5px solid white;
 
]])
 
]])
</lua>
+
</syntaxhighlight>
  
 
[[File:Basic_stylesheet_border.png|center]]
 
[[File:Basic_stylesheet_border.png|center]]
Line 315: Line 321:
 
Fiddling with it some more and applying new properties we find on that page, we get a rounded border on our label:
 
Fiddling with it some more and applying new properties we find on that page, we get a rounded border on our label:
  
<lua>
+
<syntaxhighlight lang="lua">
 
mylabel:setStyleSheet([[
 
mylabel:setStyleSheet([[
 
   background-color: grey;
 
   background-color: grey;
Line 323: Line 329:
 
   border-radius: 10px;
 
   border-radius: 10px;
 
]])
 
]])
</lua>
+
</syntaxhighlight>
  
 
[[File:Basic_stylesheet_border_radius.png|center]]
 
[[File:Basic_stylesheet_border_radius.png|center]]
Line 329: Line 335:
 
Which'll conclude our exploration for now. Try out all of the other possible options available there - there's loads, from [http://doc.qt.io/qt-5/stylesheet-reference.html#border-style funky borders], to tiling images and fancy color combinations using gradients.
 
Which'll conclude our exploration for now. Try out all of the other possible options available there - there's loads, from [http://doc.qt.io/qt-5/stylesheet-reference.html#border-style funky borders], to tiling images and fancy color combinations using gradients.
  
==== Aligning text/images inside a label ====
+
=== Adding a tooltip to a label ===
 +
 
 +
Since Mudlet 4.6, you can now add a tooltip to labels and gauges. You can start by making a simple label and echoing some text to it:
 +
 
 +
<syntaxhighlight lang="lua">
 +
testLabel = Geyser.Label:new({
 +
  name = "testLabel",
 +
  x = "50%",
 +
  y = "50%",
 +
  height = "25%",
 +
  width = "25%",
 +
})
 +
testLabel:echo("This is on the label!")
 +
testLabel:setAlignment("center")
 +
-- sets the tooltip text
 +
testLabel:setToolTip("This is the tooltip", "10")
 +
-- and gives it some style!
 +
testLabel:setStyleSheet("QToolTip{background: yellow; color: blue; border:none;}")
 +
</syntaxhighlight>
 +
 
 +
Without tooltip
 +
[[File:TestLabelForTooltips.png|thumb|center]]
 +
 
 +
With tooltip
 +
 
 +
[[File:LabelTooltip.png|thumb|center]]
 +
 
 +
=== Aligning text/images inside a label ===
 
By default, text is [http://qt-project.org/doc/qt-5/qlabel.html#alignment-prop centered vertically and left aligned] in a label. To align it to a specific side, use the stylesheets we learnt about earlier with the qproperty-alignment:
 
By default, text is [http://qt-project.org/doc/qt-5/qlabel.html#alignment-prop centered vertically and left aligned] in a label. To align it to a specific side, use the stylesheets we learnt about earlier with the qproperty-alignment:
  
<lua>
+
<syntaxhighlight lang="lua">
 
mylabel = Geyser.Label:new({
 
mylabel = Geyser.Label:new({
 
   name = "testlabel",
 
   name = "testlabel",
Line 352: Line 385:
  
 
mylabel:echo("hi!")
 
mylabel:echo("hi!")
</lua>
+
</syntaxhighlight>
  
 
[[File:Text_aligned.png|center]]
 
[[File:Text_aligned.png|center]]
  
==== Enabling wordwrap in a label ====
+
=== Enabling wordwrap in a label ===
 
If you need to enable word wrapping in a label (which by default is off), add the following line to the labels stylesheet:
 
If you need to enable word wrapping in a label (which by default is off), add the following line to the labels stylesheet:
  
Line 363: Line 396:
 
As an example:
 
As an example:
  
<lua>
+
<syntaxhighlight lang="lua">
 
mylabel:setStyleSheet([[
 
mylabel:setStyleSheet([[
 
   qproperty-wordWrap: true;
 
   qproperty-wordWrap: true;
 
]])
 
]])
</lua>
+
</syntaxhighlight>
  
 
If you'd like to set multiple properties, set them all at once - not via multiple :setStyleSheet() calls:
 
If you'd like to set multiple properties, set them all at once - not via multiple :setStyleSheet() calls:
  
<lua>
+
<syntaxhighlight lang="lua">
 
mylabel:setStyleSheet([[
 
mylabel:setStyleSheet([[
 
   background: red;
 
   background: red;
 
]])
 
]])
</lua>
+
</syntaxhighlight>
  
==== Adding a hover effect to a label ====
+
=== Adding a hover effect to a label ===
 
The labels support adding stylesheets for specific cases, such as when a mouse is [http://doc.qt.io/qt-5/stylesheet-reference.html#hover-ps hovering] over them. To make this work, you provide CSS for when the label is in its usual state, and for when it is hovered over:
 
The labels support adding stylesheets for specific cases, such as when a mouse is [http://doc.qt.io/qt-5/stylesheet-reference.html#hover-ps hovering] over them. To make this work, you provide CSS for when the label is in its usual state, and for when it is hovered over:
  
<lua>
+
<syntaxhighlight lang="lua">
 
-- this example will add a border to the label when it is hovered over
 
-- this example will add a border to the label when it is hovered over
 
mylabell:setStyleSheet([[
 
mylabell:setStyleSheet([[
Line 390: Line 423:
 
   }
 
   }
 
]])
 
]])
</lua>
+
</syntaxhighlight>
  
==== Checkboxes ====
+
=== Checkboxes ===
 
Combining the fact that you can click on a label with an image to do something with the fact that you can change pictures on a label at will, you can make an image that changes itself when you click on it.
 
Combining the fact that you can click on a label with an image to do something with the fact that you can change pictures on a label at will, you can make an image that changes itself when you click on it.
  
<lua>
+
<syntaxhighlight lang="lua">
 
picture_label = Geyser.Label:new({
 
picture_label = Geyser.Label:new({
 
   name = "picture_label",
 
   name = "picture_label",
Line 420: Line 453:
 
   end
 
   end
 
end
 
end
</lua>
+
</syntaxhighlight>
  
 
The ''on_checkbox_press()'' function this time keeps the track of the checkbox with the ''checkbox_ticked'' variable and sets the image appropriately. You can download the ticked ([[File:Checkbox_ticked.png]]) and unticked images ([[File:Checkbox_unticked.png]]) or the [http://wiki.mudlet.org/images/6/6d/Checkbox.mpackage whole package] altogether.
 
The ''on_checkbox_press()'' function this time keeps the track of the checkbox with the ''checkbox_ticked'' variable and sets the image appropriately. You can download the ticked ([[File:Checkbox_ticked.png]]) and unticked images ([[File:Checkbox_unticked.png]]) or the [http://wiki.mudlet.org/images/6/6d/Checkbox.mpackage whole package] altogether.
Line 426: Line 459:
 
[[File:Checkbox_demo.png|500px|center]]
 
[[File:Checkbox_demo.png|500px|center]]
  
==== Animated labels ====
+
=== Animated labels ===
 
Using timers and several pictures, you can make your labels change quickly enough and look animated. Here's one such example:
 
Using timers and several pictures, you can make your labels change quickly enough and look animated. Here's one such example:
  
<lua>
+
<syntaxhighlight lang="lua">
 
picture_label = Geyser.Label:new({
 
picture_label = Geyser.Label:new({
 
   name = "picture_label",
 
   name = "picture_label",
Line 447: Line 480:
  
 
animate_santa()
 
animate_santa()
</lua>
+
</syntaxhighlight>
  
 
The completed package is available [http://wiki.mudlet.org/images/6/6b/Dancing-santa.mpackage here], install it and do '''start/end animation''' to watch.
 
The completed package is available [http://wiki.mudlet.org/images/6/6b/Dancing-santa.mpackage here], install it and do '''start/end animation''' to watch.
  
==== Inserting extra spaces and newlines ====
+
=== Inserting extra spaces and newlines ===
 
Echoing text into Mudlet and Geyser labels is different from miniconsoles and the main window, due to their nature. One of the differences is that extra spaces in a label, by default, get compressed down to one. '''To add extra spaces in a label''', replace extra spaces with '''&amp;nbsp;''' or by wrapping your text with them inside '''<nowiki><pre>my text here</pre></nowiki>'''.
 
Echoing text into Mudlet and Geyser labels is different from miniconsoles and the main window, due to their nature. One of the differences is that extra spaces in a label, by default, get compressed down to one. '''To add extra spaces in a label''', replace extra spaces with '''&amp;nbsp;''' or by wrapping your text with them inside '''<nowiki><pre>my text here</pre></nowiki>'''.
  
<lua>
+
<syntaxhighlight lang="lua">
 
-- this won't work, it'll show as one space:
 
-- this won't work, it'll show as one space:
 
mylabel:echo("You      ->      point")
 
mylabel:echo("You      ->      point")
Line 460: Line 493:
 
-- but this would, because it replaces all spaces with &nbsp before echoing
 
-- but this would, because it replaces all spaces with &nbsp before echoing
 
mylabel:echo(string.gsub("You      ->      point", " ", "&nbsp;"))
 
mylabel:echo(string.gsub("You      ->      point", " ", "&nbsp;"))
</lua>
+
</syntaxhighlight>
  
<lua>
+
<syntaxhighlight lang="lua">
 
-- here is another way to go about this - and it additionally makes the font be monospaced:
 
-- here is another way to go about this - and it additionally makes the font be monospaced:
 
mylabel:echo("<pre>You      ->      point</pre>")
 
mylabel:echo("<pre>You      ->      point</pre>")
</lua>
+
</syntaxhighlight>
  
 
'''To add a new line in a label''' (aka linebreak), use '''<br>''' (instead of ''\n'' as you are used to in an echo).
 
'''To add a new line in a label''' (aka linebreak), use '''<br>''' (instead of ''\n'' as you are used to in an echo).
<lua>
+
<syntaxhighlight lang="lua">
 
mylabel:echo("These<br>words<br>are<br>split")
 
mylabel:echo("These<br>words<br>are<br>split")
</lua>
+
</syntaxhighlight>
  
==== Transparent labels ====
+
=== Transparent labels ===
 
One of the possible ways of achieving transparency on a label is to add <code>background-color: rgba(0,0,0,0%);</code> to its stylesheet. Here's an example:
 
One of the possible ways of achieving transparency on a label is to add <code>background-color: rgba(0,0,0,0%);</code> to its stylesheet. Here's an example:
  
<lua>
+
<syntaxhighlight lang="lua">
 
my_transparent_label:setStyleSheet([[
 
my_transparent_label:setStyleSheet([[
 
   background-color: rgba(0,0,0,0%);
 
   background-color: rgba(0,0,0,0%);
 
]])
 
]])
</lua>
+
</syntaxhighlight>
 +
 
 +
=== Change Label Mouse Cursor ===
 +
Since Mudlet 4.7 it is possible to change the shape of your mouse cursor if you put it over your Label by using for example:
 +
<syntaxhighlight lang="lua">
 +
mylabel:setCursor("Forbidden") -- will change your mousecursor to a forbidden cursor
 +
</syntaxhighlight>
 +
Possible cursor shapes are [[CursorShapes| available here]].
 +
 
 +
It is also possible to change the mouse cursor to a custom made cursor by:
 +
<syntaxhighlight lang="lua">
 +
mylabel:setCustomCursor(getMudletHomeDir().."/custom_cursor.png")
 +
</syntaxhighlight>
 +
It is recommended the the custom cursor is a png with size of 32x32 to be supported on all systems.
  
==== Flyout Labels ====
+
[[File:Changecursoroverlabel.gif]]
 +
 
 +
=== Flyout Labels ===
  
 
Flyout labels allow you to create 'dropdown' or 'flyout' menus - menus that reveal more items once you hover your mouse over them. To create flyout labels:
 
Flyout labels allow you to create 'dropdown' or 'flyout' menus - menus that reveal more items once you hover your mouse over them. To create flyout labels:
# add <code>nestable=true</code> to your main label.
+
# add <code>nestable=true</code> (left click to open menu) or <code>nestflyout=true</code> (mouse hover to open menu) to your main label.
 
# use [http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html#Geyser.Label:addChild :addChild()] on your main label to add flyout labels to it.
 
# use [http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html#Geyser.Label:addChild :addChild()] on your main label to add flyout labels to it.
 
## [http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html#Geyser.Label:addChild :addChild()] uses the same arguments as when creating a new label but also takes the '''layoutDir''' option to specify in which direction and axis should the labels align, where 2 letters combine into the option: first letter R for right, L for left, T for top, B for bottom, followed by the orientation: V for vertical or H for horizontal. So options are: <code>layoutDir="RV"</code>, <code>layoutDir="RH"</code>, <code>layoutDir="LV"</code>, <code>layoutDir="LH"</code>, and so on.
 
## [http://www.mudlet.org/geyser/files/geyser/GeyserLabel.html#Geyser.Label:addChild :addChild()] uses the same arguments as when creating a new label but also takes the '''layoutDir''' option to specify in which direction and axis should the labels align, where 2 letters combine into the option: first letter R for right, L for left, T for top, B for bottom, followed by the orientation: V for vertical or H for horizontal. So options are: <code>layoutDir="RV"</code>, <code>layoutDir="RH"</code>, <code>layoutDir="LV"</code>, <code>layoutDir="LH"</code>, and so on.
Line 493: Line 541:
 
{{note}} Requires Mudlet 3.0.
 
{{note}} Requires Mudlet 3.0.
  
===== Demo =====
+
==== Demo ====
 
Here's an example that follows the steps above:
 
Here's an example that follows the steps above:
  
<lua>
+
<syntaxhighlight lang="lua">
 
label0 = Geyser.Label:new({name="label0",  
 
label0 = Geyser.Label:new({name="label0",  
 
   x="50%",y="50%",height=50,width=300,nestable=true,  
 
   x="50%",y="50%",height=50,width=300,nestable=true,  
Line 510: Line 558:
 
label3 = label0:addChild({name="label3",height=30,width=70, layoutDir="RV", flyOut=true, message="label three"})
 
label3 = label0:addChild({name="label3",height=30,width=70, layoutDir="RV", flyOut=true, message="label three"})
 
label3:setStyleSheet([[background-color: red;  border-width: 2px;  border-style: solid;  border-color: blue;  border-radius: 2px;  font-size: 7pt;]])
 
label3:setStyleSheet([[background-color: red;  border-width: 2px;  border-style: solid;  border-color: blue;  border-radius: 2px;  font-size: 7pt;]])
</lua>
+
</syntaxhighlight>
  
 
A more thorough example. Try it out to see what you can create with flyout labels:
 
A more thorough example. Try it out to see what you can create with flyout labels:
<lua>
+
<syntaxhighlight lang="lua">
 
-- create a label with a nestable=true property to say that it can nest labels
 
-- create a label with a nestable=true property to say that it can nest labels
mainlabel = Geyser.Label:new({name="testa", x=400,y=50,height=50,width=300,nestable=true, message="<center>CLICK ME TO SEE FLY-OUT LABELS!</center>"})
+
mainlabel = Geyser.Label:new({name="testa", x=400,y=50,height=50,width=300,nestflyout=true, message="<center>HOVER HERE TO SEE FLY-OUT LABELS!</center>"})
 
   
 
   
 
-- create 15 labels and store them in a table  
 
-- create 15 labels and store them in a table  
Line 541: Line 589:
 
   display(name)
 
   display(name)
 
end
 
end
</lua>
+
</syntaxhighlight>
  
 
It'll look something like this:  
 
It'll look something like this:  
Line 547: Line 595:
 
[[File:Flyout_labels_demo.png|150px]]
 
[[File:Flyout_labels_demo.png|150px]]
  
===== Demo of layouts =====
+
==== Demo of layouts ====
 
Here's another demo that explains all of the layout styles quite well:
 
Here's another demo that explains all of the layout styles quite well:
<lua>
+
<syntaxhighlight lang="lua">
 
local directions = {"R", "L", "T", "B"}
 
local directions = {"R", "L", "T", "B"}
 
local orientations = {"V", "H"}
 
local orientations = {"V", "H"}
Line 562: Line 610:
  
 
local function get_foreground_text_colour(r,g,b)
 
local function get_foreground_text_colour(r,g,b)
   local luminosity = (0.2126 * ((r/255)^2.2)) + (0.7152 * ((g/255)^2.2)) + (0.0722 * ((b /255)^2.2))
+
   local luminosity = (0.2126 * ((r/255)^2.2)) + (0.7152 * ((g/255)^2.2)) + (0.0722 * ((b /255)^2.2))
 
   if luminosity > 0.5 then
 
   if luminosity > 0.5 then
 
     return "black"
 
     return "black"
Line 575: Line 623:
  
 
-- create a label with a nestable=true property to say that it can nest labels
 
-- create a label with a nestable=true property to say that it can nest labels
all_possible_combinations_label = Geyser.Label:new({name="all_possible_combinations_label", x=400,y="-200",height=50,width=500,
+
all_possible_combinations_label = Geyser.Label:new({name="all_possible_combinations_label", x=0,y="-400",height=50,width=500,
   nestable=true, message="<center>Click to see a listing of possible combinations</center>"})
+
   nestable = true, message="<center>Click to see a listing of possible combinations</center>"})
  
 
for i = 1, #combinations do
 
for i = 1, #combinations do
 
   local combination = combinations[i]
 
   local combination = combinations[i]
   combination_labels[i] = all_possible_combinations_label:addChild({name="combo_"..combination,height=30,width=150, layoutDir="BH", flyOut=false, message="<center>Combination "..combination.."</center>"})
+
   combination_labels[i] = all_possible_combinations_label:addChild({name="combo_"..combination,height=30,width=150, nestable = true, flyOut=true, layoutDir="BH", message="<center>Combination "..combination.."</center>"})
 
   
 
   
 
   local r,g,b = get_random_colour_rgb()
 
   local r,g,b = get_random_colour_rgb()
Line 588: Line 636:
 
   for ii = 1, 3 do
 
   for ii = 1, 3 do
 
     combination_labels_children[ii] = combination_labels[i]:addChild({
 
     combination_labels_children[ii] = combination_labels[i]:addChild({
       name="combo_"..combination.."_"..ii, height = 30, width = 150, layoutDir=combination,
+
       name="combo_"..combination.."_"..ii, height = 30, width = 150, layoutDir=combination, flyOut = true,
      flyOut = false, message = string.format("<center><b>%s</b>%s+<b>%s</b>%s layout</center>",  
+
        message = string.format("<center><b>%s</b>%s+<b>%s</b>%s layout</center>",  
 
         combination:sub(1,1), mappings[combination:sub(1,1)]:sub(2), combination:sub(2,2), mappings[combination:sub(2,2)]:sub(2)),
 
         combination:sub(1,1), mappings[combination:sub(1,1)]:sub(2), combination:sub(2,2), mappings[combination:sub(2,2)]:sub(2)),
 
       fgColor = text_colour})
 
       fgColor = text_colour})
Line 596: Line 644:
 
   end
 
   end
 
end
 
end
</lua>
+
</syntaxhighlight>
  
 
It'll look like this:
 
It'll look like this:
Line 602: Line 650:
 
[[File:Flyoutlabels-layout-demo.png]]
 
[[File:Flyoutlabels-layout-demo.png]]
  
===[http://www.mudlet.org/geyser/files/geyser/GeyserMiniConsole.html Geyser.MiniConsole]===
+
=== Background for Mudlets buttons ===
 +
You can give Mudlets buttons a background to have them blend in with your UI by doing this:
 +
 
 +
<syntaxhighlight lang="lua">
 +
-- replace the /home/vadi/Pictures/tile.png location below with the one of your picture!
 +
-- you can download the sample tile.png from https://opengameart.org/content/bevouliin-free-game-background-for-game-developers
 +
local backgroundpath = [[/home/vadi/Pictures/tile.png]]
 +
-- Windows:
 +
-- local backgroundpath = [[C:/Users/Vadim/Downloads/Free game background/transparent PNG/tile.png]]
 +
 
 +
setAppStyleSheet([[
 +
QToolBar {
 +
  border-image: url(]]..backgroundpath..[[);
 +
 
 +
}
 +
 
 +
QToolBar QToolButton:!hover {
 +
  color: white;
 +
}
 +
QToolBar QToolButton:hover {
 +
  color: black;
 +
}
 +
]])
 +
</syntaxhighlight>
 +
 
 +
Result:
 +
 
 +
[[File:Mudlet tiled buttons.png|frame|left]]
 +
<br clear=all>
 +
 
 +
==[http://www.mudlet.org/geyser/files/geyser/GeyserMiniConsole.html Geyser.MiniConsole]==
 
This allows you to spawn a Mudlet miniconsole - unlike labels, these aren't as styleable, but they do format text better. They make a good fit for text-based menus, chat and map capture, and other things.
 
This allows you to spawn a Mudlet miniconsole - unlike labels, these aren't as styleable, but they do format text better. They make a good fit for text-based menus, chat and map capture, and other things.
  
Spawning one is very similar to other Geyser elements:
+
Spawning one is very similar to other Geyser elements - paste this into a new script:
<lua>
+
<syntaxhighlight lang="lua">
 
HelloWorld = Geyser.MiniConsole:new({
 
HelloWorld = Geyser.MiniConsole:new({
 
   name="HelloWorld",
 
   name="HelloWorld",
 
   x="70%", y="50%",
 
   x="70%", y="50%",
 +
  autoWrap = true,
 +
  color = "black",
 +
  scrollBar = false,
 +
  fontSize = 8,
 
   width="30%", height="50%",
 
   width="30%", height="50%",
 
})
 
})
</lua>
+
</syntaxhighlight>
  
 
This'll make you one at the bottom-right of the screen. The miniconsole will have a grey background by default, but you can set it to any color you'd like with [http://www.mudlet.org/geyser/files/geyser/GeyserWindow.html#Geyser.Window:setColor miniconsole:setColor()]:
 
This'll make you one at the bottom-right of the screen. The miniconsole will have a grey background by default, but you can set it to any color you'd like with [http://www.mudlet.org/geyser/files/geyser/GeyserWindow.html#Geyser.Window:setColor miniconsole:setColor()]:
  
<lua>
+
<syntaxhighlight lang="lua">
 
HelloWorld:setColor("black") -- give it a nice black background
 
HelloWorld:setColor("black") -- give it a nice black background
</lua>
+
</syntaxhighlight>
  
 
A special dimension property that MiniConsoles have is a character - instead of specifying a miniconsole to be % of a container or a certain number of pixels, you can specify it as a certain number of characters. You do this by using "c" at the end of a number. This way, you can, for example, specify miniconsole to be 10 letters long and 2 lines high:
 
A special dimension property that MiniConsoles have is a character - instead of specifying a miniconsole to be % of a container or a certain number of pixels, you can specify it as a certain number of characters. You do this by using "c" at the end of a number. This way, you can, for example, specify miniconsole to be 10 letters long and 2 lines high:
  
<lua>
+
<syntaxhighlight lang="lua">
 
flatbox = Geyser.MiniConsole:new({
 
flatbox = Geyser.MiniConsole:new({
 
   name="flatbox",
 
   name="flatbox",
 
   x="70%", y="50%",
 
   x="70%", y="50%",
 +
  wrapAt = 10,
 
   width="10c", height="2c",
 
   width="10c", height="2c",
 
})
 
})
 
flatbox:setColor("red")
 
flatbox:setColor("red")
 
flatbox:echo("ABCDEFGHIJ") -- that is 10 letters
 
flatbox:echo("ABCDEFGHIJ") -- that is 10 letters
</lua>
+
</syntaxhighlight>
  
==== Adding text ====
+
=== Adding text ===
 
You can use [[Manual:Technical_Manual#echo|echo()]] the same way with a miniconsole to add text as to the usual window:
 
You can use [[Manual:Technical_Manual#echo|echo()]] the same way with a miniconsole to add text as to the usual window:
  
<lua>
+
<syntaxhighlight lang="lua">
 
HelloWorld:echo("hello!")
 
HelloWorld:echo("hello!")
</lua>
+
</syntaxhighlight>
  
 
As well as [[Manual:Technical_Manual#cecho|cecho]], [[Manual:Technical_Manual#decho|decho]], or [[Manual:Technical_Manual#hecho|hecho]]:
 
As well as [[Manual:Technical_Manual#cecho|cecho]], [[Manual:Technical_Manual#decho|decho]], or [[Manual:Technical_Manual#hecho|hecho]]:
  
<lua>
+
<syntaxhighlight lang="lua">
 
HelloWorld:cecho("<green>hey, <blue>colored <red>text!\n")
 
HelloWorld:cecho("<green>hey, <blue>colored <red>text!\n")
</lua>
+
</syntaxhighlight>
  
==== Copying lines with color ====
+
=== Copying lines with color ===
To copy a line over to the miniconsole, as it is from the game with all colors preserved, you just select, copy, and append it. For an example, try making a trigger with this as the '''''Lua function''''' '''pattern type''':
+
To copy a line over to the miniconsole, as it is from the game with all colors preserved, you can [[Manual:UI_Functions#selectCurrentLine|select]], [[Manual:UI_Functions#copy|copy]], and [[Manual:UI_Functions#appendBuffer|append]] it. For an example, try making a trigger with this as the ''Lua function'' pattern type:
  
<lua>
+
<syntaxhighlight lang="lua">
 
return true
 
return true
</lua>
+
</syntaxhighlight>
  
That'll make the trigger go off on every line. Then give it the following script:
+
That'll make the trigger go off on every line. Then give it the following script (assumed you have made the HelloWorld miniconsole from earlier):
<lua>
+
<syntaxhighlight lang="lua">
 
selectCurrentLine()
 
selectCurrentLine()
 
copy()
 
copy()
appendBuffer("HelloWorld")
+
HelloWorld:appendBuffer()
</lua>
+
</syntaxhighlight>
  
 
... and you'll see all MUD output duplicated exactly as it is to the miniconsole. Amazing! It's very efficient as well, so you can have many miniconsoles, even in spam, not lag you down.
 
... and you'll see all MUD output duplicated exactly as it is to the miniconsole. Amazing! It's very efficient as well, so you can have many miniconsoles, even in spam, not lag you down.
  
==== Doing edits in copied lines ====
+
=== Doing edits in copied lines ===
 
Sometimes you'll want to edit the line before stuffing it into the miniconsole. For example, if you're making a chat capture, you'd want to condense a really long org name into something that's more space-friendly.
 
Sometimes you'll want to edit the line before stuffing it into the miniconsole. For example, if you're making a chat capture, you'd want to condense a really long org name into something that's more space-friendly.
  
 
To do so, you'd use the [[Manual:Technical_Manual#selectString|selectString()]] the text you'd like to modify, [[Manual:Technical_Manual#replace|replace()]] it with a different one:
 
To do so, you'd use the [[Manual:Technical_Manual#selectString|selectString()]] the text you'd like to modify, [[Manual:Technical_Manual#replace|replace()]] it with a different one:
  
<lua>
+
<syntaxhighlight lang="lua">
 
selectString("Your", 1)  -- select the word you'd like to replace - in this case, 'Your'
 
selectString("Your", 1)  -- select the word you'd like to replace - in this case, 'Your'
 
setBgColor(getBgColor()) -- preserve the background color in the replacement
 
setBgColor(getBgColor()) -- preserve the background color in the replacement
Line 674: Line 757:
 
selectCurrentLine()
 
selectCurrentLine()
 
copy()
 
copy()
appendBuffer("HelloWorld")
+
HellowWorld:appendBuffer()
</lua>
+
</syntaxhighlight>
  
==== Gagging from the main window ====
+
=== Gagging from the main window ===
 
If you'd like to gag the line from the main window so it only shows up in your miniconsole, [[Manual:Technical_Manual#deleteLine|delete]] it after moving it over:
 
If you'd like to gag the line from the main window so it only shows up in your miniconsole, [[Manual:Technical_Manual#deleteLine|delete]] it after moving it over:
  
<lua>
+
<syntaxhighlight lang="lua">
 
selectCurrentLine()
 
selectCurrentLine()
 
copy()
 
copy()
appendBuffer("HelloWorld")
+
HellowWorld:appendBuffer()
 
deleteLine()
 
deleteLine()
</lua>
+
</syntaxhighlight>
  
==== Clickable menus ====
+
=== Clickable menus ===
 
Using the [[Manual:Technical_Manual#echoLink|echoLink]], [[Manual:Technical_Manual#insertLink|insertLink]] and [[Manual:Technical_Manual#setLink|setLink]] functions, you can turn text into one that reacts on a click. Combined with your power of placing text anywhere on the screen with a miniconsole, you can make menus with options. Here is one such example, where selecting an item causes an echo to happen:
 
Using the [[Manual:Technical_Manual#echoLink|echoLink]], [[Manual:Technical_Manual#insertLink|insertLink]] and [[Manual:Technical_Manual#setLink|setLink]] functions, you can turn text into one that reacts on a click. Combined with your power of placing text anywhere on the screen with a miniconsole, you can make menus with options. Here is one such example, where selecting an item causes an echo to happen:
  
<lua>
+
<syntaxhighlight lang="lua">
 
flatbox = Geyser.MiniConsole:new({
 
flatbox = Geyser.MiniConsole:new({
 
   name="flatbox",
 
   name="flatbox",
Line 701: Line 784:
 
flatbox:cecho("<white:red>Choose one of the following options:\n")
 
flatbox:cecho("<white:red>Choose one of the following options:\n")
  
setFgColor("flatbox", 255,255,255)
+
flatbox:fg("white")
setBgColor("flatbox", 255,0,0)
+
flatbox:bg("red")
  
 
for _, fruit in ipairs{"banana", "apple", "orange"} do
 
for _, fruit in ipairs{"banana", "apple", "orange"} do
Line 709: Line 792:
  
 
resetFormat()
 
resetFormat()
</lua>
+
</syntaxhighlight>
  
 
Which'll look something like the following:
 
Which'll look something like the following:
Line 715: Line 798:
 
[[File:Fruit_menu.png|center]]
 
[[File:Fruit_menu.png|center]]
  
===[http://www.mudlet.org/geyser/files/geyser/GeyserGauge.html Geyser.Gauge]===
+
==[http://www.mudlet.org/geyser/files/geyser/GeyserGauge.html Geyser.Gauge]==
 
<!--
 
<!--
 
This is a composite window. Gauge duplicates the functionality of the built in Mudlet gauges, but in a clean and easily extended way. Internally, a Geyser Gauge is a container holding two Labels, front and back, which are initially scaled to fill the entire Gauge container. Hence, a gauge, g, can be given callbacks with the g.front:setClickCallback() method.
 
This is a composite window. Gauge duplicates the functionality of the built in Mudlet gauges, but in a clean and easily extended way. Internally, a Geyser Gauge is a container holding two Labels, front and back, which are initially scaled to fill the entire Gauge container. Hence, a gauge, g, can be given callbacks with the g.front:setClickCallback() method.
Line 724: Line 807:
 
A Gauge allows you to represent numbers on a scale - and most typically, you've seen it be used as your standard hp/mana/whatever bar. A basic bar is made similarly to other Geyser elements. To set the value on the gauge that it should represent, use the [http://www.mudlet.org/geyser/files/geyser/GeyserGauge.html#Geyser.Gauge:setValue setValue()] function:
 
A Gauge allows you to represent numbers on a scale - and most typically, you've seen it be used as your standard hp/mana/whatever bar. A basic bar is made similarly to other Geyser elements. To set the value on the gauge that it should represent, use the [http://www.mudlet.org/geyser/files/geyser/GeyserGauge.html#Geyser.Gauge:setValue setValue()] function:
  
<lua>
+
<syntaxhighlight lang="lua">
 
hpbar = Geyser.Gauge:new({
 
hpbar = Geyser.Gauge:new({
 
   name="hpbar",
 
   name="hpbar",
Line 731: Line 814:
 
})
 
})
 
hpbar:setValue(math.random(1,100),100)
 
hpbar:setValue(math.random(1,100),100)
</lua>
+
</syntaxhighlight>
  
 
That'll spawn you a pretty basic gauge with a horizontal orientation and a grey colour - and as a test, with a random value.
 
That'll spawn you a pretty basic gauge with a horizontal orientation and a grey colour - and as a test, with a random value.
Line 737: Line 820:
 
[[File:Basic_gauge.png|center]]
 
[[File:Basic_gauge.png|center]]
  
==== Updating a gauge ====
+
=== Updating a gauge ===
 
You'd want your gauge to stay in sync with your actual values. To make that happen, you want to call [http://www.mudlet.org/geyser/files/geyser/GeyserGauge.html#Geyser.Gauge:setValue setValue()] whenever the value that the gauge is tracking changes.
 
You'd want your gauge to stay in sync with your actual values. To make that happen, you want to call [http://www.mudlet.org/geyser/files/geyser/GeyserGauge.html#Geyser.Gauge:setValue setValue()] whenever the value that the gauge is tracking changes.
  
 
So for example, if you make a health bar - wherever you get your new health at (be it prompt, gmcp, atcp or whatever), update the gauge as well:
 
So for example, if you make a health bar - wherever you get your new health at (be it prompt, gmcp, atcp or whatever), update the gauge as well:
  
<lua>
+
<syntaxhighlight lang="lua">
 
-- theoretical example
 
-- theoretical example
 
current_health, max_health = tonumber(matches[2]), tonumber(matches[3])
 
current_health, max_health = tonumber(matches[2]), tonumber(matches[3])
Line 748: Line 831:
 
-- update the bar
 
-- update the bar
 
hp_bar:setValue(current_health, max_health)
 
hp_bar:setValue(current_health, max_health)
</lua>
+
</syntaxhighlight>
  
 
You can also write down how much health have you got on the bar with:
 
You can also write down how much health have you got on the bar with:
  
<lua>
+
<syntaxhighlight lang="lua">
 
lua local hp = math.random(1,100)  
 
lua local hp = math.random(1,100)  
 
hpbar:setValue(current_health, max_health, "<b>"..max_health.."hp</b>")
 
hpbar:setValue(current_health, max_health, "<b>"..max_health.."hp</b>")
</lua>
+
 
 +
-- example using GMCP in IRE games:
 +
hpbar:setValue((100/gmcp.Char.Vitals.maxhp)*gmcp.Char.Vitals.hp,100,gmcp.Char.Vitals.hp)
 +
</syntaxhighlight>
  
 
[[File:Hpbar_basic.png|center]]
 
[[File:Hpbar_basic.png|center]]
  
==== Styling a gauge ====
+
=== Styling a gauge ===
The Geyser gauge is composed of two labels - one is called ''mygauge.front'' and the other is ''mygauge.back''. Combining this with Geyser:Label.setStyleSheet, you can improve the visuals of your gauges by using Qt-supported CSS. The syntax for specifying CSS is a bit different - it requires a semicolon after every property, and is done in the format of ''property name''''':'''''values''''';'''. A list of all possible properties you can use is [http://doc.qt.io/qt-5/stylesheet-reference.html#list-of-properties available here]. Practical example:
+
The Geyser gauge is composed of three labels - one is called ''mygauge.front'', ''mygauge.back'' and ''mygauge.text''. Combining this with Geyser:Label.setStyleSheet, you can improve the visuals of your gauges by using Qt-supported CSS. The syntax for specifying CSS is a bit different - it requires a semicolon after every property, and is done in the format of ''property name''''':'''''values''''';'''. A list of all possible properties you can use is [http://doc.qt.io/qt-5/stylesheet-reference.html#list-of-properties available here] and you can use [https://build-system.fman.io/qt-designer-download Qt Designer] to create them. Practical example:
  
<lua>
+
<syntaxhighlight lang="lua">
 
hpbar = Geyser.Gauge:new({
 
hpbar = Geyser.Gauge:new({
 
   name="hpbar",
 
   name="hpbar",
Line 784: Line 870:
  
 
hpbar:setValue(math.random(1,100),100)
 
hpbar:setValue(math.random(1,100),100)
</lua>
+
</syntaxhighlight>
  
 
[[File:Fancy_Geyser_gauge.png|center]]
 
[[File:Fancy_Geyser_gauge.png|center]]
Line 790: Line 876:
 
The same style can be adjusted by colors to red as well:
 
The same style can be adjusted by colors to red as well:
  
<lua>
+
<syntaxhighlight lang="lua">
 
hpbar = Geyser.Gauge:new({
 
hpbar = Geyser.Gauge:new({
 
   name="hpbar",
 
   name="hpbar",
Line 810: Line 896:
  
 
hpbar:setValue(math.random(1,100),100)
 
hpbar:setValue(math.random(1,100),100)
</lua>
+
</syntaxhighlight>
  
 
[[File:Fancy_Geyser_gauge_red.png|center]]
 
[[File:Fancy_Geyser_gauge_red.png|center]]
  
=== HBox/VBox ===
+
=== Updating a gauge ===
 +
The Geyser gauge is composed of three labels - one is called ''mygauge.front'', ''mygauge.back'' and ''mygauge.text''. To make a gauge clickable you can set a ClickCallBack on the top label which is ''mygauge.text'' example: <syntaxhighlight lang="lua">mygauge.text:setClickCallback("functionName", variableToSendToFunctionName)</syntaxhighlight><br>
 +
If you would like to have different click events for the top or back of a gauge you can enable clickThrough for the top or ''mygauge.text'' label example
 +
 
 +
<syntaxhighlight lang="lua">
 +
mygauge.text:enableClickthrough()
 +
mygauge.front:setClickCallback("functionOne", variableToSendToFunctionOne)
 +
mygauge.back:setClickCallback("functionTwo", variableToSendToFunctionTwo)
 +
</syntaxhighlight>
 +
 
 +
== HBox/VBox ==
  
 
These are special types of containers. Every window in these is horizontally or vertically aligned in the order they were added.
 
These are special types of containers. Every window in these is horizontally or vertically aligned in the order they were added.
Line 820: Line 916:
 
<sub>Added to Mudlet in 2.0-rc4</sub>
 
<sub>Added to Mudlet in 2.0-rc4</sub>
  
== Tutorial ==
+
== Geyser.UserWindow ==
 +
Allows you to use Mudlets UserWindows within Geyser. Which allows you to use all the functionality of a MiniConsole in it‘s basic form.
 +
The big advantage is the possibility to add other Geyser Elements like Labels, MiniConsole, Gauges, Mappers to the UserWindow.
 +
The UserWindow then can act as container for those elements with all the perks of dynamic resizing or any other Geyser functionality.
 +
 
 +
{{note}} available in Mudlet 4.6.1+
 +
 
 +
===Basic floating UserWindow ===
 +
This will create a movable floating UserWindow.
 +
 
 +
<syntaxhighlight lang="lua">
 +
testuserwindow = Geyser.UserWindow:new({
 +
  name = "TestUserWindow",
 +
  x = "20%", y="20%",
 +
  width="30%", height ="40%"
 +
})
 +
</syntaxhighlight>
 +
 
 +
=== Docked UserWindow ===
 +
To create the window docked at the right side (for now only right side is possible on creation)
 +
Set the variable docked (at creation of the container) to true.
 +
Be aware that with this variable set to true the position and the size at creation of the userwindow will be ignored.
 +
 
 +
<syntaxhighlight lang="lua">
 +
testuserwindow = Geyser.UserWindow:new({
 +
  name = "DockedTestUserWindow",
 +
  docked = true
 +
 
 +
})
 +
</syntaxhighlight>
 +
 
 +
=== UserWindow as Container ===
 +
This is the feature which shows the versatile nature of Geyser.UserWindows.
 +
The UserWindow act as container and is at that possible to dynamically resize the containing Geyser Elments.
 +
Put a label in the UserWindow resize it as rectangle.
 +
<syntaxhighlight lang="lua">
 +
testuserwindow = Geyser.UserWindow:new({
 +
  name = "ParentTestUserWindow",
 +
  x = "20%", y="20%",
 +
  width="30%", height ="40%"
 +
})
 +
 
 +
testuserwindow:setColor("dark_green") -- give the userwindow a bit of color
 +
 
 +
labelinuserw = Geyser.Label:new({
 +
  name = "LabelinUserWindow",
 +
  x=20, y=20,
 +
  width = -20, height = -20,
 +
  color="light_blue", fontSize=20,
 +
  },testuserwindow)
 +
 
 +
labelinuserw:echo("This is a label in an userwindow", "black", "c")
 +
</syntaxhighlight>
 +
[[File:LabelInUserWindow.png]]
 +
 
 +
The same way you are able to add your favorite Geyser Application (like tabbed chat, animated timers, gauges) to an UserWindow.
 +
 
 +
[[File:Tabbedchatinuserwindow.png]]
 +
 
 +
==Change Container==
 +
{{note}} available in Mudlet 4.7+
 +
 
 +
With this command it is possible to change an elements or even a containers location to that from another container.
 +
For example:
 +
<syntaxhighlight lang="lua">
 +
mycontainerone:changeContainer(mycontainertwo)
 +
--puts container one into container two which means container two will be the parent of container one
 +
</syntaxhighlight>
 +
It is also possible to change to a container which is not located on the main window:
 +
<syntaxhighlight lang="lua">
 +
myEmco:changeContainer(emco_userwindow)
 +
--puts my tabbed chat Emco into my userwindow
 +
--to put it back to the main window change to a container located on the main window
 +
myEmco:changeContainer(mymainwindow_container)
 +
--or if it the element wasn't in a container use the main Geyser Root container called Geyser
 +
myEmco:changeContainer(Geyser)
 +
</syntaxhighlight>
 +
 
 +
==Create Map Window==
 +
{{note}} available in Mudlet 4.7+
 +
 
 +
It‘s possible to create the mapper as a map window (similar to clicking the icon) like this:
 +
<syntaxhighlight lang="lua">
 +
myMapWidget = Geyser.Mapper:new({embedded= false})
 +
</syntaxhighlight>
 +
 
 +
This will open a map window with your saved layout (if there is one, otherwise it will dock at the right corner)
 +
 
 +
To choose the position of the DockWindow at creation use: (this will create a map window docked at the left corner)
 +
<syntaxhighlight lang="lua">
 +
myMapWidget = Geyser.Mapper:new({embedded= false, dockPosition=“left“})
 +
</syntaxhighlight>
 +
Possible dockPositions are left "l", right "r", top "t", bottom "b" and floating "f" <br>
 +
To change the dockPosition after creation use:
 +
<syntaxhighlight lang="lua">
 +
myMapWidget:setDockPosition("f")
 +
-- this will change myMapWidget dockPosition to "f" floating
 +
</syntaxhighlight>
 +
 
 +
= Tutorial =
 
Note: This tutorial assumes you know how scripts in Mudlet work. If not then you should look at the manual first. Also it only shows how Geyser basically works and explains Geysers special windows. It wont go into detail about the windows that where already in Mudlet.
 
Note: This tutorial assumes you know how scripts in Mudlet work. If not then you should look at the manual first. Also it only shows how Geyser basically works and explains Geysers special windows. It wont go into detail about the windows that where already in Mudlet.
  
==== Hello World ====
+
=== Hello World ===
 
Let's start with something simple. A Label.
 
Let's start with something simple. A Label.
  
<lua>
+
<syntaxhighlight lang="lua">
 
  Geyser.Label:new({
 
  Geyser.Label:new({
name="HelloWorld",
+
  name="HelloWorld",
x=50, y=50,
+
  x=50, y=50,
width=200, height=50,
+
  width=200, height=50,
 
})
 
})
</lua>
+
</syntaxhighlight>
  
 
[[Image:Geyser_HW_1.png]]
 
[[Image:Geyser_HW_1.png]]
Line 840: Line 1,035:
 
You can manipulate the Label through the normal functions but Geyser.Label:new() returns an object which can be used to manipulate the label directly. So you should store it:
 
You can manipulate the Label through the normal functions but Geyser.Label:new() returns an object which can be used to manipulate the label directly. So you should store it:
  
<lua>
+
<syntaxhighlight lang="lua">
 
  local HelloWorld = Geyser.Label:new({
 
  local HelloWorld = Geyser.Label:new({
name="HelloWorld",
+
  name="HelloWorld",
x=50, y=50,
+
  x=50, y=50,
width=200, height=50,
+
  width=200, height=50,
 
})
 
})
</lua>
+
</syntaxhighlight>
  
 
Then you can, for example print a text on it:
 
Then you can, for example print a text on it:
  
<lua>
+
<syntaxhighlight lang="lua">
 
  HelloWorld:echo("Hello World")
 
  HelloWorld:echo("Hello World")
</lua>
+
</syntaxhighlight>
  
 
[[Image:Geyser_HW_2.png]]
 
[[Image:Geyser_HW_2.png]]
  
 
You can put a format parameter so that the text is, for example, centered.
 
You can put a format parameter so that the text is, for example, centered.
<lua>
+
<syntaxhighlight lang="lua">
 
HelloWorld:echo("Hello World", nil, "c")
 
HelloWorld:echo("Hello World", nil, "c")
</lua>
+
</syntaxhighlight>
  
 
[[Image:Geyser_HW_3.png]]
 
[[Image:Geyser_HW_3.png]]
Line 868: Line 1,063:
  
 
Example:
 
Example:
<lua>
+
<syntaxhighlight lang="lua">
 
HelloWorld:echo("Hello World", "red", "c")
 
HelloWorld:echo("Hello World", "red", "c")
</lua>
+
</syntaxhighlight>
  
 
[[Image:Geyser_HW_4.png]]
 
[[Image:Geyser_HW_4.png]]
Line 878: Line 1,073:
 
You can also set the foreground color with the setFgColor method:
 
You can also set the foreground color with the setFgColor method:
  
<lua>
+
<syntaxhighlight lang="lua">
 
HelloWorld:setFgColor("red")
 
HelloWorld:setFgColor("red")
 
HelloWorld:echo("Hello World", nil, "c")
 
HelloWorld:echo("Hello World", nil, "c")
</lua>
+
</syntaxhighlight>
  
 
[[Image:Geyser_HW_4.png]]
 
[[Image:Geyser_HW_4.png]]
  
==== Containers ====
+
=== Containers ===
  
 
Containers are windows that can contain other windows. Actually, since all other Geyser windows subclass container, every window can do that. But containers do not have any visible content by themselves.  
 
Containers are windows that can contain other windows. Actually, since all other Geyser windows subclass container, every window can do that. But containers do not have any visible content by themselves.  
  
 
Let's show that by an example:
 
Let's show that by an example:
<lua>
+
<syntaxhighlight lang="lua">
 
  local container = Geyser.Container:new({
 
  local container = Geyser.Container:new({
name="container",
+
  name="container",
x=50, y=50,
+
  x=50, y=50,
width=250, height=50,
+
  width=250, height=50,
 
})
 
})
</lua>
+
</syntaxhighlight>
  
 
This will create a container, but if you look at the screen you will see nothing at the positon.
 
This will create a container, but if you look at the screen you will see nothing at the positon.
 
There is a way to make containers visible though:
 
There is a way to make containers visible though:
<lua>
+
<syntaxhighlight lang="lua">
 
container:flash()
 
container:flash()
</lua>
+
</syntaxhighlight>
  
 
This will flash the container for a short period of time.
 
This will flash the container for a short period of time.
Line 914: Line 1,109:
 
Directly when creating the window:
 
Directly when creating the window:
  
<lua>
+
<syntaxhighlight lang="lua">
 
  local container_label = Geyser.Label:new({
 
  local container_label = Geyser.Label:new({
name="container_label",
+
  name="container_label",
x=0, y=0,
+
  x=0, y=0,
width="100%", height="100%",
+
  width="100%", height="100%",
},
+
  },
container)
+
  container)
 
container_label:echo("This is a label in a container", nil, "c")
 
container_label:echo("This is a label in a container", nil, "c")
</lua>
+
</syntaxhighlight>
  
 
Later, after the window was created
 
Later, after the window was created
<lua>
+
<syntaxhighlight lang="lua">
 
  local container_label = Geyser.Label:new({
 
  local container_label = Geyser.Label:new({
name="container_label",
+
  name="container_label",
x=0, y=0,
+
  x=0, y=0,
width="100%", height="100%",
+
  width="100%", height="100%",
})
+
  })
 
container_label:echo("This is a label in a container", nil, "c")
 
container_label:echo("This is a label in a container", nil, "c")
 
container:add(container_label)
 
container:add(container_label)
</lua>
+
</syntaxhighlight>
  
 
Both will lead to the same outcome.
 
Both will lead to the same outcome.
Line 941: Line 1,136:
 
Note that we gave a width and height of "100%" to the constructor of the container. This means that the label will take 100% of the containers width and height. If values are given in percent they will even resize with its parent:
 
Note that we gave a width and height of "100%" to the constructor of the container. This means that the label will take 100% of the containers width and height. If values are given in percent they will even resize with its parent:
  
<lua>
+
<syntaxhighlight lang="lua">
 
container:resize(325, nil)
 
container:resize(325, nil)
</lua>
+
</syntaxhighlight>
  
 
[[Image:Geyser_Container_3.png]]
 
[[Image:Geyser_Container_3.png]]
Line 952: Line 1,147:
  
 
When we now move the container the label moves with it:
 
When we now move the container the label moves with it:
<lua>
+
<syntaxhighlight lang="lua">
 
container:move(400, nil)
 
container:move(400, nil)
</lua>
+
</syntaxhighlight>
  
 
[[Image:Geyser_Container_4.png]]
 
[[Image:Geyser_Container_4.png]]
Line 960: Line 1,155:
 
The first parameter is the x-, the second the y-position. If the value is nil the current value is used.
 
The first parameter is the x-, the second the y-position. If the value is nil the current value is used.
  
==== VBox and HBox ====
+
=== VBox and HBox ===
  
 
The VBox and HBox classes are special Containers.
 
The VBox and HBox classes are special Containers.
 
They will automatically align its containing windows vertically or horizontally, respectively, in the order they where added to them.
 
They will automatically align its containing windows vertically or horizontally, respectively, in the order they where added to them.
  
<lua>
+
<syntaxhighlight lang="lua">
  
 
  local HBox = Geyser.HBox:new({
 
  local HBox = Geyser.HBox:new({
name="HBox",
+
  name="HBox",
x=0, y=0,
+
  x=0, y=0,
width=400, height=30,
+
  width=400, height=30,
})
+
  })
  
</lua>
+
</syntaxhighlight>
  
 
Like containers you won't see them by themselves.
 
Like containers you won't see them by themselves.
  
 
Adding children works like with containers
 
Adding children works like with containers
<lua>
+
<syntaxhighlight lang="lua">
  
 
  local label1 = Geyser.Label:new({
 
  local label1 = Geyser.Label:new({
name="Label1",
+
  name="Label1",
},
+
  },
HBox)
+
  HBox)
 
label1:echo("Label 1", "black", "c")
 
label1:echo("Label 1", "black", "c")
 
label1:setColor(255, 0, 0)
 
label1:setColor(255, 0, 0)
  
</lua>
+
</syntaxhighlight>
  
 
[[Image:HVBox_1.png]]
 
[[Image:HVBox_1.png]]
Line 994: Line 1,189:
  
 
If we add another window:
 
If we add another window:
<lua>
+
<syntaxhighlight lang="lua">
  
 
  local label2 = Geyser.Label:new({
 
  local label2 = Geyser.Label:new({
name="Label2",
+
  name="Label2",
},
+
  },
HBox)
+
  HBox)
 
label2:echo("Label 2", "black", "c")
 
label2:echo("Label 2", "black", "c")
 
label2:setColor(0, 255, 0)
 
label2:setColor(0, 255, 0)
  
</lua>
+
</syntaxhighlight>
  
 
[[Image:HVBox_2.png]]
 
[[Image:HVBox_2.png]]
Line 1,011: Line 1,206:
 
What if you want a child that takes more or less space than the others?
 
What if you want a child that takes more or less space than the others?
 
That's possible too:
 
That's possible too:
<lua>
+
<syntaxhighlight lang="lua">
  
 
  local label3 = Geyser.Label:new({
 
  local label3 = Geyser.Label:new({
name="Label3",
+
  name="Label3",
h_stretch_factor=2.0,
+
  h_stretch_factor=2.0,
},
+
  },
HBox)
+
  HBox)
 
label3:echo("Label 3", nil, "c")
 
label3:echo("Label 3", nil, "c")
 
label3:setColor(0, 0, 255)
 
label3:setColor(0, 0, 255)
  
</lua>
+
</syntaxhighlight>
  
 
[[Image:HVBox_3.png]]
 
[[Image:HVBox_3.png]]
Line 1,033: Line 1,228:
 
To accomplish this you have to set the horizontal and/or vertical policy:
 
To accomplish this you have to set the horizontal and/or vertical policy:
  
<lua>
+
<syntaxhighlight lang="lua">
  
 
  local label4 = Geyser.Label:new({
 
  local label4 = Geyser.Label:new({
name="Label4",
+
  name="Label4",
width="13%",
+
  width="13%",
h_policy=Geyser.Fixed,
+
  h_policy=Geyser.Fixed,
},
+
  },
HBox)
+
  HBox)
 
label4:echo("Label 4", "black", "c")
 
label4:echo("Label 4", "black", "c")
 
label4:setColor(0, 255, 255)
 
label4:setColor(0, 255, 255)
  
</lua>
+
</syntaxhighlight>
  
 
[[Image:HVBox_4.png]]
 
[[Image:HVBox_4.png]]
Line 1,053: Line 1,248:
 
The VBox works like the HBox, only that the child windows are aligned vertically.
 
The VBox works like the HBox, only that the child windows are aligned vertically.
  
== Walkthroughs ==
+
= Walkthroughs =
 
Here are a few walkthroughs that will show you how to combine Geyser elements to create some simple GUI widgets.
 
Here are a few walkthroughs that will show you how to combine Geyser elements to create some simple GUI widgets.
  
====Create a Clickable Compass====
+
===Create a Clickable Compass===
 
[[File: compass.png]]
 
[[File: compass.png]]
 
The following will walk you through the process of creating your own clickable compass using the Geyser framework.
 
The following will walk you through the process of creating your own clickable compass using the Geyser framework.
=====Setup the image files=====
+
====Setup the image files====
 
The compass requires a handful of images to work properly. You can find them here: https://www.dropbox.com/sh/53l7xrn4ds35wnq/WpWOziVKmH <br>
 
The compass requires a handful of images to work properly. You can find them here: https://www.dropbox.com/sh/53l7xrn4ds35wnq/WpWOziVKmH <br>
 
Download each image and place it in your profile folder. You can find your profile folder with getMudletHomeDir()<br>
 
Download each image and place it in your profile folder. You can find your profile folder with getMudletHomeDir()<br>
 
If you're using Mudlet 2.1+ you can enter '''lua getMudletHomeDir()''' from the command line to return the profile folder path on your computer.
 
If you're using Mudlet 2.1+ you can enter '''lua getMudletHomeDir()''' from the command line to return the profile folder path on your computer.
  
=====Create a new script=====
+
====Create a new script====
 
Script Name: '''''compass.resize'''''<br>
 
Script Name: '''''compass.resize'''''<br>
 
Registered Event Handlers: '''''sysWindowResizeEvent'''''<p>
 
Registered Event Handlers: '''''sysWindowResizeEvent'''''<p>
 
Every snippet of code will be placed within this script.
 
Every snippet of code will be placed within this script.
=====Store the screen size=====
+
====Store the screen size====
 
We'll want to store the screen size in some local variables so they can be easily referenced to later on.
 
We'll want to store the screen size in some local variables so they can be easily referenced to later on.
<lua>local mw, mh = getMainWindowSize()</lua>
+
<syntaxhighlight lang="lua">local mw, mh = getMainWindowSize()</syntaxhighlight>
  
=====Create a global table or namespace=====
+
====Create a global table or namespace====
 
Creating a global table will make each of your variables unique. Our namespace will be called '''''compass''''' and everything we make from here on out will be stored within the compass table. We'll also add a few values to it: dirs and ratio. '''''compass.dirs''''' will store each direction while '''''compass.ratio''''' will store the ratio of our screen size so you can 'square up' your compass.
 
Creating a global table will make each of your variables unique. Our namespace will be called '''''compass''''' and everything we make from here on out will be stored within the compass table. We'll also add a few values to it: dirs and ratio. '''''compass.dirs''''' will store each direction while '''''compass.ratio''''' will store the ratio of our screen size so you can 'square up' your compass.
<lua>compass = compass or {
+
<syntaxhighlight lang="lua">compass = compass or {
 
   dirs = {"nw","n","ne","w","center","e","sw","s","se"},
 
   dirs = {"nw","n","ne","w","center","e","sw","s","se"},
 
   ratio = mw / mh
 
   ratio = mw / mh
}</lua>
+
}</syntaxhighlight>
  
=====Create the parent label=====
+
====Create the parent label====
 
[[File: grey.png|thumbnail]]
 
[[File: grey.png|thumbnail]]
 
The 'parent label' refers to the label on the bottom layer. The entire compass will be created within this label. It's container is '''main''' for it's parent is the main window.
 
The 'parent label' refers to the label on the bottom layer. The entire compass will be created within this label. It's container is '''main''' for it's parent is the main window.
<lua>compass.back = Geyser.Label:new({
+
<syntaxhighlight lang="lua">compass.back = Geyser.Label:new({
 
   name = "compass.back",
 
   name = "compass.back",
 
   x = "25%",
 
   x = "25%",
Line 1,088: Line 1,283:
 
   width = "10%",
 
   width = "10%",
 
   height = "10%",
 
   height = "10%",
},main)</lua>
+
},main)</syntaxhighlight>
  
=====Set the parent label stylesheet=====
+
====Set the parent label stylesheet====
 
[[File: blue.png|thumbnail]]
 
[[File: blue.png|thumbnail]]
 
This will create the blue sphere that makes up most of the compass. The background color is a radial gradient that goes from a deep blue to a brighter shade. The border radius rounds the edges. When the radius is exactly half of the label width it forms a circle. The arrows of the compass actually protrude from the sphere so we give it a margin to suck it in a bit for this effect.
 
This will create the blue sphere that makes up most of the compass. The background color is a radial gradient that goes from a deep blue to a brighter shade. The border radius rounds the edges. When the radius is exactly half of the label width it forms a circle. The arrows of the compass actually protrude from the sphere so we give it a margin to suck it in a bit for this effect.
<lua>compass.back:setStyleSheet([[
+
<syntaxhighlight lang="lua">compass.back:setStyleSheet([[
 
   background-color: QRadialGradient(cx:.3,cy:1,radius:1,stop:0 rgb(0,0,50),stop:.5 rgb(0,0,100),stop:1 rgb(0,0,255));
 
   background-color: QRadialGradient(cx:.3,cy:1,radius:1,stop:0 rgb(0,0,50),stop:.5 rgb(0,0,100),stop:1 rgb(0,0,255));
 
   border-radius: ]]..tostring(compass.back:get_width()/2-14)..[[px;
 
   border-radius: ]]..tostring(compass.back:get_width()/2-14)..[[px;
 
   margin: 10px;
 
   margin: 10px;
]])</lua>
+
]])</syntaxhighlight>
  
=====Create a 3x3 grid=====
+
====Create a 3x3 grid====
 
The compass is split into 9 sections. One for each cardinal direction plus an extra space that sits in the center. This 3x3 grid is created by 3 VBoxes that sit within a single HBox (or vice versa but I flipped a coin and this is what it gave me).<br>
 
The compass is split into 9 sections. One for each cardinal direction plus an extra space that sits in the center. This 3x3 grid is created by 3 VBoxes that sit within a single HBox (or vice versa but I flipped a coin and this is what it gave me).<br>
 
So first off, we create the HBox. It will be the same size as its parent, ''compass.back''.
 
So first off, we create the HBox. It will be the same size as its parent, ''compass.back''.
<lua>  compass.box = Geyser.HBox:new({
+
<syntaxhighlight lang="lua">  compass.box = Geyser.HBox:new({
 
     name = "compass.box",
 
     name = "compass.box",
 
     x = 0,
 
     x = 0,
Line 1,108: Line 1,303:
 
     width = "100%",
 
     width = "100%",
 
     height = "100%",
 
     height = "100%",
   },compass.back)</lua>
+
   },compass.back)</syntaxhighlight>
 
Next, we create our 3 VBoxes. You don't need to specify position or size because these are placed within ''compass.box'', an HBox.
 
Next, we create our 3 VBoxes. You don't need to specify position or size because these are placed within ''compass.box'', an HBox.
<lua>    compass.row1 = Geyser.VBox:new({
+
<syntaxhighlight lang="lua">    compass.row1 = Geyser.VBox:new({
 
       name = "compass.row1",
 
       name = "compass.row1",
 
     },compass.box)
 
     },compass.box)
Line 1,118: Line 1,313:
 
     compass.row3 = Geyser.VBox:new({
 
     compass.row3 = Geyser.VBox:new({
 
       name = "compass.row3",
 
       name = "compass.row3",
     },compass.box)</lua>
+
     },compass.box)</syntaxhighlight>
 
Finally, we add our 9 labels. Take note that they are split up into even groups of 3. Each group is placed into a different ''compass.row#''
 
Finally, we add our 9 labels. Take note that they are split up into even groups of 3. Each group is placed into a different ''compass.row#''
<lua>      compass.nw = Geyser.Label:new({
+
<syntaxhighlight lang="lua">      compass.nw = Geyser.Label:new({
 
         name = "compass.nw",
 
         name = "compass.nw",
 
       },compass.row1)
 
       },compass.row1)
Line 1,154: Line 1,349:
 
       compass.se = Geyser.Label:new({
 
       compass.se = Geyser.Label:new({
 
         name = "compass.se",
 
         name = "compass.se",
       },compass.row3)</lua>
+
       },compass.row3)</syntaxhighlight>
=====Create a callback function=====
+
====Create a callback function====
 
We'll want our compass to head in the direction of the arrow we're clicking. This is where we specify so. When the arrow is clicked, this function will be ran with the arrow direction as the argument.
 
We'll want our compass to head in the direction of the arrow we're clicking. This is where we specify so. When the arrow is clicked, this function will be ran with the arrow direction as the argument.
<lua>function compass.click(name)
+
<syntaxhighlight lang="lua">function compass.click(name)
 
   send(name)
 
   send(name)
end</lua>
+
end</syntaxhighlight>
=====Create the hover functions=====
+
====Create the hover functions====
 
We want our arrows to turn yellow when we hover over them. We do so by simply resetting the label's stylesheet and changing the border image. Don't forget to include the margin as we still want that.
 
We want our arrows to turn yellow when we hover over them. We do so by simply resetting the label's stylesheet and changing the border image. Don't forget to include the margin as we still want that.
<lua>function compass.onEnter(name)
+
<syntaxhighlight lang="lua">function compass.onEnter(name)
 
   compass[name]:setStyleSheet([[
 
   compass[name]:setStyleSheet([[
 
     border-image: url("]]..getMudletHomeDir()..[[/]]..name..[[hover.png");
 
     border-image: url("]]..getMudletHomeDir()..[[/]]..name..[[hover.png");
Line 1,174: Line 1,369:
 
     margin: 5px;
 
     margin: 5px;
 
   ]])
 
   ]])
end</lua>
+
end</syntaxhighlight>
=====Set the stylesheets in the grid=====
+
====Set the stylesheets in the grid====
 
[[File: Sample.png|thumb]]
 
[[File: Sample.png|thumb]]
 
Each of the 9 labels need an image of an arrow. Rather than setting each individually, we'll iterate over the ''compass.dirs'' table we made awhile back and add the respective image to each. The names of images are a reflection of the ''compass.dirs'' table. This keeps it consistent and easy to refer to. During the iteration, the callback, setLabelOnEnter and setLabelOnLeave are also set for each label.
 
Each of the 9 labels need an image of an arrow. Rather than setting each individually, we'll iterate over the ''compass.dirs'' table we made awhile back and add the respective image to each. The names of images are a reflection of the ''compass.dirs'' table. This keeps it consistent and easy to refer to. During the iteration, the callback, setLabelOnEnter and setLabelOnLeave are also set for each label.
<lua>for k,v in pairs(compass.dirs) do
+
<syntaxhighlight lang="lua">for k,v in pairs(compass.dirs) do
 
   compass[v]:setStyleSheet([[
 
   compass[v]:setStyleSheet([[
 
     border-image: url("]]..getMudletHomeDir()..[[/]]..v..[[.png");
 
     border-image: url("]]..getMudletHomeDir()..[[/]]..v..[[.png");
Line 1,186: Line 1,381:
 
   setLabelOnEnter("compass."..v,"compass.onEnter",v)
 
   setLabelOnEnter("compass."..v,"compass.onEnter",v)
 
   setLabelOnLeave("compass."..v,"compass.onLeave",v)
 
   setLabelOnLeave("compass."..v,"compass.onLeave",v)
end</lua>
+
end</syntaxhighlight>
  
=====Resize the compass into a square=====
+
====Resize the compass into a square====
 
[[File: final.png|thumb]]
 
[[File: final.png|thumb]]
Most screen size ratios aren't a perfect 1:1. This will cause a 10% x 10% label to be far from square. By multiplying our height (the smaller of the two numbers) by our ''compass.ratio'' we set earlier, we can resize our compass to a near perfect square. This function is also the name of our script because we want it to run each time sysWindowResizeEvent is raised.
+
Most screen size ratios aren't a perfect 1:1. This will cause a 10% x 10% label to be far from square. By setting our height (the smaller of the two numbers) to our width, we can resize our compass to a near perfect square. This function is also the name of our script because we want it to run each time sysWindowResizeEvent is raised.
<lua>function compass.resize()
+
<syntaxhighlight lang="lua">function compass.resize()
   compass.back:resize(compass.back:get_width(),math.floor(compass.back:get_height()*compass.ratio))
+
   compass.back:resize(compass.back.width, compass.back:get_width())
 
end
 
end
  
compass.resize()</lua>
+
compass.resize()</syntaxhighlight>
  
====Create a Tabbed Window====
+
===Create a Tabbed Window===
 
[[File: tabwindow.png]]
 
[[File: tabwindow.png]]
 
The following will walk you through the process of creating your own tabbed window using the Geyser framework.
 
The following will walk you through the process of creating your own tabbed window using the Geyser framework.
  
=====Create a new script=====
+
====Create a new script====
 
Script Name: '''''Tabbed Window'''''<br>
 
Script Name: '''''Tabbed Window'''''<br>
 
Every snippet of code will be placed within this script.
 
Every snippet of code will be placed within this script.
=====Create a global table=====
+
====Create a global table====
 
Creating a global table will make each of your variables unique. Our namespace will be called '''''menu''''' and everything we make from here on out will be stored within the menu table. We'll also add a few values to it: tabs, color1, color2, width, height and current. <br>
 
Creating a global table will make each of your variables unique. Our namespace will be called '''''menu''''' and everything we make from here on out will be stored within the menu table. We'll also add a few values to it: tabs, color1, color2, width, height and current. <br>
 
''''tabs'''' will be a table that stores all our tab names. If we want our tabs to have different names, we alter this table.<br>
 
''''tabs'''' will be a table that stores all our tab names. If we want our tabs to have different names, we alter this table.<br>
 
''''color1'''' and ''''color2'''' will store the colors of our tabbed window. If we want to change the color of our tabbed window, we alter these values.<br>
 
''''color1'''' and ''''color2'''' will store the colors of our tabbed window. If we want to change the color of our tabbed window, we alter these values.<br>
 
''''width'''' and ''''height'''' will store the size of our tabbed window. If we want to change the size of the tabbed window, we alter these values.<br>
 
''''width'''' and ''''height'''' will store the size of our tabbed window. If we want to change the size of the tabbed window, we alter these values.<br>
''''current'''' keeps track of which tab is selected. Since no tab is selected at startup, we'll make this an empty string.<br>
+
''''current'''' keeps track of which tab is selected. We will set this to the first tab in the table by default. We do this outside the initial table creation so we can easily access menu.tabs<br>
<lua>menu = menu or {
+
<syntaxhighlight lang="lua">menu = menu or {
 
   tabs = {"Tab1","Tab2","Tab3","Tab4"},
 
   tabs = {"Tab1","Tab2","Tab3","Tab4"},
 
   color1 = "rgb(0,0,70)",
 
   color1 = "rgb(0,0,70)",
Line 1,216: Line 1,411:
 
   width = "20%",
 
   width = "20%",
 
   height = "40%",
 
   height = "40%",
  current = "",
+
}
}</lua>
+
menu.current = menu.current or menu.tabs[1]</syntaxhighlight>
=====Create the main container=====
+
 
 +
====Create the main container====
 
Our tabbed window will need a container. This will be the bottom layer. Containers are invisible so no need to set a stylesheet.
 
Our tabbed window will need a container. This will be the bottom layer. Containers are invisible so no need to set a stylesheet.
<lua>menu.container = Geyser.Container:new({
+
<syntaxhighlight lang="lua">menu.container = Geyser.Container:new({
 
   name = "menu.back",
 
   name = "menu.back",
 
   x = "50%", y = "25%",
 
   x = "50%", y = "25%",
 
   width = menu.width,
 
   width = menu.width,
 
   height = menu.height,
 
   height = menu.height,
},main)</lua>
+
},main)</syntaxhighlight>
=====Create an HBox=====
+
====Create an HBox====
 
All of our tabs will be evenly spaced. So we'll create an HBox to sit at the top of our container.
 
All of our tabs will be evenly spaced. So we'll create an HBox to sit at the top of our container.
<lua>menu.header = Geyser.HBox:new({
+
<syntaxhighlight lang="lua">menu.header = Geyser.HBox:new({
 
   name = "menu.header",
 
   name = "menu.header",
 
   x = 0, y = 0,
 
   x = 0, y = 0,
 
   width = "100%",
 
   width = "100%",
 
   height = "10%",
 
   height = "10%",
},menu.container)</lua>
+
},menu.container)</syntaxhighlight>
=====Create a label=====
+
====Create a label====
 
This label will serve as a container for each window. It sits right underneath the HBox we just created for the tabs.
 
This label will serve as a container for each window. It sits right underneath the HBox we just created for the tabs.
<lua>menu.footer = Geyser.Label:new({
+
<syntaxhighlight lang="lua">menu.footer = Geyser.Label:new({
 
   name = "menu.footer",
 
   name = "menu.footer",
 
   x = 0, y = "10%",
 
   x = 0, y = "10%",
 
   width = "100%",
 
   width = "100%",
 
   height = "90%",
 
   height = "90%",
},menu.container)</lua>
+
},menu.container)</syntaxhighlight>
 
We don't want this to be a big grey box at startup, so we'll set the stylesheet to appear like the rest of the windows.
 
We don't want this to be a big grey box at startup, so we'll set the stylesheet to appear like the rest of the windows.
<lua>
+
<syntaxhighlight lang="lua">
 
menu.footer:setStyleSheet([[
 
menu.footer:setStyleSheet([[
 
   background-color: ]]..menu.color1..[[;
 
   background-color: ]]..menu.color1..[[;
 
   border-bottom-left-radius: 10px;
 
   border-bottom-left-radius: 10px;
 
   border-bottom-right-radius: 10px;
 
   border-bottom-right-radius: 10px;
]])</lua>
+
]])</syntaxhighlight>
 
Each window actually has two labels. One for the light blue background, and another for the dark blue center. This will create that dark blue center.
 
Each window actually has two labels. One for the light blue background, and another for the dark blue center. This will create that dark blue center.
<lua>menu.center = Geyser.Label:new({
+
<syntaxhighlight lang="lua">menu.center = Geyser.Label:new({
 
   name = "menu.center",
 
   name = "menu.center",
 
   x = 0, y = 0,
 
   x = 0, y = 0,
Line 1,260: Line 1,456:
 
   border-radius: 10px;
 
   border-radius: 10px;
 
   margin: 5px;
 
   margin: 5px;
]])</lua>
+
]])</syntaxhighlight>
=====Add your tabs and their windows=====
+
====Add your tabs and their windows====
 
Now we'll want to add our tabs and windows. We do this in a single for loop of the ''''menu.tabs'''' table since it holds all our tab names.
 
Now we'll want to add our tabs and windows. We do this in a single for loop of the ''''menu.tabs'''' table since it holds all our tab names.
<lua>for k,v in pairs(menu.tabs) do
+
<syntaxhighlight lang="lua">for k,v in pairs(menu.tabs) do
</lua>
+
</syntaxhighlight>
 
This will create the tabs. Each tab will be named: menu.<tabname>tab
 
This will create the tabs. Each tab will be named: menu.<tabname>tab
<lua>
+
<syntaxhighlight lang="lua">
 
   menu[v.."tab"] = Geyser.Label:new({
 
   menu[v.."tab"] = Geyser.Label:new({
 
     name = "menu."..v.."tab",
 
     name = "menu."..v.."tab",
 
   },menu.header)
 
   },menu.header)
</lua>
+
</syntaxhighlight>
 
Here is where we set the tab stylesheet. Each tab has a rounded top, so we set the border-radius of the top-left and top-right to 10px. Each tab has a small space for separation so we give the right and left sides a tiny margin of 1px.
 
Here is where we set the tab stylesheet. Each tab has a rounded top, so we set the border-radius of the top-left and top-right to 10px. Each tab has a small space for separation so we give the right and left sides a tiny margin of 1px.
<lua>
+
<syntaxhighlight lang="lua">
 
   menu[v.."tab"]:setStyleSheet([[
 
   menu[v.."tab"]:setStyleSheet([[
 
     background-color: ]]..menu.color1..[[;
 
     background-color: ]]..menu.color1..[[;
Line 1,280: Line 1,476:
 
     margin-left: 1px;
 
     margin-left: 1px;
 
   ]])
 
   ]])
</lua>
+
</syntaxhighlight>
 
This will display the name of each tab on the tab.
 
This will display the name of each tab on the tab.
<lua>
+
<syntaxhighlight lang="lua">
 
   menu[v.."tab"]:echo("<center>"..v)
 
   menu[v.."tab"]:echo("<center>"..v)
</lua>
+
</syntaxhighlight>
 
We need our tabs to do stuff when clicked, so we'll assign it a callback function, '''''menu.click''''', which we'll create later on. Our tab name is the argument.
 
We need our tabs to do stuff when clicked, so we'll assign it a callback function, '''''menu.click''''', which we'll create later on. Our tab name is the argument.
<lua>
+
<syntaxhighlight lang="lua">
 
   menu[v.."tab"]:setClickCallback("menu.click",v)
 
   menu[v.."tab"]:setClickCallback("menu.click",v)
</lua>
+
</syntaxhighlight>
 
Now we create the windows that appear when each tab is clicked. Each window has two labels, one atop the other. The first, which we'll create here, has rounded edges on its bottom.
 
Now we create the windows that appear when each tab is clicked. Each window has two labels, one atop the other. The first, which we'll create here, has rounded edges on its bottom.
<lua>
+
<syntaxhighlight lang="lua">
 
   menu[v] = Geyser.Label:new({
 
   menu[v] = Geyser.Label:new({
 
     name = "menu."..v,
 
     name = "menu."..v,
Line 1,303: Line 1,499:
 
     border-bottom-right-radius: 10px;
 
     border-bottom-right-radius: 10px;
 
   ]])
 
   ]])
</lua>
+
</syntaxhighlight>
 
The second label serves as the window's center and has rounded edges on all sides. And a margin of 5px from it's parent, the label we just created. When adding stuff to your windows, this is the label you'll want to use. '''''menu.<tabname>center'''''
 
The second label serves as the window's center and has rounded edges on all sides. And a margin of 5px from it's parent, the label we just created. When adding stuff to your windows, this is the label you'll want to use. '''''menu.<tabname>center'''''
<lua>
+
<syntaxhighlight lang="lua">
 
   menu[v.."center"] = Geyser.Label:new({
 
   menu[v.."center"] = Geyser.Label:new({
 
     name = "menu."..v.."center",
 
     name = "menu."..v.."center",
Line 1,312: Line 1,508:
 
     height = "100%",
 
     height = "100%",
 
   },menu[v])
 
   },menu[v])
</lua><lua>
+
</syntaxhighlight><syntaxhighlight lang="lua">
 
   menu[v.."center"]:setStyleSheet([[
 
   menu[v.."center"]:setStyleSheet([[
 
     background-color: ]]..menu.color2..[[;
 
     background-color: ]]..menu.color2..[[;
Line 1,318: Line 1,514:
 
     margin: 5px;
 
     margin: 5px;
 
   ]])
 
   ]])
</lua>
+
</syntaxhighlight>
 
Finally, we hide all the windows and end the for loop.
 
Finally, we hide all the windows and end the for loop.
<lua>
+
<syntaxhighlight lang="lua">
 
   menu[v]:hide()
 
   menu[v]:hide()
end</lua>
+
end</syntaxhighlight>
=====Create a callback function=====
+
====Create a callback function====
 
The last step is to create our callback function for when a tab is clicked. This will hide that tab that is stored in '''''menu.current''''', set menu.current to the clicked tab, and then show the menu.current tab.
 
The last step is to create our callback function for when a tab is clicked. This will hide that tab that is stored in '''''menu.current''''', set menu.current to the clicked tab, and then show the menu.current tab.
<lua>function menu.click(tab)
+
<syntaxhighlight lang="lua">function menu.click(tab)
 
   menu[menu.current]:hide()
 
   menu[menu.current]:hide()
 
   menu.current = tab
 
   menu.current = tab
 
   menu[menu.current]:show()
 
   menu[menu.current]:show()
end</lua>
+
end</syntaxhighlight>
=====Adding content to your windows=====
+
====Adding content to your windows====
 
Add content to '''menu.<tab name>center'''
 
Add content to '''menu.<tab name>center'''
So if we wanted to display our gold in a window we could:<lua>menu.Tab1center:echo(myGold)</lua>
+
So if we wanted to display our gold in a window we could:<syntaxhighlight lang="lua">menu.Tab1center:echo(myGold)</syntaxhighlight>
 
If we wanted to add a map to a window we could:
 
If we wanted to add a map to a window we could:
<lua>myMap = Geyser.Mapper:new({
+
<syntaxhighlight lang="lua">myMap = Geyser.Mapper:new({
 
   name = "myMap",
 
   name = "myMap",
 
   x = 0, y = 0,
 
   x = 0, y = 0,
 
   width = "100%",
 
   width = "100%",
 
   height = "100%",
 
   height = "100%",
},menu.Tab2center)</lua>
+
},menu.Tab2center)</syntaxhighlight>
 +
 
 +
===Create a Window with a resize label===
 +
[[File: resize_window.png]]
 +
This walkthrough will create a window with a smaller label which will let you resize the window.
 +
 
 +
====Create a new script====
 +
Script Name: '''''Resize Window'''''<br>
 +
Every snippet of code will be placed within this script.
 +
 
 +
====Create a window====
 +
Create a window label which will be resizable.
 +
<syntaxhighlight lang="lua">--
 +
-- Create a label that will be resized and contain the drag icon.
 +
---
 +
mLabel = Geyser.Label:new({
 +
  name = "mLabel",
 +
  x = 400, y = 200,
 +
  width = 200, height = 200,
 +
  fgColor = "black",
 +
  color = "blue",
 +
  message = [[<center>drag the white label to resize</center>]]
 +
})
 +
mLabel:setStyleSheet([[qproperty-wordWrap: true]])
 +
</syntaxhighlight>
 +
 
 +
====Create small icon inside the window====
 +
Create the label that will be used as a drag icon.
 +
<syntaxhighlight lang="lua">--
 +
-- Create the small drag label within the window.
 +
-- The y position is set to "-15px" to align it to
 +
-- the bottom of the main label.
 +
--
 +
mVDrag = Geyser.Label:new({
 +
  name = "mVDrag",
 +
  x = 85, y = "-15px",
 +
  width = 30, height = 15,
 +
  fgColor = "black",
 +
  color = "white",
 +
}, mLabel)
 +
</syntaxhighlight>
 +
 
 +
====Create callback functions====
 +
Create the callback functions that will be called by mouse and timer events.<br>
 +
 
 +
Create a timer function that will be called repeatedly while the mouse button is pressed.
 +
<syntaxhighlight lang="lua">
 +
function onVDragTimer()
 +
  local x
 +
  local y
 +
  local height
 +
 
 +
  -- Get mouse position
 +
  x, y = getMousePosition()
 +
 
 +
  -- Substract the top of the label  to get the new height.
 +
  height = y - 200
 +
  if height < MIN_HEIGHT then
 +
    -- Height is too small.
 +
    height = MIN_HEIGHT
 +
  end
 +
 
 +
  -- Set the new size and restart timer.
 +
  mLabel:resize(200, height)
 +
  vdragtimer = tempTimer(0.2, onVDragTimer)
 +
end
 +
</syntaxhighlight><br>
 +
 
 +
Create a function which will be called when we first press the icon. The function will create the timer which will trigger as long as the button is pressed.
 +
<syntaxhighlight lang="lua">
 +
function onVDragClick()
 +
  -- The user clicked the drag label.
 +
  -- Start a temp timer to update the size of the label.
 +
  if not exists("vdragtimer", "timer") then
 +
    vdragtimer = permTimer("vdragtimer", "", .016, "onVDragTimer()")
 +
  end
 +
 
 +
  enableTimer("vdragtimer")
 +
end
 +
</syntaxhighlight><br>
  
 +
Create the callback function which will be called when we release the drag icon.
 +
<syntaxhighlight lang="lua">
 +
function onVDragRelease()
 +
  -- Button is release so stop timer and updates.
 +
  disableTimer("vdragtimer")
 +
end
 +
</syntaxhighlight>
 +
 +
====Set up the callback functions====
 +
Set up the limit how small the window can be, and setup the callback functions.
 +
<syntaxhighlight lang="lua">
 +
MAX_HEIGHT = 100
 +
--
 +
-- Set mouse event callbacks.
 +
--
 +
setLabelClickCallback("mVDrag", "onVDragClick")
 +
setLabelReleaseCallback("mVDrag", "onVDragRelease")
 +
</syntaxhighlight>
 +
 +
====Final result====
 +
The whole script looks like this:
 +
 +
<syntaxhighlight lang="lua">
 +
--
 +
-- Example: Resize a label.
 +
--
 +
-- Creates a blue label with a smaller white label, which is
 +
-- used to resize the blue label.
 +
--
 +
-- Utilizing:
 +
-- * getMousePosition()
 +
-- * setLabelClickCallback()
 +
-- * setLabelReleaseCallback()
 +
-- * tempTimer().
 +
--
 +
 +
--
 +
-- Create labels
 +
--
 +
mLabel = Geyser.Label:new({
 +
  name = "mLabel",
 +
  x = 400, y = 200,
 +
  width = 200, height = 200,
 +
})
 +
mLabel:setStyleSheet([[
 +
  background-color: rgba(30, 30, 30, 80%);
 +
  qproperty-wordWrap: true;
 +
]])
 +
mLabel:setFontSize(10)
 +
mLabel:echo([[<center>Drag the white label to resize.</center>]])
 +
 +
--
 +
-- Create the small drag label within the window.
 +
-- The y position is set to "-15px" to align it to
 +
-- the bottom of the main label.
 +
mVDrag = Geyser.Label:new({
 +
  name = "mVDrag",
 +
  x = 85, y = "-15px",
 +
  width = 30, height = 15,
 +
  fgColor = "black",
 +
  color = "white",
 +
}, mLabel)
 +
mVDrag:setStyleSheet([[
 +
  border-radius: 6;
 +
  background-color: white;
 +
]])
 +
 +
MIN_HEIGHT = 100
 +
 +
--
 +
-- Callback functions.
 +
--
 +
function onVDragTimer()
 +
  local x
 +
  local y
 +
  local height
 +
 +
  -- Get mouse position
 +
  x, y = getMousePosition()
 +
 +
  -- Substract the top of the label  to get the new height.
 +
  height = y - 200
 +
  if height < MIN_HEIGHT then
 +
    -- Height is too small.
 +
    height = MIN_HEIGHT
 +
  end
 +
 +
  -- Set the new size and restart timer.
 +
  mLabel:resize(200, height)
 +
end
 +
 +
function onVDragClick()
 +
  -- The user clicked the drag label.
 +
  -- Start a temp timer to update the size of the label.
 +
  if not exists("vdragtimer", "timer") then
 +
    vdragtimer = permTimer("vdragtimer", "", .016, "onVDragTimer()")
 +
  end
 +
 +
  enableTimer("vdragtimer")
 +
end
 +
 +
function onVDragRelease()
 +
  -- Button is release so stop timer and updates.
 +
  disableTimer("vdragtimer")
 +
end
 +
 +
--
 +
-- Set mouse event callbacks.
 +
--
 +
setLabelClickCallback("mVDrag", "onVDragClick")
 +
setLabelReleaseCallback("mVDrag", "onVDragRelease")
 +
</syntaxhighlight>
 
[[Category:Mudlet Manual]]
 
[[Category:Mudlet Manual]]

Revision as of 15:29, 26 March 2020

Introduction

The Geyser Layout Manager is an object oriented framework for creating, updating and organizing GUI elements within Mudlet - it allows you to make your UI easier on Mudlet, and makes it easier for the UI to be compatible with different screen sizes.

Motivation

Mudlet makes the creation of label, miniconsoles and gauges a quick and easy thing. Mudlet provides a nice signal when window resize events happen. To help with complex window management, Geyser steps in.

Main Geyser Features

Geyser is based on traditional GUI concepts and should feel similar to using Java's Swing. The biggest difference is in how positions are specified.

  • All window positions are specified relative to their container - nothing new there. However, window positions can also take on percentages and negative pixel and character values. For instance, a window could be constrained to have a height of 50% of its container and a width such that the window's right edge is always 20 characters from its container's right edge. See examples below and the demos/tests that come with Geyser.
  • All windows under Geyser control are automatically resized as necessary when the main Mudlet window is resized. Once you create a window and assign it to a container, you never have to worry about positioning it again. Nonetheless, it's very easy to shift the container that a window is in, maintaining its constraints so that it resizes as needed according to the dimensions of the new container.
  • Due to the container hierarchy, hiding a container window automatically hides all its contained windows too. The same for show. With clever construction and labels with callbacks, this lets one make complex GUI elements that are minimizable or maximizable or ...
  • However, there is always some overhead for automation systems and Geyser is no exception. Fortunately, most of the overhead is during window creation and resize events - not things that happen frequently.

Getting pictures for your stuff

You can find good, freely-available assets for your UI here:

Constraints format

Geyser position constraints are a string composed of a number and a format type. For example, "10px" means 10 pixels, either pixels from the origin (e.g. x or y) or a value for the width or height. A negative number indicates distance from a container's right or bottom border depending on whether is a constraint for x/width or y/height, respectively. Percentages for width and height are in terms of the container's dimensions and negative values are converted to the equivalent positive value. A 100% width subwindow with an x-coordinate of 10 will have part of itself displayed outside the confines of its container. There is no hard limit on maximum window size, just as with regular Mudlet windows. If a number, n, is passed as a constraint instead of a string, it is assumed to be equivalent to "npx". Any Lua table that contains entries for x, y, width and height in the proper format can be used for Geyser constructors and setting constraints. Just like in Mudlet, 0,0 coordinates mean the top-left corner.

The following is a valid example for coordinates of a Geyser object:

{x = "20px", y = "-10c", width = "40%", height = 30}

Geyser elements

The purpose of this document is to go through every Geyser element and provide practical examples on how they are used. Read it from top to bottom, preferably doing all of the examples to understand how they work!

See also: https://www.mudlet.org/geyser/files/index.html for a brief and technical overview of all elements and their functions.

Geyser.Container

An invisible, organizing object in Geyser - use it to divide your screen and position elements accordingly. See here for all of the functions that are available to you to use.

A container is also the base class - which means that everything (labels, miniconsoles and gauges) can use its functions, since everything else is at heart a container.

Creating a container

To get started with a container, here's an example that'll create a 200px border on the left side of Mudlet for you, and make a container cover all of it - so you can place other visual elements inside it:

setBorderLeft(200)
left_container = Geyser.Container:new({
  name = "left_container",    -- give it a unique name here
  x=0, y=0,                   -- have it start at the top-left corner of mudlet
  width = 200, height="100%", -- with a width of 200, and a height of the full screen, hence 100%
})

Right away, you'll see space appear on the left side. It'll be black, as the container is an invisible unit by itself. You can make sure it's there by making it flash by doing this from the input line:

lua left_container:flash()

The command will cause your container to flash for a moment for you, revealing itself.

Container within a container

You can place containers within other containers by specifying which "parent" the new container should have when you create one. Given our previous example, you can split the left side into two halves like this:

left_container_top = Geyser.Container:new({
  name = "left_container_top",
  x=0, y=0,                     -- this container occupies the top, so it starts top-left as well
  width = "100%", height="50%", -- but only uses up half of the height
}, left_container)              -- this is the important bit - it says that left_container_top should be inside left_container

left_container_bottom = Geyser.Container:new({
  name = "left_container_bottom",
  x=0, y="50%",                 -- this container starts halfway down the first one
  width = "100%", height="50%", -- and has the same half height of the original container
}, left_container)

Aligning relative to bottom or right sides

The aligning point within Mudlet is the top-left corner, and it's the same for the elements they are aligned - the position you specify is used by the top-left corner of the element.

Using Geyser, you can align to the opposite side as well, using the coordinates in negatives, while keeping the dimensions of the object in mind. For example, if you want to align a box that's 20px wide on the usual left side, you'd give it a width of 20 and an x value of 0. If you'd like to align it on the right side, then you'd give it an x value of -20. The box will spawn 20px away from the right side and "grow" to the right by 20px.

right_container = Geyser.Container:new({
  name = "right_container",
  x="-20%", y=0,                    -- makes the container start 20% of the screen away from the right side
  width = "20%", height="50%",      -- filling it up until the end
})

Do make sure to account for the scrollbar, as Mudlet UI elements can overlap it. You can also move the scrollbar with setBorderRight().

Geyser.Label

Based on the Mudlet label, this allows you to use the labels functionality within Geyser. Labels allow you to use pictures in your interface, as well as nicely-formatted text.

Basic label

Here's an example to get you started with:

testlabel = Geyser.Label:new({
  name = "testlabel",
  x = "50%", y = 0,
  width = "50%", height = "100%",
  fgColor = "black",
  color = "SeaGreen",
  message = [[<center>heey</center>]]
})

This labels x coordinate is specified as 50% - and because it's not attached to any container, this implies that the window will start halfway at the main window. You can tell it's not attached to a container because there's nothing in between the last } and ), the place where the container goes.

The y coordinate is 0 - which means that the label will start at the top of the screen. With the width being 50%, the label will occupy 50% of the screen - and since it starts at the halfway point, it means it'll occupy the entire right side. A height of 100% means that it'll stretch from the top to the full bottom.

Here's what that'll look like:

Simple-label.png


Playing around with the starting location and dimensions, we can also place it in the center of the screen with:

testlabel = Geyser.Label:new({
  name = "testlabel",
  x = "25%", y = "25%",
  width = "50%", height = "50%",
  fgColor = "black",
  message = [[<center>heey</center>]]
})
testlabel:setColor(0,255,0,150)
Simple label centered.png

To change the message on a label, you can use the mylabel:echo() function, where mylabel is the name of the label you gave it:

mylabel:echo("hello!")

Setting the font size

To set a different font size for your Label, use the setFontSize() method. For example:

testlabel:setFontSize(14)

The font size is set in Pt, so anything above 30 will likely be too large to be useful.

Label inside a container

Once you've got your containers and mastered the basic labels, you can drop labels into your nicely-organized containers. Doing so is similar to nesting containers:

testlabel = Geyser.Label:new({
  name = "testlabel",
  x = "25%", y = "25%",
  width = "50%", height = "50%",
  fgColor = "black",
  message = [[<center>heey</center>]]
}, left_container_bottom) -- this is where we tell it what container to go into
testlabel:setColor(0,255,0,150)

That label is exactly the same as the one above that goes across the screen, except it's in our bottom-left container - so it looks appropriately different:

Label in a container.png

Image on a label

One of the more amazing things labels allow you to do is put pictures anywhere on your Mudlet screen, that blend in very well. To do so, once the label is created, use the setBackgroundImage() function with the exact path to the image (Skullface.png):

picture_label = Geyser.Label:new({
  name = "picture_label",
  x = 0, y = "-14px",
  width = "16px", height = "14px",
})
picture_label:setBackgroundImage([[/home/vadi/Desktop/skullface.png]]) -- update location to actual image location on your computer

This'll plop the picture to the bottom-left of your screen. To make the picture show, download the skullface picture above - save it to your desktop, and adjust the location of the image within [[]]'s to what it is on your computer. For example, if you saved this on your Windows 7 desktop, it would be:

picture_label:setBackgroundImage([[C:/Users/<your user name>/Desktop/skullface.png]])

(yes, that's / and not \ - \ has been known not to work)

If you saved this on your Mac desktop, it would be:

picture_label:setBackgroundImage([[/Users/<your user name>/Desktop/skullface.png]])

If you saved this on your Ubuntu desktop, it would be:

picture_label:setBackgroundImage([[/home/<your user name>/Desktop/skullface.png]])

Using this basic building block, you can work up to making yourself a UI!

Stretching an image on a label

If you'd like your image not to keep it's original size, but instead use up the available space of the label - you can use the border-image stylesheet property to do so.

label = Geyser.Label:new({
  name = "label",
  x = "50%", y = "50%",
  width = "50%", height = "50%",
})

-- change the location to your picture
-- on windows, use / to separate folders still, not \
label:setStyleSheet[[
  border-image: url(/home/vadi/Desktop/iso-avatar-draft_0.png);
]]

Note Note: If you're on a Mudlet earlier than 3.15 and are having difficulty with the image coming up, it may be because of strange differences between Qt's CSS engine which does not affect mudlet's Lua. You may want to try appending :gsub("\\","/") to your string including getMudletHomeDir() (e.g. getMudletHomeDir():gsub("\\","/")). No longer necessary after Mudlet 3.15.

Aligning an image within a label

You can use background-image in combination with background-position to align an image within a label (if, say, the image is much smaller than the label).

-- this will set and align an image top-right of the label
if stunning then
  mylabel:setStyleSheet([[
    background-image: url("/home/vadi/Games/Mudlet/Offensive/Artwork/dialog-ok.png");
    background-repeat: no-repeat; background-position: top right; background-origin: margin;
  ]])
else
  mylabel:setStyleSheet([[
    background-image: url("/home/vadi/Games/Mudlet/Offensive/Artwork/dialog-no.png");
    background-repeat: no-repeat; background-position: top right; background-origin: margin;
  ]])
end

Showing / hiding a label

You can show and hide labels, as you can any container, miniconsole or a gauge in Geyser with Geyser.Container:show() and Geyser.Container:hide(). Remember that since labels are a type of a container, all container functions work on them.

Hiding a label will allow you to click through on what is below the label, as well as free up the visual space for something else.

testlabel = Geyser.Label:new({
  name = "testlabel",
  x = "50%", y = 0,
  width = "50%", height = "100%",
  fgColor = "black",
  color = "SeaGreen",
  message = [[<center>heey</center>]]
})

-- hide the label with:
testlabel:hide()

-- show the label with:
testlabel:show()

Clickable images

Tacking onto the fact that you can plop images anywhere on your Mudlet screen now, you can also make them react to your clicks. You can do so with the setClickCallback() function - by giving it a function to call when your label is clicked, you'll make it react.

picture_label = Geyser.Label:new({
  name = "picture_label",
  x = "-215px", y = "0px",
  width = "200px", height = "200px",
})
picture_label:setBackgroundImage([[/home/vadi/Desktop/qubodup-opengameart-cc0-200px-missile_icon.png]]) -- update location to actual image location on your computer
picture_label:setClickCallback("on_bomb_press")

function on_bomb_press()
  send("say BOOM!")
end

That's it! Pressing on the image will make the on_bomb_press() function go off, which will do its code of send("say BOOM!"). Download the picture for use here.

Clickable image.png

Styling labels

Besides putting text or images on labels, you can also style them using Qt's stylesheets feature. Doing so allows you to create various graphics that make the label look more appealing:

Label styling examples.png

To set a stylesheet on a label, use the Geyser.Label:setStyleSheet() function on your label, describing the stylesheet you'd like to give it. A stylesheet consists of properties you set - for example the background color, borders, padding, and so forth. You describe properties in the following format: property name:values;. See here for a list of all supported properties. For example, to make your labels background be yellow, you'd use the background-color property:

mylabel = Geyser.Label:new({
  x = "50%", y = "50%",
  width = 200, height = 100
})

mylabel:setStyleSheet([[
  background-color: yellow;
]])
Basic stylesheet.png

Which is nice, but not particularly impressive.

Scrolling down the list of properties, you'll come along a border one. Plopping it into our stylesheet nets the following:

mylabel:setStyleSheet([[
  background-color: yellow;
  border: 5px solid white;
]])
Basic stylesheet border.png

Which gives a border!

Fiddling with it some more and applying new properties we find on that page, we get a rounded border on our label:

mylabel:setStyleSheet([[
  background-color: grey;
  border-width: 15px;
  border-style: solid;
  border-color: green;
  border-radius: 10px;
]])
Basic stylesheet border radius.png

Which'll conclude our exploration for now. Try out all of the other possible options available there - there's loads, from funky borders, to tiling images and fancy color combinations using gradients.

Adding a tooltip to a label

Since Mudlet 4.6, you can now add a tooltip to labels and gauges. You can start by making a simple label and echoing some text to it:

testLabel = Geyser.Label:new({
  name = "testLabel",
  x = "50%",
  y = "50%",
  height = "25%",
  width = "25%",
})
testLabel:echo("This is on the label!")
testLabel:setAlignment("center")
-- sets the tooltip text
testLabel:setToolTip("This is the tooltip", "10")
-- and gives it some style!
testLabel:setStyleSheet("QToolTip{background: yellow; color: blue; border:none;}")

Without tooltip

TestLabelForTooltips.png

With tooltip

LabelTooltip.png

Aligning text/images inside a label

By default, text is centered vertically and left aligned in a label. To align it to a specific side, use the stylesheets we learnt about earlier with the qproperty-alignment:

mylabel = Geyser.Label:new({
  name = "testlabel",
  x = "50%", y = 0,
  width = "50%", height = "100%",
  fgColor = "black",
  color = "SeaGreen",
  message = [[<center>heey</center>]]
})

-- specify one property this way:
mylabel:setStyleSheet([[qproperty-alignment: 'AlignTop';]])

-- or multiple ones separated with a |, for example this will align text to top-left:
-- specify one property this way:
mylabel:setStyleSheet([[
  qproperty-alignment: 'AlignLeft | AlignTop';
]])

mylabel:echo("hi!")
Text aligned.png

Enabling wordwrap in a label

If you need to enable word wrapping in a label (which by default is off), add the following line to the labels stylesheet:

 qproperty-wordWrap: true;

As an example:

mylabel:setStyleSheet([[
  qproperty-wordWrap: true;
]])

If you'd like to set multiple properties, set them all at once - not via multiple :setStyleSheet() calls:

mylabel:setStyleSheet([[
  background: red;
]])

Adding a hover effect to a label

The labels support adding stylesheets for specific cases, such as when a mouse is hovering over them. To make this work, you provide CSS for when the label is in its usual state, and for when it is hovered over:

-- this example will add a border to the label when it is hovered over
mylabell:setStyleSheet([[
  QLabel{ border-radius: 4px; }
  QLabel::hover{
    background-color: rgba(0,0,0,0%);
    border: 4px double green;
    border-radius: 4px;
  }
]])

Checkboxes

Combining the fact that you can click on a label with an image to do something with the fact that you can change pictures on a label at will, you can make an image that changes itself when you click on it.

picture_label = Geyser.Label:new({
  name = "picture_label",
  x = "50%", y = "50%",
  width = "21px", height = "19px"
})
-- a little trick we do to make the background of the label be transparent
picture_label:setStyleSheet([[
  background-color: rgba(0,0,0,0%);
]])

picture_label:setBackgroundImage([[/home/vadi/Desktop/checkbox_ticked.png]])
picture_label:setClickCallback("on_checkbox_press")

function on_checkbox_press()
  if checkbox_ticked then
    checkbox_ticked = false
    picture_label:setBackgroundImage([[/home/vadi/Desktop/checkbox_unticked.png]])
    echo("Checkbox unticked.\n")
  else
    checkbox_ticked = true
    picture_label:setBackgroundImage([[/home/vadi/Desktop/checkbox_ticked.png]])
    echo("Checkbox TICKED!\n")
  end
end

The on_checkbox_press() function this time keeps the track of the checkbox with the checkbox_ticked variable and sets the image appropriately. You can download the ticked (Checkbox ticked.png) and unticked images (Checkbox unticked.png) or the whole package altogether.

Checkbox demo.png

Animated labels

Using timers and several pictures, you can make your labels change quickly enough and look animated. Here's one such example:

picture_label = Geyser.Label:new({
  name = "picture_label",
  x = 10, y = "-24px",
  width = "16px", height = "14px",
})

santa_counter = nil

function animate_santa()
  santa_counter = (santa_counter or 0) + 1
  if santa_counter > 8 then santa_counter = 1 end

  picture_label:setBackgroundImage([[/home/vadi/Desktop/santa/santa]]..santa_counter..[[.png]]) -- update location to actual image location on your computer
  santa_timer = tempTimer(.16, animate_santa)
end

animate_santa()

The completed package is available here, install it and do start/end animation to watch.

Inserting extra spaces and newlines

Echoing text into Mudlet and Geyser labels is different from miniconsoles and the main window, due to their nature. One of the differences is that extra spaces in a label, by default, get compressed down to one. To add extra spaces in a label, replace extra spaces with &nbsp; or by wrapping your text with them inside <pre>my text here</pre>.

-- this won't work, it'll show as one space:
mylabel:echo("You       ->      point")

-- but this would, because it replaces all spaces with &nbsp before echoing
mylabel:echo(string.gsub("You       ->      point", " ", "&nbsp;"))
-- here is another way to go about this - and it additionally makes the font be monospaced:
mylabel:echo("<pre>You       ->      point</pre>")

To add a new line in a label (aka linebreak), use
(instead of \n as you are used to in an echo).

mylabel:echo("These<br>words<br>are<br>split")

Transparent labels

One of the possible ways of achieving transparency on a label is to add background-color: rgba(0,0,0,0%); to its stylesheet. Here's an example:

my_transparent_label:setStyleSheet([[
  background-color: rgba(0,0,0,0%);
]])

Change Label Mouse Cursor

Since Mudlet 4.7 it is possible to change the shape of your mouse cursor if you put it over your Label by using for example:

mylabel:setCursor("Forbidden") -- will change your mousecursor to a forbidden cursor

Possible cursor shapes are available here.

It is also possible to change the mouse cursor to a custom made cursor by:

mylabel:setCustomCursor(getMudletHomeDir().."/custom_cursor.png")

It is recommended the the custom cursor is a png with size of 32x32 to be supported on all systems.

Changecursoroverlabel.gif

Flyout Labels

Flyout labels allow you to create 'dropdown' or 'flyout' menus - menus that reveal more items once you hover your mouse over them. To create flyout labels:

  1. add nestable=true (left click to open menu) or nestflyout=true (mouse hover to open menu) to your main label.
  2. use :addChild() on your main label to add flyout labels to it.
    1. :addChild() uses the same arguments as when creating a new label but also takes the layoutDir option to specify in which direction and axis should the labels align, where 2 letters combine into the option: first letter R for right, L for left, T for top, B for bottom, followed by the orientation: V for vertical or H for horizontal. So options are: layoutDir="RV", layoutDir="RH", layoutDir="LV", layoutDir="LH", and so on.
  3. optionally, add flyOut=true to your flyout labels to make the labels dissapear when the mouse isn't hovering over them anymore.

Note that the main flyout label cannot go into a container and needs to be on its own.

Note Note: Requires Mudlet 3.0.

Demo

Here's an example that follows the steps above:

label0 = Geyser.Label:new({name="label0", 
  x="50%",y="50%",height=50,width=300,nestable=true, 
  message="<center>Clicky clicky</center>"})
 
-- and add 3 labels to it with RV layout - so Right of the label, aligned Vertically
label1 = label0:addChild({name="label1",height=30,width=70, layoutDir="RV", flyOut=true, message="label one"})
label1:setStyleSheet([[background-color: purple;  border-width: 2px;  border-style: solid;  border-color: blue;  border-radius: 2px;  font-size: 7pt;]])

label2 = label0:addChild({name="label2",height=30,width=70, layoutDir="RV", flyOut=true, message="label two"}) 
label2:setStyleSheet([[background-color: green;  border-width: 2px;  border-style: solid;  border-color: blue;  border-radius: 2px;  font-size: 7pt;]])

label3 = label0:addChild({name="label3",height=30,width=70, layoutDir="RV", flyOut=true, message="label three"})
label3:setStyleSheet([[background-color: red;  border-width: 2px;  border-style: solid;  border-color: blue;  border-radius: 2px;  font-size: 7pt;]])

A more thorough example. Try it out to see what you can create with flyout labels:

-- create a label with a nestable=true property to say that it can nest labels
mainlabel = Geyser.Label:new({name="testa", x=400,y=50,height=50,width=300,nestflyout=true, message="<center>HOVER HERE TO SEE FLY-OUT LABELS!</center>"})
 
-- create 15 labels and store them in a table 
table_for_flyout_labels = {}
for i=1,15 do
  -- options to layoutDir are the direction the window should go (R for right, L for left, T for top, B for bottom), followed by how the nested labels should be oriented (V for vertical or H for horizontal). So "BH" here means it'll go on the bottom of the label, while expanding horizontally
  table_for_flyout_labels[i] = mainlabel:addChild({name="test"..tostring(i),height=30,width=70, layoutDir="BH", flyOut=true, message="test"..tostring(i)})
 
  table_for_flyout_labels[i]:setStyleSheet([[background-color: purple;  border-width: 2px;  border-style: solid;  border-color: blue;  border-radius: 2px;]])
end

-- make the test5 label look a bit special as it has got a surprise
table_for_flyout_labels[5]:echo("Hover here")
 
-- add even more nested labels to the 5th label!
even_more_flyout_labels = {}
for i=1,60 do
  -- here, the layout will be to the right of it, while expanding vertically
  even_more_flyout_labels[i]=table_for_flyout_labels[5]:addChild({name="hover label "..tostring(i),height=30,width=100, layoutDir="RV", flyOut=true, message="label "..tostring(i)})
  even_more_flyout_labels[i]:setClickCallback("testFunc", even_more_flyout_labels[i].name)
  even_more_flyout_labels[i]:setStyleSheet([[background-color: grey;   border-width: 2px;  border-style: solid;   border-color: green;  border-width: 2px;  font-size: 7pt;]])
end

function testFunc(name)
  display(name)
end

It'll look something like this:

Flyout labels demo.png

Demo of layouts

Here's another demo that explains all of the layout styles quite well:

local directions = {"R", "L", "T", "B"}
local orientations = {"V", "H"}
local mappings = {R = "right", L = "left", T = "top", B = "bottom", V = "vertical", H = "horizontal"}

local combinations, combination_labels = {}, {}
for _, direction in pairs(directions) do
  for _, orientation in pairs(orientations) do
    combinations[#combinations+1] = direction..orientation
  end
end

local function get_foreground_text_colour(r,g,b)
  local luminosity = (0.2126 * ((r/255)^2.2)) + (0.7152 * ((g/255)^2.2)) + (0.0722 * ((b  /255)^2.2))
  if luminosity > 0.5 then
    return "black"
  else
    return "white"
  end
end

local function get_random_colour_rgb()
  return math.random(1,255), math.random(1,255), math.random(1,255)
end

-- create a label with a nestable=true property to say that it can nest labels
all_possible_combinations_label = Geyser.Label:new({name="all_possible_combinations_label", x=0,y="-400",height=50,width=500,
  nestable = true, message="<center>Click to see a listing of possible combinations</center>"})

for i = 1, #combinations do
  local combination = combinations[i]
  combination_labels[i] = all_possible_combinations_label:addChild({name="combo_"..combination,height=30,width=150, nestable = true, flyOut=true, layoutDir="BH", message="<center>Combination "..combination.."</center>"})
 
  local r,g,b = get_random_colour_rgb()
  local text_colour = get_foreground_text_colour(r,g,b)

  local combination_labels_children = {}
  for ii = 1, 3 do
    combination_labels_children[ii] = combination_labels[i]:addChild({
      name="combo_"..combination.."_"..ii, height = 30, width = 150, layoutDir=combination, flyOut = true,
        message = string.format("<center><b>%s</b>%s+<b>%s</b>%s layout</center>", 
        combination:sub(1,1), mappings[combination:sub(1,1)]:sub(2), combination:sub(2,2), mappings[combination:sub(2,2)]:sub(2)),
      fgColor = text_colour})
    
    combination_labels_children[ii]:setStyleSheet(string.format([[background-color:rgb(%d, %d, %d); border-width: 2px; border-style: solid; border-color: green; border-width: 2px; font-size: 7pt;]], r,g,b))
  end
end

It'll look like this:

Flyoutlabels-layout-demo.png

Background for Mudlets buttons

You can give Mudlets buttons a background to have them blend in with your UI by doing this:

-- replace the /home/vadi/Pictures/tile.png location below with the one of your picture!
-- you can download the sample tile.png from https://opengameart.org/content/bevouliin-free-game-background-for-game-developers
local backgroundpath = [[/home/vadi/Pictures/tile.png]]
-- Windows:
-- local backgroundpath = [[C:/Users/Vadim/Downloads/Free game background/transparent PNG/tile.png]]

setAppStyleSheet([[
QToolBar {
  border-image: url(]]..backgroundpath..[[);

}

QToolBar QToolButton:!hover {
  color: white;
}
QToolBar QToolButton:hover {
  color: black;
}
]])

Result:

Mudlet tiled buttons.png


Geyser.MiniConsole

This allows you to spawn a Mudlet miniconsole - unlike labels, these aren't as styleable, but they do format text better. They make a good fit for text-based menus, chat and map capture, and other things.

Spawning one is very similar to other Geyser elements - paste this into a new script:

HelloWorld = Geyser.MiniConsole:new({
  name="HelloWorld",
  x="70%", y="50%",
  autoWrap = true,
  color = "black",
  scrollBar = false,
  fontSize = 8,
  width="30%", height="50%",
})

This'll make you one at the bottom-right of the screen. The miniconsole will have a grey background by default, but you can set it to any color you'd like with miniconsole:setColor():

HelloWorld:setColor("black") -- give it a nice black background

A special dimension property that MiniConsoles have is a character - instead of specifying a miniconsole to be % of a container or a certain number of pixels, you can specify it as a certain number of characters. You do this by using "c" at the end of a number. This way, you can, for example, specify miniconsole to be 10 letters long and 2 lines high:

flatbox = Geyser.MiniConsole:new({
  name="flatbox",
  x="70%", y="50%",
  wrapAt = 10,
  width="10c", height="2c",
})
flatbox:setColor("red")
flatbox:echo("ABCDEFGHIJ") -- that is 10 letters

Adding text

You can use echo() the same way with a miniconsole to add text as to the usual window:

HelloWorld:echo("hello!")

As well as cecho, decho, or hecho:

HelloWorld:cecho("<green>hey, <blue>colored <red>text!\n")

Copying lines with color

To copy a line over to the miniconsole, as it is from the game with all colors preserved, you can select, copy, and append it. For an example, try making a trigger with this as the Lua function pattern type:

return true

That'll make the trigger go off on every line. Then give it the following script (assumed you have made the HelloWorld miniconsole from earlier):

selectCurrentLine()
copy()
HelloWorld:appendBuffer()

... and you'll see all MUD output duplicated exactly as it is to the miniconsole. Amazing! It's very efficient as well, so you can have many miniconsoles, even in spam, not lag you down.

Doing edits in copied lines

Sometimes you'll want to edit the line before stuffing it into the miniconsole. For example, if you're making a chat capture, you'd want to condense a really long org name into something that's more space-friendly.

To do so, you'd use the selectString() the text you'd like to modify, replace() it with a different one:

selectString("Your", 1)  -- select the word you'd like to replace - in this case, 'Your'
setBgColor(getBgColor()) -- preserve the background color in the replacement
setFgColor(getFgColor()) -- preserve the foreground color in the replacement
replace("Mine")          -- replace the selection with the wird 'Mine'

selectCurrentLine()
copy()
HellowWorld:appendBuffer()

Gagging from the main window

If you'd like to gag the line from the main window so it only shows up in your miniconsole, delete it after moving it over:

selectCurrentLine()
copy()
HellowWorld:appendBuffer()
deleteLine()

Clickable menus

Using the echoLink, insertLink and setLink functions, you can turn text into one that reacts on a click. Combined with your power of placing text anywhere on the screen with a miniconsole, you can make menus with options. Here is one such example, where selecting an item causes an echo to happen:

flatbox = Geyser.MiniConsole:new({
  name="flatbox",
  x="20%", y="80%",
  width="40c", height="4c",
})
flatbox:setColor("red")
clearWindow("flatbox")

flatbox:cecho("<white:red>Choose one of the following options:\n")

flatbox:fg("white")
flatbox:bg("red")

for _, fruit in ipairs{"banana", "apple", "orange"} do
  echoLink("flatbox", "* "..fruit:title().."\n", [[echo("You picked ]]..fruit..[[\n")]], "The "..fruit.." option", true)
end

resetFormat()

Which'll look something like the following:

Fruit menu.png

Geyser.Gauge

A Gauge allows you to represent numbers on a scale - and most typically, you've seen it be used as your standard hp/mana/whatever bar. A basic bar is made similarly to other Geyser elements. To set the value on the gauge that it should represent, use the setValue() function:

hpbar = Geyser.Gauge:new({
  name="hpbar",
  x="50%", y="85%",
  width="45%", height="5%",
})
hpbar:setValue(math.random(1,100),100)

That'll spawn you a pretty basic gauge with a horizontal orientation and a grey colour - and as a test, with a random value.

Basic gauge.png

Updating a gauge

You'd want your gauge to stay in sync with your actual values. To make that happen, you want to call setValue() whenever the value that the gauge is tracking changes.

So for example, if you make a health bar - wherever you get your new health at (be it prompt, gmcp, atcp or whatever), update the gauge as well:

-- theoretical example
current_health, max_health = tonumber(matches[2]), tonumber(matches[3])

-- update the bar
hp_bar:setValue(current_health, max_health)

You can also write down how much health have you got on the bar with:

lua local hp = math.random(1,100) 
hpbar:setValue(current_health, max_health, "<b>"..max_health.."hp</b>")

-- example using GMCP in IRE games:
hpbar:setValue((100/gmcp.Char.Vitals.maxhp)*gmcp.Char.Vitals.hp,100,gmcp.Char.Vitals.hp)
Hpbar basic.png

Styling a gauge

The Geyser gauge is composed of three labels - one is called mygauge.front, mygauge.back and mygauge.text. Combining this with Geyser:Label.setStyleSheet, you can improve the visuals of your gauges by using Qt-supported CSS. The syntax for specifying CSS is a bit different - it requires a semicolon after every property, and is done in the format of property name:values;. A list of all possible properties you can use is available here and you can use Qt Designer to create them. Practical example:

hpbar = Geyser.Gauge:new({
  name="hpbar",
  x="50%", y="85%",
  width="45%", height="20px",
})
hpbar.front:setStyleSheet([[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #98f041, stop: 0.1 #8cf029, stop: 0.49 #66cc00, stop: 0.5 #52a300, stop: 1 #66cc00);
    border-top: 1px black solid;
    border-left: 1px black solid;
    border-bottom: 1px black solid;
    border-radius: 7;
    padding: 3px;
]])
hpbar.back:setStyleSheet([[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #78bd33, stop: 0.1 #6ebd20, stop: 0.49 #4c9900, stop: 0.5 #387000, stop: 1 #4c9900);
    border-width: 1px;
    border-color: black;
    border-style: solid;
    border-radius: 7;
    padding: 3px;
]])

hpbar:setValue(math.random(1,100),100)
Fancy Geyser gauge.png

The same style can be adjusted by colors to red as well:

hpbar = Geyser.Gauge:new({
  name="hpbar",
  x="50%", y="85%",
  width="45%", height="20px",
})
hpbar.front:setStyleSheet([[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f04141, stop: 0.1 #ef2929, stop: 0.49 #cc0000, stop: 0.5 #a40000, stop: 1 #cc0000);
    border-top: 1px black solid;
    border-left: 1px black solid;
    border-bottom: 1px black solid;
    border-radius: 7;
    padding: 3px;]])
hpbar.back:setStyleSheet([[background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #bd3333, stop: 0.1 #bd2020, stop: 0.49 #990000, stop: 0.5 #700000, stop: 1 #990000);
    border-width: 1px;
    border-color: black;
    border-style: solid;
    border-radius: 7;
    padding: 3px;]])

hpbar:setValue(math.random(1,100),100)
Fancy Geyser gauge red.png

Updating a gauge

The Geyser gauge is composed of three labels - one is called mygauge.front, mygauge.back and mygauge.text. To make a gauge clickable you can set a ClickCallBack on the top label which is mygauge.text example:

mygauge.text:setClickCallback("functionName", variableToSendToFunctionName)


If you would like to have different click events for the top or back of a gauge you can enable clickThrough for the top or mygauge.text label example

mygauge.text:enableClickthrough()
mygauge.front:setClickCallback("functionOne", variableToSendToFunctionOne)
mygauge.back:setClickCallback("functionTwo", variableToSendToFunctionTwo)

HBox/VBox

These are special types of containers. Every window in these is horizontally or vertically aligned in the order they were added.

Added to Mudlet in 2.0-rc4

Geyser.UserWindow

Allows you to use Mudlets UserWindows within Geyser. Which allows you to use all the functionality of a MiniConsole in it‘s basic form. The big advantage is the possibility to add other Geyser Elements like Labels, MiniConsole, Gauges, Mappers to the UserWindow. The UserWindow then can act as container for those elements with all the perks of dynamic resizing or any other Geyser functionality.

Note Note: available in Mudlet 4.6.1+

Basic floating UserWindow

This will create a movable floating UserWindow.

testuserwindow = Geyser.UserWindow:new({
  name = "TestUserWindow",
  x = "20%", y="20%",
  width="30%", height ="40%"
})

Docked UserWindow

To create the window docked at the right side (for now only right side is possible on creation) Set the variable docked (at creation of the container) to true. Be aware that with this variable set to true the position and the size at creation of the userwindow will be ignored.

testuserwindow = Geyser.UserWindow:new({
  name = "DockedTestUserWindow",
  docked = true

})

UserWindow as Container

This is the feature which shows the versatile nature of Geyser.UserWindows. The UserWindow act as container and is at that possible to dynamically resize the containing Geyser Elments. Put a label in the UserWindow resize it as rectangle.

testuserwindow = Geyser.UserWindow:new({
  name = "ParentTestUserWindow",
  x = "20%", y="20%",
  width="30%", height ="40%"
})

testuserwindow:setColor("dark_green") -- give the userwindow a bit of color 

labelinuserw = Geyser.Label:new({
  name = "LabelinUserWindow",
  x=20, y=20,
  width = -20, height = -20,
  color="light_blue", fontSize=20,
  },testuserwindow)
  
 labelinuserw:echo("This is a label in an userwindow", "black", "c")

LabelInUserWindow.png

The same way you are able to add your favorite Geyser Application (like tabbed chat, animated timers, gauges) to an UserWindow.

Tabbedchatinuserwindow.png

Change Container

Note Note: available in Mudlet 4.7+

With this command it is possible to change an elements or even a containers location to that from another container. For example:

mycontainerone:changeContainer(mycontainertwo)
--puts container one into container two which means container two will be the parent of container one

It is also possible to change to a container which is not located on the main window:

myEmco:changeContainer(emco_userwindow)
--puts my tabbed chat Emco into my userwindow
--to put it back to the main window change to a container located on the main window
myEmco:changeContainer(mymainwindow_container)
--or if it the element wasn't in a container use the main Geyser Root container called Geyser
myEmco:changeContainer(Geyser)

Create Map Window

Note Note: available in Mudlet 4.7+

It‘s possible to create the mapper as a map window (similar to clicking the icon) like this:

myMapWidget = Geyser.Mapper:new({embedded= false})

This will open a map window with your saved layout (if there is one, otherwise it will dock at the right corner)

To choose the position of the DockWindow at creation use: (this will create a map window docked at the left corner)

 
myMapWidget = Geyser.Mapper:new({embedded= false, dockPosition=“left“})

Possible dockPositions are left "l", right "r", top "t", bottom "b" and floating "f"
To change the dockPosition after creation use:

 
myMapWidget:setDockPosition("f")
-- this will change myMapWidget dockPosition to "f" floating

Tutorial

Note: This tutorial assumes you know how scripts in Mudlet work. If not then you should look at the manual first. Also it only shows how Geyser basically works and explains Geysers special windows. It wont go into detail about the windows that where already in Mudlet.

Hello World

Let's start with something simple. A Label.

 Geyser.Label:new({
  name="HelloWorld",
  x=50, y=50,
  width=200, height=50,
})

Geyser HW 1.png

This code creates a blank Label with a size of 200x50 at a position of 50 points horizontal and vertical from its parent window - which is the main window since we didn't specify any.

You can manipulate the Label through the normal functions but Geyser.Label:new() returns an object which can be used to manipulate the label directly. So you should store it:

 local HelloWorld = Geyser.Label:new({
  name="HelloWorld",
  x=50, y=50,
  width=200, height=50,
})

Then you can, for example print a text on it:

 HelloWorld:echo("Hello World")

Geyser HW 2.png

You can put a format parameter so that the text is, for example, centered.

HelloWorld:echo("Hello World", nil, "c")

Geyser HW 3.png

The second parameter is the color. We set it to nil which means the labels foreground color will be used.

The color parameter either accepts a string ("red"), a hex value("#FF0000" or "0xFF0000" or "|cFF0000"), or a decimal value "<255,0,0>"

Example:

HelloWorld:echo("Hello World", "red", "c")

Geyser HW 4.png

Note Note: This will automatically set the foreground color, so any echo, without the color parameter set, after that will use the same color.

You can also set the foreground color with the setFgColor method:

HelloWorld:setFgColor("red")
HelloWorld:echo("Hello World", nil, "c")

Geyser HW 4.png

Containers

Containers are windows that can contain other windows. Actually, since all other Geyser windows subclass container, every window can do that. But containers do not have any visible content by themselves.

Let's show that by an example:

 local container = Geyser.Container:new({
  name="container",
  x=50, y=50,
  width=250, height=50,
})

This will create a container, but if you look at the screen you will see nothing at the positon. There is a way to make containers visible though:

container:flash()

This will flash the container for a short period of time.

Geyser Container 1.png

flash() accepts a number as paremeter which defines the time, in seconds, the flash is shown.

Now, that the container is created, you can add other windows to it. There are 2 ways:

Directly when creating the window:

 local container_label = Geyser.Label:new({
  name="container_label",
  x=0, y=0,
  width="100%", height="100%",
  },
  container)
container_label:echo("This is a label in a container", nil, "c")

Later, after the window was created

 local container_label = Geyser.Label:new({
  name="container_label",
  x=0, y=0,
  width="100%", height="100%",
  })
container_label:echo("This is a label in a container", nil, "c")
container:add(container_label)

Both will lead to the same outcome.

Geyser Container 2.png

Note that we gave a width and height of "100%" to the constructor of the container. This means that the label will take 100% of the containers width and height. If values are given in percent they will even resize with its parent:

container:resize(325, nil)

Geyser Container 3.png

The first parameter is the width, the second the height. If the value is nil the current value is used.

As said in the "Hello World" tutorial the position is relative to its parent window. That's why we could set both x and y to 0 and it is at the position we wanted - the position of the container.

When we now move the container the label moves with it:

container:move(400, nil)

Geyser Container 4.png

The first parameter is the x-, the second the y-position. If the value is nil the current value is used.

VBox and HBox

The VBox and HBox classes are special Containers. They will automatically align its containing windows vertically or horizontally, respectively, in the order they where added to them.

 local HBox = Geyser.HBox:new({
  name="HBox",
  x=0, y=0,
  width=400, height=30,
  })

Like containers you won't see them by themselves.

Adding children works like with containers

 local label1 = Geyser.Label:new({
  name="Label1",
  },
  HBox)
label1:echo("Label 1", "black", "c")
label1:setColor(255, 0, 0)

HVBox 1.png

We didn't set any position or size, but the label gets the same size as the HBox.

If we add another window:

 local label2 = Geyser.Label:new({
  name="Label2",
  },
  HBox)
label2:echo("Label 2", "black", "c")
label2:setColor(0, 255, 0)

HVBox 2.png

the size will be divided equally between them!

What if you want a child that takes more or less space than the others? That's possible too:

 local label3 = Geyser.Label:new({
  name="Label3",
  h_stretch_factor=2.0,
  },
  HBox)
label3:echo("Label 3", nil, "c")
label3:setColor(0, 0, 255)

HVBox 3.png

As you can see, Label 3 takes the same space as Label 1 and 2 Together. That's because we supplied a horizontal stretch factor with "h_stretch_factor=2.0"

This works also with a vertical stretch factor, just replace "h_stretch_factor" with "v_stretch_factor"

Now you may have windows that should not be stretched at all. To accomplish this you have to set the horizontal and/or vertical policy:

 local label4 = Geyser.Label:new({
  name="Label4",
  width="13%",
  h_policy=Geyser.Fixed,
  },
  HBox)
label4:echo("Label 4", "black", "c")
label4:setColor(0, 255, 255)

HVBox 4.png

Possible values for the policies are Geyser.Fixed and Geyser.Dynamic. The default is Geyser.Dynamic. Note that, like in the example above, the label will retain relative values (like percent) if used.

The VBox works like the HBox, only that the child windows are aligned vertically.

Walkthroughs

Here are a few walkthroughs that will show you how to combine Geyser elements to create some simple GUI widgets.

Create a Clickable Compass

Compass.png The following will walk you through the process of creating your own clickable compass using the Geyser framework.

Setup the image files

The compass requires a handful of images to work properly. You can find them here: https://www.dropbox.com/sh/53l7xrn4ds35wnq/WpWOziVKmH
Download each image and place it in your profile folder. You can find your profile folder with getMudletHomeDir()
If you're using Mudlet 2.1+ you can enter lua getMudletHomeDir() from the command line to return the profile folder path on your computer.

Create a new script

Script Name: compass.resize

Registered Event Handlers: sysWindowResizeEvent

Every snippet of code will be placed within this script.

Store the screen size

We'll want to store the screen size in some local variables so they can be easily referenced to later on.

local mw, mh = getMainWindowSize()

Create a global table or namespace

Creating a global table will make each of your variables unique. Our namespace will be called compass and everything we make from here on out will be stored within the compass table. We'll also add a few values to it: dirs and ratio. compass.dirs will store each direction while compass.ratio will store the ratio of our screen size so you can 'square up' your compass.

compass = compass or {
  dirs = {"nw","n","ne","w","center","e","sw","s","se"},
  ratio = mw / mh
}

Create the parent label

Grey.png

The 'parent label' refers to the label on the bottom layer. The entire compass will be created within this label. It's container is main for it's parent is the main window.

compass.back = Geyser.Label:new({
  name = "compass.back",
  x = "25%",
  y = "25%",
  width = "10%",
  height = "10%",
},main)

Set the parent label stylesheet

Blue.png

This will create the blue sphere that makes up most of the compass. The background color is a radial gradient that goes from a deep blue to a brighter shade. The border radius rounds the edges. When the radius is exactly half of the label width it forms a circle. The arrows of the compass actually protrude from the sphere so we give it a margin to suck it in a bit for this effect.

compass.back:setStyleSheet([[
  background-color: QRadialGradient(cx:.3,cy:1,radius:1,stop:0 rgb(0,0,50),stop:.5 rgb(0,0,100),stop:1 rgb(0,0,255));
  border-radius: ]]..tostring(compass.back:get_width()/2-14)..[[px;
  margin: 10px;
]])

Create a 3x3 grid

The compass is split into 9 sections. One for each cardinal direction plus an extra space that sits in the center. This 3x3 grid is created by 3 VBoxes that sit within a single HBox (or vice versa but I flipped a coin and this is what it gave me).
So first off, we create the HBox. It will be the same size as its parent, compass.back.

  compass.box = Geyser.HBox:new({
    name = "compass.box",
    x = 0,
    y = 0,
    width = "100%",
    height = "100%",
  },compass.back)

Next, we create our 3 VBoxes. You don't need to specify position or size because these are placed within compass.box, an HBox.

    compass.row1 = Geyser.VBox:new({
      name = "compass.row1",
    },compass.box)
    compass.row2 = Geyser.VBox:new({
      name = "compass.row2",
    },compass.box)
    compass.row3 = Geyser.VBox:new({
      name = "compass.row3",
    },compass.box)

Finally, we add our 9 labels. Take note that they are split up into even groups of 3. Each group is placed into a different compass.row#

      compass.nw = Geyser.Label:new({
        name = "compass.nw",
      },compass.row1)

      compass.w = Geyser.Label:new({
        name = "compass.w",
      },compass.row1)
    
      compass.sw = Geyser.Label:new({
        name = "compass.sw",
      },compass.row1)
  
      compass.n = Geyser.Label:new({
        name = "compass.n",
      },compass.row2)
        
      compass.center = Geyser.Label:new({
        name = "compass.center",
      },compass.row2)

      compass.s = Geyser.Label:new({
        name = "compass.s",
      },compass.row2)

      compass.ne = Geyser.Label:new({
        name = "compass.ne",
      },compass.row3)
    
      compass.e = Geyser.Label:new({
        name = "compass.e",
      },compass.row3)
  
      compass.se = Geyser.Label:new({
        name = "compass.se",
      },compass.row3)

Create a callback function

We'll want our compass to head in the direction of the arrow we're clicking. This is where we specify so. When the arrow is clicked, this function will be ran with the arrow direction as the argument.

function compass.click(name)
  send(name)
end

Create the hover functions

We want our arrows to turn yellow when we hover over them. We do so by simply resetting the label's stylesheet and changing the border image. Don't forget to include the margin as we still want that.

function compass.onEnter(name)
  compass[name]:setStyleSheet([[
    border-image: url("]]..getMudletHomeDir()..[[/]]..name..[[hover.png");
    margin: 5px;
  ]])
end

function compass.onLeave(name)
  compass[name]:setStyleSheet([[
    border-image: url("]]..getMudletHomeDir()..[[/]]..name..[[.png");
    margin: 5px;
  ]])
end

Set the stylesheets in the grid

Sample.png

Each of the 9 labels need an image of an arrow. Rather than setting each individually, we'll iterate over the compass.dirs table we made awhile back and add the respective image to each. The names of images are a reflection of the compass.dirs table. This keeps it consistent and easy to refer to. During the iteration, the callback, setLabelOnEnter and setLabelOnLeave are also set for each label.

for k,v in pairs(compass.dirs) do
  compass[v]:setStyleSheet([[
    border-image: url("]]..getMudletHomeDir()..[[/]]..v..[[.png");
    margin: 5px;
  ]])
  compass[v]:setClickCallback("compass.click",v)
  setLabelOnEnter("compass."..v,"compass.onEnter",v)
  setLabelOnLeave("compass."..v,"compass.onLeave",v)
end

Resize the compass into a square

Final.png

Most screen size ratios aren't a perfect 1:1. This will cause a 10% x 10% label to be far from square. By setting our height (the smaller of the two numbers) to our width, we can resize our compass to a near perfect square. This function is also the name of our script because we want it to run each time sysWindowResizeEvent is raised.

function compass.resize()
  compass.back:resize(compass.back.width, compass.back:get_width())
end

compass.resize()

Create a Tabbed Window

Tabwindow.png The following will walk you through the process of creating your own tabbed window using the Geyser framework.

Create a new script

Script Name: Tabbed Window
Every snippet of code will be placed within this script.

Create a global table

Creating a global table will make each of your variables unique. Our namespace will be called menu and everything we make from here on out will be stored within the menu table. We'll also add a few values to it: tabs, color1, color2, width, height and current.
'tabs' will be a table that stores all our tab names. If we want our tabs to have different names, we alter this table.
'color1' and 'color2' will store the colors of our tabbed window. If we want to change the color of our tabbed window, we alter these values.
'width' and 'height' will store the size of our tabbed window. If we want to change the size of the tabbed window, we alter these values.
'current' keeps track of which tab is selected. We will set this to the first tab in the table by default. We do this outside the initial table creation so we can easily access menu.tabs

menu = menu or {
  tabs = {"Tab1","Tab2","Tab3","Tab4"},
  color1 = "rgb(0,0,70)",
  color2 = "rgb(0,0,50)",
  width = "20%",
  height = "40%",
}
menu.current = menu.current or menu.tabs[1]

Create the main container

Our tabbed window will need a container. This will be the bottom layer. Containers are invisible so no need to set a stylesheet.

menu.container = Geyser.Container:new({
  name = "menu.back",
  x = "50%", y = "25%",
  width = menu.width,
  height = menu.height,
},main)

Create an HBox

All of our tabs will be evenly spaced. So we'll create an HBox to sit at the top of our container.

menu.header = Geyser.HBox:new({
  name = "menu.header",
  x = 0, y = 0,
  width = "100%",
  height = "10%",
},menu.container)

Create a label

This label will serve as a container for each window. It sits right underneath the HBox we just created for the tabs.

menu.footer = Geyser.Label:new({
  name = "menu.footer",
  x = 0, y = "10%",
  width = "100%",
  height = "90%",
},menu.container)

We don't want this to be a big grey box at startup, so we'll set the stylesheet to appear like the rest of the windows.

menu.footer:setStyleSheet([[
  background-color: ]]..menu.color1..[[;
  border-bottom-left-radius: 10px;
  border-bottom-right-radius: 10px;
]])

Each window actually has two labels. One for the light blue background, and another for the dark blue center. This will create that dark blue center.

menu.center = Geyser.Label:new({
  name = "menu.center",
  x = 0, y = 0,
  width = "100%",
  height = "100%",
},menu.footer)
menu.center:setStyleSheet([[
  background-color: ]]..menu.color2..[[;
  border-radius: 10px;
  margin: 5px;
]])

Add your tabs and their windows

Now we'll want to add our tabs and windows. We do this in a single for loop of the 'menu.tabs' table since it holds all our tab names.

for k,v in pairs(menu.tabs) do

This will create the tabs. Each tab will be named: menu.<tabname>tab

  menu[v.."tab"] = Geyser.Label:new({
    name = "menu."..v.."tab",
  },menu.header)

Here is where we set the tab stylesheet. Each tab has a rounded top, so we set the border-radius of the top-left and top-right to 10px. Each tab has a small space for separation so we give the right and left sides a tiny margin of 1px.

  menu[v.."tab"]:setStyleSheet([[
    background-color: ]]..menu.color1..[[;
    border-top-left-radius: 10px;
    border-top-right-radius: 10px;
    margin-right: 1px;
    margin-left: 1px;
  ]])

This will display the name of each tab on the tab.

  menu[v.."tab"]:echo("<center>"..v)

We need our tabs to do stuff when clicked, so we'll assign it a callback function, menu.click, which we'll create later on. Our tab name is the argument.

  menu[v.."tab"]:setClickCallback("menu.click",v)

Now we create the windows that appear when each tab is clicked. Each window has two labels, one atop the other. The first, which we'll create here, has rounded edges on its bottom.

  menu[v] = Geyser.Label:new({
    name = "menu."..v,
    x = 0, y = 0,
    width = "100%",
    height = "100%",
  },menu.footer)

  menu[v]:setStyleSheet([[
    background-color: ]]..menu.color1..[[;
    border-bottom-left-radius: 10px;
    border-bottom-right-radius: 10px;
  ]])

The second label serves as the window's center and has rounded edges on all sides. And a margin of 5px from it's parent, the label we just created. When adding stuff to your windows, this is the label you'll want to use. menu.<tabname>center

  menu[v.."center"] = Geyser.Label:new({
    name = "menu."..v.."center",
    x = 0, y = 0,
    width = "100%",
    height = "100%",
  },menu[v])
  menu[v.."center"]:setStyleSheet([[
    background-color: ]]..menu.color2..[[;
    border-radius: 10px;
    margin: 5px;
  ]])

Finally, we hide all the windows and end the for loop.

  menu[v]:hide()
end

Create a callback function

The last step is to create our callback function for when a tab is clicked. This will hide that tab that is stored in menu.current, set menu.current to the clicked tab, and then show the menu.current tab.

function menu.click(tab)
  menu[menu.current]:hide()
  menu.current = tab
  menu[menu.current]:show()
end

Adding content to your windows

Add content to menu.<tab name>center

So if we wanted to display our gold in a window we could:

menu.Tab1center:echo(myGold)

If we wanted to add a map to a window we could:

myMap = Geyser.Mapper:new({
  name = "myMap",
  x = 0, y = 0,
  width = "100%",
  height = "100%",
},menu.Tab2center)

Create a Window with a resize label

Resize window.png This walkthrough will create a window with a smaller label which will let you resize the window.

Create a new script

Script Name: Resize Window
Every snippet of code will be placed within this script.

Create a window

Create a window label which will be resizable.

--
-- Create a label that will be resized and contain the drag icon.
---
mLabel = Geyser.Label:new({
  name = "mLabel",
  x = 400, y = 200,
  width = 200, height = 200,
  fgColor = "black",
  color = "blue",
  message = [[<center>drag the white label to resize</center>]]
})
mLabel:setStyleSheet([[qproperty-wordWrap: true]])

Create small icon inside the window

Create the label that will be used as a drag icon.

--
-- Create the small drag label within the window.
-- The y position is set to "-15px" to align it to
-- the bottom of the main label.
--
mVDrag = Geyser.Label:new({
  name = "mVDrag",
  x = 85, y = "-15px",
  width = 30, height = 15,
  fgColor = "black",
  color = "white",
}, mLabel)

Create callback functions

Create the callback functions that will be called by mouse and timer events.

Create a timer function that will be called repeatedly while the mouse button is pressed.

function onVDragTimer()
  local x
  local y
  local height

  -- Get mouse position
  x, y = getMousePosition()

  -- Substract the top of the label  to get the new height.
  height = y - 200
  if height < MIN_HEIGHT then
    -- Height is too small.
    height = MIN_HEIGHT
  end

  -- Set the new size and restart timer.
  mLabel:resize(200, height)
  vdragtimer = tempTimer(0.2, onVDragTimer)
end


Create a function which will be called when we first press the icon. The function will create the timer which will trigger as long as the button is pressed.

function onVDragClick()
  -- The user clicked the drag label.
  -- Start a temp timer to update the size of the label.
  if not exists("vdragtimer", "timer") then
    vdragtimer = permTimer("vdragtimer", "", .016, "onVDragTimer()")
  end

  enableTimer("vdragtimer")
end


Create the callback function which will be called when we release the drag icon.

function onVDragRelease()
  -- Button is release so stop timer and updates.
  disableTimer("vdragtimer")
end

Set up the callback functions

Set up the limit how small the window can be, and setup the callback functions.

MAX_HEIGHT = 100
--
-- Set mouse event callbacks.
--
setLabelClickCallback("mVDrag", "onVDragClick")
setLabelReleaseCallback("mVDrag", "onVDragRelease")

Final result

The whole script looks like this:

--
-- Example: Resize a label.
--
-- Creates a blue label with a smaller white label, which is
-- used to resize the blue label.
--
-- Utilizing:
-- * getMousePosition()
-- * setLabelClickCallback()
-- * setLabelReleaseCallback()
-- * tempTimer().
--
 
--
-- Create labels
--
mLabel = Geyser.Label:new({
  name = "mLabel",
  x = 400, y = 200,
  width = 200, height = 200,
})
mLabel:setStyleSheet([[
  background-color: rgba(30, 30, 30, 80%);
  qproperty-wordWrap: true;
]])
mLabel:setFontSize(10)
mLabel:echo([[<center>Drag the white label to resize.</center>]])
 
--
-- Create the small drag label within the window.
-- The y position is set to "-15px" to align it to
-- the bottom of the main label.
mVDrag = Geyser.Label:new({
  name = "mVDrag",
  x = 85, y = "-15px",
  width = 30, height = 15,
  fgColor = "black",
  color = "white",
}, mLabel)
mVDrag:setStyleSheet([[
  border-radius: 6;
  background-color: white;
]])
 
MIN_HEIGHT = 100
 
--
-- Callback functions.
--
function onVDragTimer()
  local x
  local y
  local height
 
  -- Get mouse position
  x, y = getMousePosition()
 
  -- Substract the top of the label  to get the new height.
  height = y - 200
  if height < MIN_HEIGHT then
    -- Height is too small.
    height = MIN_HEIGHT
  end
 
  -- Set the new size and restart timer.
  mLabel:resize(200, height)
end
 
function onVDragClick()
  -- The user clicked the drag label.
  -- Start a temp timer to update the size of the label.
  if not exists("vdragtimer", "timer") then
    vdragtimer = permTimer("vdragtimer", "", .016, "onVDragTimer()")
  end

  enableTimer("vdragtimer")
end
 
function onVDragRelease()
  -- Button is release so stop timer and updates.
  disableTimer("vdragtimer")
end
 
--
-- Set mouse event callbacks.
--
setLabelClickCallback("mVDrag", "onVDragClick")
setLabelReleaseCallback("mVDrag", "onVDragRelease")