WoW:Creating simple pop-up dialog boxes: Difference between revisions

mention maxLetters
mNo edit summary
(mention maxLetters)
Line 1: Line 1:
{{UIHowTo}}
{{UIHowTo}}
'''Static popups''' are simple one- or two-button dialog boxes you see when confirming a warlock summon, sending money
'''Static popups''' are simple one-, two-, or three-button dialog boxes you see when confirming a warlock summon, sending money
through the mail, renaming a pet, and so forth. This tutorial describes how you can use the StaticPopup code to display simple dialogs in your own addon.
through the mail, renaming a pet, and so forth. This tutorial describes how you can use the StaticPopup code to display simple dialogs in your own addon.


Line 16: Line 16:
   button2 = "No",
   button2 = "No",
   OnAccept = function()
   OnAccept = function()
       GreetTheWorld();
       GreetTheWorld()
   end,
   end,
   timeout = 0,
   timeout = 0,
Line 29: Line 29:


* ''text'' - This is the text inside the dialog box.  For example, "Looting this item will bind it to you."
* ''text'' - This is the text inside the dialog box.  For example, "Looting this item will bind it to you."
* ''button1'' - This is the text on the left "yes" button.  Clicking this button will call the <tt>OnAccept</tt> function in the entry.  In a popup with only one button, it is this one.  Some dialogs (like the "you are not part of this instance's group and are going to get teleported" warning) do not even have a single button.
* ''button1'' - This is the text on the left-hand "yes" button.  Clicking this button will call the <tt>OnAccept</tt> function in the entry.  In a popup with only one button, it is this one.  There are global variables includiung ACCEPT, CANCEL, and OKAY, which contain localized strings and are perfectly suited for assigning to the button* fields.  Some dialogs (like the "you are not part of this instance's group and are going to get teleported" warning) do not even have a single button.
* ''button2'' - This is the text on the right "no" button.  If the entry has an <tt>OnCancel</tt> function, clicking this button will call it with "clicked" as the reason (see below).
* ''button2'' - This is the text on the right-hand "no" button.  If the entry has an <tt>OnCancel</tt> function, clicking this button will call it with "clicked" as the reason (see below).
* ''OnAccept'' - This is a local function; it can be as complicated as you like.  You do not need to explicitly hide the popup frame, it will be done for you.
* ''OnAccept'' - This points to a function; it can be as complicated as you like and is typically a local "anonymous"-style function defined on the spot as shown above.  You do not need to explicitly hide the popup frame; it will be hidden for you.
* ''timeout'' - After this many seconds, the dialog will go away.  If the entry has an <tt>OnCancel</tt> function, it will be called with "timeout" as the reason.  Dialogs which do not expire should set this to zero.
* ''timeout'' - After this many seconds, the dialog will go away.  If the entry has an <tt>OnCancel</tt> function, it will be called with "timeout" as the reason.  Dialogs which do not expire should set this to zero.
* ''whileDead'' - Set to true if this dialog can be shown while the player is a ghost.  You probably want to do this.
* ''whileDead'' - Set to true if this dialog can be shown while the player is a ghost.  You probably want to do this.
* ''hideOnEscape'' - Set to true if hitting the Escape key should be treated like clicking button2.  You probably want to do this.
* ''hideOnEscape'' - Set to true if hitting the Escape key should be treated like clicking button2.  You probably want to do this.


If your addon has a general OnLoad event handler, that is an excellent place to perform this array insertion.
If your addon has a general OnLoad event handler, that is an excellent place to perform this array insertion.  If the contents of the entry do not require any runtime information, you can perform the insertion during loadup by putting it at file scope.


Note that this guide refers to setting boolean options to 'true' or 'false'; earlier editions used '1' and 'nil' for the same purposes.  The fact of the matter is that you can set those options to anything which evaluates to true-valued or false-valued results according to Lua:  'nil' and 'false' are false-valued, anything else (including 0 and "") is true-valued.  A lot of original Blizzard code was written for an earlier version of Lua, which did not have formal boolean types.  Use whatever makes the most sense for your addon.
Note that this guide refers to setting boolean options to 'true' or 'false'; earlier editions used '1' and 'nil' for the same purposes.  The fact of the matter is that you can set those options to anything which evaluates to true-valued or false-valued results according to Lua:  'nil' and 'false' are false-valued, anything else (including 0 and "") is true-valued.  A lot of original Blizzard code was written for an earlier version of Lua, which did not have formal boolean types.  Use whatever makes the most sense for your addon.
Line 43: Line 43:
To display the dialog, call <tt>StaticPopup_Show</tt> with the name of the entry:
To display the dialog, call <tt>StaticPopup_Show</tt> with the name of the entry:


  StaticPopup_Show ("EXAMPLE_HELLOWORLD");
  StaticPopup_Show ("EXAMPLE_HELLOWORLD")


The dialog will be put together and displayed, and the function returns as soon as the dialog is shown.
The dialog will be put together and displayed, and the function returns as soon as the dialog is shown.
If all goes well, the XML frame object for that dialog will be returned from the function.  If there
If all goes well, the table object for that dialog will be returned from the function.  If there
are any problems, it returns nil.
are any problems, it returns nil.


This function has two more optional arguments, see [[#Dialog_Text_Parameters|Dialog Text Parameters]] below.
This function has two more optional arguments, see [[#Dialog_Text_Parameters|Dialog Text Parameters]] below.


Up to 4 static popups may be displayed at once.  The UI will handle finding an open slot for you.
Up to 4 static popups may be displayed at once.  The UI will handle finding an open popup slot for you.


== Hiding the popup ==
== Hiding the popup ==
To make the dialog disappear without having a user click it, call <tt>StaticPopup_Hide</tt> with the name of the entry:
To make the dialog disappear without having a user click it, call <tt>StaticPopup_Hide</tt> with the name of the entry:


  StaticPopup_Hide ("EXAMPLE_HELLOWORLD");
  StaticPopup_Hide ("EXAMPLE_HELLOWORLD")


Calling the <tt>StaticPopup_Hide</tt> function after the dialog has already been hidden does not appear to have any ill effect.  Return values of this function, if any, are not documented.
Calling the <tt>StaticPopup_Hide</tt> function after the dialog has already been hidden does not appear to have any ill effect.  There are no return values from this function.


== Advanced setup ==
== Advanced setup ==
* ''OnAccept'' - This function can take up to two arguments, both optional.  They are for passing arbitrary data around the callbacks.  There are very few examples of the use of the arguments.  In general this is used with dialogs that have an editable text field, to pass the entered text back to the function.  Also for chaining dialog boxes together.
* ''OnAccept'' - This function can take up to two arguments, both optional.  They are for passing arbitrary data around the callbacks.  In general this is used with dialogs that have an editable text field, to pass the entered text back to the function; also for chaining dialog boxes together.  For details, see "Passing arguments to local functions" below.


* ''OnCancel'' - This function can take up to two arguments, both optional.  The first is used the same way as the first parameter in OnAccept (whatever that may actually be).  The second is a string describing the reason the popup was cancelled; the game will pass this as required:
* ''OnCancel'' - This function can take up to two arguments, both optional.  The first is used the same way as the first parameter in OnAccept (whatever that may actually be).  The second is a string describing the reason the popup was cancelled; the game will pass this as required:
Line 93: Line 93:
  end
  end


Using ''hasEditBox''/''.editBox'' causes a small one-line text field to appear.  You can use the ''hasWideEditBox'' option field (and the corresponding ''.wideEditBox'' dialog field) to cause the text field to have the full width of the dialog box instead.  To do this, you must set both options, but only the wide edit box will be used.
Using ''hasEditBox''/''.editBox'' causes a small one-line text field to appear.  You can use the ''hasWideEditBox'' option field (and the corresponding ''.wideEditBox'' dialog field) to cause the text field to have the full width of the dialog box instead.  To do this, you must set both options, but only the wide edit box will be used.  Both normal and wide editboxes will respect the ''maxLetters'' field if you set it (most editbox popups used by Blizzard set this to 24 or 31).


== Optional features ==
== Optional features ==
Line 109: Line 109:
* ''button3''/''OnAlt'' - You can set text for a third button to appear, and its corresponding callback.  The button is placed ''between'' the first two buttons.  (To remember this, think of how mouse buttons are labeled.)
* ''button3''/''OnAlt'' - You can set text for a third button to appear, and its corresponding callback.  The button is placed ''between'' the first two buttons.  (To remember this, think of how mouse buttons are labeled.)


As an example, consider the Ready Check from [http://ctmod.net/ CT_RaidAssist], which pops up a two-button dialog box with a 30-second timeout.  Currently the CT authors implement everything from scratch:  107 lines of XML specifying window, field, and button sizes, plus a couple lines of Lua here and there.  It could be replaced with something like the following:
As an example, consider the Ready Check from [http://ctmod.net/ CT_RaidAssist], which pops up a two-button dialog box with a 30-second timeout.  The CT authors implemented everything from scratch:  107 lines of XML specifying window, field, and button sizes, plus a couple lines of Lua here and there.  It could be replaced with something like the following:


  StaticPopupDialogs["EXAMPLE_CTRA_READY"] = {
  StaticPopupDialogs["EXAMPLE_CTRA_READY"] = {
Line 133: Line 133:
and called via
and called via


  StaticPopup_Show ("EXAMPLE_CTRA_READY", CT_RA_CheckReady_Person);
  StaticPopup_Show ("EXAMPLE_CTRA_READY", CT_RA_CheckReady_Person)


(Note:  the above was written before the 1.11 game patch added a builtin ready check.  While ready checks no longer need
(Note:  the above was written before the 1.11 game patch added a builtin ready check.  While ready checks no longer need
Line 142: Line 142:


   OnAccept = function (self, data, data2)
   OnAccept = function (self, data, data2)
       DoSomethingWith(self.data)
       DoSomethingWith(data)
   end
   end


Line 157: Line 157:
The dialog's fields "data" and "data2" are passed as additional arguments to OnAccept.  The "data" field is passed to OnCancel and OnAlt (the function called if button3 is set), but not "data2".  They are also accessible through the dialog itself, as ''self.data'' and ''self.data2''.  In this example they are strings, but they can be of any type including tables.
The dialog's fields "data" and "data2" are passed as additional arguments to OnAccept.  The "data" field is passed to OnCancel and OnAlt (the function called if button3 is set), but not "data2".  They are also accessible through the dialog itself, as ''self.data'' and ''self.data2''.  In this example they are strings, but they can be of any type including tables.


Notice that you are actually setting the frame's data ''after'' the user has clicked the button.  This works because popping up a dialog box does not halt script execution.  The dialog box isn't even visible to the player until after the current script execution cycle completes.  By the time the player clicks a button to run OnAccept/OnCancel/etc, all of this code will have long since finished.
Notice that you are actually setting the frame's data ''after'' you have called StaticPopup_Show.  This works because popping up a dialog box does not halt script execution.  The dialog box isn't even visible to the player until after the current script execution cycle completes.  By the time the player clicks a button to run OnAccept/OnCancel/etc, all of this code will have long since finished.


If you need to manipulate any of the dialog's visual elements, most of them are directly accessible as table fields of the dialog, so you do not need to use an expensive sequence of ''getglobal(self:GetName().."Something")''.  For example, ''dialog.button1'' points to the first button.  See the StaticPopup.xml file's various OnLoad sections for the full list.
If you need to manipulate any of the dialog's visual elements, most of them are directly accessible as table fields of the dialog, so you do not need to use an expensive sequence of ''getglobal(self:GetName().."Something")''.  For example, ''dialog.button1'' points to the first button.  See the StaticPopup.xml file's various OnLoad sections for the full list.


== Notes and observations ==
== Notes and observations ==
* The 'text' fields and button1/2/3 fields are usually localized.  Blizzard tends to use generic texts like ACCEPT, CANCEL, and OKAY; you can probably do the same.  These global variables contain a localized string and can be used as-is, like <tt>button1 = ACCEPT</tt>
* Creating a static popup with an editbox and only one button will cause the button and the editbox to overlap. Having more than one button will get the desired behavior. (Tested on 2.4.1)
* Creating a static popup with an editbox and only one button will cause the button and the editbox to overlap. Having more than one button will get the desired behavior. (Tested on 2.4.1)
* While creating your popup entries, you will probably be doing a lot of UI reloading.  Extract the <tt>[[FrameXML/DebugUI.xml]]</tt> file from the default UI, copy it into your addon folder, and add it to your .toc file.  This has two effects:  it starts verbose logging into FrameXML.log, and it adds a "Reload UI" button to your screen.  Very handy timesaver.  :-)
* While creating your popup entries, you will probably be doing a lot of UI reloading.  Extract the <tt>[[FrameXML/DebugUI.xml]]</tt> file from the default UI, copy it into your addon folder, and add it to your .toc file.  This has two effects:  it starts verbose logging into FrameXML.log, and it adds a "Reload UI" button to your screen.  Very handy timesaver.  :-)
Anonymous user