AlexGames
Game API documentation
See the below files for the source of truth on these APIs:
src/lua_api/lua_api.c
: Lua wrapper aroundgame_api.h
. Games written in Lua call into the APIs defined in this file. They should simply call the APIs defined ingame_api.h
(see below)src/game_api/game_api.h
: Main API defintion, for games implemented in Lua or C++. This is where the APIs should be documented in the code. For anything not clearly documented, the expected behaviour is how it currently works in HTML. Other implementations should try to be as similar to HTML as possible, when reasonable.src/emscripten/emscripten_api.c
: Implementation ofgame_api.h
calling into the HTML client's javascript APIs.src/html/js/alexgames_wasm_api.js
: HTML/JS implementation ofgame_api.h
APIs.
Example API sequence
See an example game here.- Init: Game client initializes (on HTML this means downloading images), including network connection to the server for network multiplayer.
- Load main Lua file: This initializion includes running all the code in the game's main Lua file (which may include additional Lua files). These files should only define functions, and not actually "do" anything outside of those functions.
- Call start_game: The game client calls the game's start_game callback, optionally providing serialized state if the user has provided state from a URL parameter (or is loading this game from the autosave / history browser UI. If the game is being loaded from saved history, a session ID param is also provided. From this callback, the game should initialize its own state if not provided, and may call some or all of the below APIs:
- calling the enable_evt API. This can enable things like keyboard, detailed touch or mouse input (more than just clicks).
- calling the set_update_timer_ms API. This configures a regular timer to call the update callback.
- Call update: The game client calls the game's update callback. From here, the game should:
- draw the current game state using the Drawing APIs, such as draw_graphic, draw_line, draw_rect, or draw_circle. Games should first call draw_clear to first clear the buffer/screen, and then call draw_refresh to commit their drawing to the user's screen.
- If the game configured a timer via the set_update_timer_ms API, then the game should also update its time-based state here (
update
is called at the frequency passed as an argument toset_update_timer_ms
).
- Handle user input: The user may provide input by clicking on the screen with their mouse, or pressing it with their finger on mobile (handle_user_clicked), or other forms of input if enabled via enable_evt: keyboard input (handle_key_evt), touch (handle_touch_evt), or more granular mouse input (button pressed, released, mouse moved: handle_mouse_evt, handle_mousemove)
- From these callbacks, the game should update its state accordingly, and draw the latest state on the screen.
- Network multiplayer: The game may send messages to other players with send_message, and receive messages from handle_msg_received.
- Autosave state: The game may store its state with the save_state API. This allows the user to browse through saved states through the history browser in Load autosaved game button in the options menu.
- Save other game state: Alternatively, the game can read or write saved data directly with the store_data and read_stored_data APIs.
- Export game state: The user may wish to continue playing the game on another device, or share the initial state with a friend to try the same puzzle they just enjoyed. When the user presses the Options button, the get_state and the (if defined) get_init_state APIs are called, and both are available as URLs with the binary state data base 64 encoded in the web version. (The serialized state will be passed to start_game callback when the user opens the URL with the serialized state)
API and callback summary/contents
Contents :
- Drawing APIs
- draw_graphic
- draw_line
- draw_text
- draw_rect
- draw_circle
- draw_clear: Clears all drawing on the canvas.
- draw_refresh: Causes previously called draw APIs to be visible by the user. Admittedly this API doesn't need to be called in HTML, but other clients need it.
- Network Multiplayer APIs
- send_message: Sends a message to all players connected to this session, or to a specified player. Players receive messages via the handle_msg_received callback. In HTML this is implemented as websockets, but on other platforms it could be implemented as a raw TCP socket.
- UI APIs
- create_btn: Adds a button to the bottom of the screen, below the canvas. Note that some games may choose to simply draw rectangles on the canvas and use those as buttons, for more flexibility (e.g. changing parts of the interface). Buttons created here are typically shown throughout the whole game.
- set_btn_enabled
- set_btn_visible
- show_popup: Shows a popup, optionally containing text, buttons, and/or dropdowns.
- hide_popup
- set_status_msg: Adds a text log in the interface.
- set_status_err: Adds a red text log in the interface. This can be used if the player provides invalid input (or makes an invalid move in a game), but it's also used for programming errors.
- prompt_string: Shows the user a popup to allow them to enter text. This is convenient for games that don't otherwise require keyboard input, especially on mobile.
- enable_evt: Enables callbacks to receive events such as mouse move/up/down/wheel, touch events, keyboard events.
- disable_evt
- Timer APIs
- set_update_timer_ms: Calls the update callback at the specified interval, in milliseconds. This allows for real time games, or games with animations.
- Persistent Storage APIs: These APIs store data raw binary byte ararys as a key/value pair. These can be use to save a game's state, but for many games, it's better to use the "saved state" APIs below, where the game allows the user to browse through previous saved states.
- Persistent saved state APIs: stores games' states to the "history browser" interface, where the user can browse through different game sessions, and individual moves within those games. A preview of the game is rendered through the regular
update
API. - Miscellaneous APIs
- get_time_ms
- get_time_of_day: Gets the current time of day, in
yyyy-mm-dd HH:MM:SS
format. - get_user_colour_pref: Gets the user's colour preference, currently either
"light"
or"dark"
. - Callbacks
- Main
- update: Called when the screen should be rendered, or at a specific interval if the set_update_timer_ms is called. Meant to be the "main loop" of games.
- start_game: Called when the game is started. May pass serialized state if the user is loading a previous game from the history browser, or is opening a URL with serialized state passed as a parameter.
- get_state
- get_init_state
- User input
- handle_user_clicked: Called when the user clicks (or touches) a point on the screen. Note that this is different from a mouse up/down event. This is the
"click"
event in HTML, which seems to have some debouncing, so that it's only sent if the user presses and releases at the same spot, rather than clicking and dragging. - handle_mousemove: Sent when the user moves the mouse over the canvas. Must be enabled by calling
alexgames.enable_evt("mouse_move")
- handle_mouse_evtSent when the presses or releases a mouse button. Must be enabled by calling
alexgames.enable_evt("mouse_updown")
- handle_wheel_changed
- handle_key_evt
- handle_touch_evt
- handle_btn_clicked
- handle_popup_btn_clicked
- Network Multiplayer callbacks
- handle_msg_received: Called when a player receives a message sent from another player via the send_message API.
Drawing APIs
Drawing preface
Points / coordinate system
Almost all drawing APIs defined below specify the position of the thing you are drawing with y and x coordinates. The top left is 0, 0 and the bottom right is currently 480, 480. That means that y is zero at the top, and 480 at the bottom.
In the future the canvas may support additional sizes, but for now everything is 480 by 480 (scaled) pixels.
Hexadecimal colour strings
All colours are specified as a hexadecimal colour string. This starts with a number sign (#
), and then is either 3 (rgb), 6 (rrggbb), or 8 (rrggbbaa) characters long. "r" is red, "g" is green, "b" is blue, and "a" is alpha (transparency)
Some examples: #f00
is red, #0f0
is green, and #00f
is blue. Black is #000
and white is #fff
. Completely transparent is #00000000
(8 zeros), where the first 6 characters can be any hex numbers.
On the HTML client they are simply passed to the browser, so if HTML supports more variants then they will work-- but other clients often need to parse these, and I have only supported the above lengths for now. See Wikipedia: Web colours, "Hex triplet" section for more information.
If you have no idea what any of this, then just use a search engine to find "HTML colour picker", where you should find a UI that can generate these hex codes for you. Browser developer tools may have this built in, too.
draw_graphic
alexgames.draw_graphic(img_id, y, x, width, height, params)
img_id
: string identifying the image. See images in the<div class="preload">
ofindex.html
.y
,x
: y and x position to draw the centre of the image. (0,0) is the top left. See coordinate system for more information.width
,height
: size to draw the image on the canvas. More info on the canvas specifications in the previous bullet point descriptiong the y and x position.params
(optional):angle_degrees
: angle to rotate image, in degrees.flip_y
: if true, flips the image across the x axis in the middle.flip_x
: if true, flips the image across the y axis in the middle.
draw_line
alexgames.draw_line(colour, line_size, y1, x1, y2, x2)
colour
: hexademical colour string, starting with a number sign (#
) just like HTML. e.g.#000000
is black,#ff0000
is red, and#00ff0088
is green at 50% opacity.line_size
: width of the line, in scaled pixels.y1
,x1
: start of the liney2
,x2
: end of the line
draw_text
alexgames.draw_text(text_str, colour, y, x, size, align)
text_str
: String of text to draw.colour
: Hexadecimal colour string, for more info see the description in thedraw_line
documentationy
,x
: Position to start drawing the text. This can be the left-most point, centre, or right-most point depending on thealign
argument.size
: Font size of the text.align
: Text alignment.alexgames.TEXT_ALIGN_LEFT
,alexgames.TEXT_ALIGN_CENTRE
, oralexgames.TEXT_ALIGN_RIGHT
.
draw_rect
alexgames.draw_rect(fill_colour, y_start, x_start, y_end, x_end)
Draws a filled rectangle at the specifed position. To draw an outline, see the draw_shapes.draw_rect_outline
library, available by loading libs/draw/draw_shapes
. (Note that this is simply a helper function that calls the draw_line
API four times.)
fill_colour
: Hexadecimal colour string, for more info see the description in thedraw_line
documentation.
draw_circle
alexgames.draw_circle(fill_colour, outline_colour, y, x, radius)
Draws a circle at the specified position. Note that the fill or outline can be invisible by providing a colour string with 8 bytes specified, e.g. #00000000
, the same way that HTML colours work.
fill_colour
: Hexadecimal colour string specifying the colour of the inside of the circle. For more info on hexadecimal colour strings, see the draw_line documentation.outline_colour
: Hexadecimal colour string specifying the colour of the line around the edge of the circle. For more info on hexadecimal colour strings, see the draw_line documentation.y
,x
: y and x position of the circle.radius
: radius of the circle. This is the distance from the centre to the edge of the circle.
draw_clear
alexgames.draw_clear()
Clears the screen of all drawn content. Generally you'll want to call this every time you start drawing the game state.
draw_refresh
alexgames.draw_refresh()
Causes any previously draw API calls to take effect (e.g. write the buffer to the screen). On HTML this has no effect since the draw APIs already draw directly onto the screen, but it is needed on some other clients. This should be called when you're done drawing the game state.
Network APIs and callbacks
Network preface
Network player identifiers
When a player joins a session, their client should broadcast "player_joined:"
to all players. Clients and games should receive this message via the handle_message_received callback, which indicates the player's identifier as the src
parameter.
Generally this is probably the player's IP address and the server port that they are connected to, but it doesn't have to be. (e.g. if AlexGames were integrated within a messaging program, this could simply be the group chat member's username, or even a single integer)
In the future, I would like to add some standard for adding a player chosen name that could be used, but nothing like that is currently implemented.
send_message
alexgames.send_message(dst, msg)
Sends a message over the network to player dst
. If dst
is "all"
then the message is broadcast to all players.
dst
: Identifier of the player you want to message, or"all"
to broadcast to all players. See network player identifiers for more informationmsg
handle_msg_received
handle_msg_received(src, msg)
UI APIs
create_btn
alexgames.create_btn(btn_id, btn_text, weight)
Creates a button on the UI, probably at the bottom.
When players press this button, the handle_btn_clicked callback is called.
btn_id
: a string identifying this button. This is to identify the button in other API/callbacks, e.g. which button is pressed when the handle_btn_clicked callback is called.btn_text
: text to display on this button.weight
: 0 to make this button only occupy as much space as it needs, or an integer greater than 0 to occupy as much space as possible, shared with other buttons based on weight by a factor ofthis button's weight divided by the sum of total button weights . e.g.: make two buttons with weight 1 and one button with weight 2, and the two weight 1 buttons will each get 25% of the space, and the weight 2 button will get 50% of the space. Similar to HTML Flexbox.
set_btn_enabled
alexgames.set_btn_enabled(btn_id, enabled)
Enables or disables the specified button. An enabled button can be pressed, but a disabled button can not be pressed, and appears greyed out.
set_btn_visible
alexgames.set_btn_visible(btn_id, visible)
Sets whether or not the specified button is visible.
show_popup
alexgames.show_popup(popup_id, popup_info)
popup_info = { title = "Popup title specified here", -- Table containing list of different items that are to be displayed in the popup -- One of each possibility is shown below as an example. items = { { item_type = alexgames.POPUP_ITEM_MSG, msg = "This is text shown to the user." }, -- This is a button displaying "My Action" that the user can click. -- If the user clicks it, the `handle_popup_btn_clicked` callback is called, -- with the id 1 passed as an argument to identify which button. -- Note that the state of other popup elements (e.g. the dropdown, defined next) is -- is also passed to the game through this callback. { item_type = alexgames.POPUP_ITEM_BTN, id = 1, text = "My action" }, -- This displays a dropdown with two choices: "White" and "Black", and the label -- label "Choose a colour". -- Once a button on the popup is pressed, the selected dropdown item is identified -- by an integer starting from 1 (e.g. 1 is the first option, 2 is the 2nd, etc). { item_type = alexgames.POPUP_ITEM_DROPDOWN, id = 2, label = "Choose a colour", options = { "White", "Black", }, } } }
Displays a popup to the user, with a title, and other optional elements such as text, buttons, and dropdowns.
When a button on the popup is pressed, the handle_popup_btn_clicked callback is called, which also provides the states of dropdowns on the popup.
hide_popup
Hides any currently visible popups.
set_status_msg
alexgames.set_status_msg(msg)
Displays a string to the user, usually indiciating the result of some action they performed, or some event (e.g. player joined). Previous messages are shown in a scrollable UI element, along with timestamps.
set_status_err
alexgames.set_status_err(msg)
Same as set_status_msg defined above, but with red text, indicating an error. This is used both for programming errors (usually showing a full Lua stacktrace), or to alert the user that their move was invalid.
prompt_string
alexgames.prompt_string(prompt_title, prompt_msg)
Shows a popup to the user with a title and message, and a text box for them to enter a string. This is useful for games that occasionally need text input, but are not centred around providing text input. (e.g. a word game should have their own UI with a keyboard or similar, but a game where you can enter your name should use this).
This likely isn't a great experience for games played with a mouse and keyboard, but it is essential on mobile-- I don't know how else you could bring up the soft keyboard on phones.
enable_evt
alexgames.enable_evt(evt_type)
Enables the event specified by evt_type
, which is one of the following strings:
"mouse_move"
: Causes the handle_mousemove callback to be called whenever the user moves their mouse over the game screen."mouse_updown"
: Causes the handle_mouse_evt callback to be called whenever the user clicks or releases their primary mouse button. This allows for doing actions while the user is holding the mouse down, rather than only be notified of a single click."mouse_alt_updown"
: Causes the handle_mouse_evt callback to be called whenever the user clicks or releases their secondary mouse button, or the third mouse button (usually a wheel)."wheel"
: Causes the handle_wheel_changed callback to be called whenever the user's mouse wheel changes. Generally this should be used for scrolling or zooming."touch"
: Causes the handle_touch_evt callback to be called whenever the user touches the game canvas. See the callback definition for more information."key"
: Causes the handle_key_evt callback to be called whenever the user presses or releases keys on their keyboard.
Timer APIs
set_update_timer_ms
alexgames.set_update_timer_ms(update_time_period_ms)
When called, causes update to be called every update_time_period_ms
milliseconds.
Persistent Storage APIs
These APIs allow you to store bytearrays with string keys persistently, they should be readable after the user refreshes the page or closes the browser or tab.
These APIs are the raw storage APIs that the client implements directly, but many games may be better off using the Persistent Saved State APIs discussed later. Those APIs allow for simply calling a "save_state" API whenever the user makes a move, and a separate UI is offered for the user to view all their different saved games' states together, and cycle through the previous moves.
store_data
alexgames.store_data(key, value)
Stores the bytearray value
to persistent storage, under string key
. On HTML this uses Window: localStorage. This may be getting cleared after some period of inactivity on iOS. I'd like to mitigate that but I haven't looked into it yet.
read_stored_data
alexgames.read_stored_data(key)
Persistent Saved State APIs
These APIs are meant to be used for games to save the state every time the user makes a move. The game client provides a separate UI for the user to browse previous games' states and cycle through their moves.
get_new_session_id
alexgames.get_new_session_id()
Returns a new saved state ID. This is meant to be called when the user starts a new game, then the ID should be used whenever calling the save_state API, so that states from the same game can be grouped together.
save_state
alexgames.save_state(session_id, state)
Saves the state
argument to persistent storage in a history database. This history database can be viewed by the user by pressing the "Options" button and then pressing the "Load autosaved game" button.
Calling save_state
multiple times will store multiple copies of the state in the history database.
session_id
: Identifier for this game session. This should be the value returned by get_new_session_id called at the beginning of a new game.state
: A byte array of game state.
get_last_session_id
alexgames.get_last_session_id()
Returns the last session ID for your current game. Returns nil
if no previous session ID is present for this game.
The only expected use case for this API is when the game is first started, you can check if this is set, and then call adjust_saved_state_offset(session_id, 0) to load the previously saved state.
has_saved_state_offset
alexgames.has_saved_state_offset(session_id, move_id_offset)
Returns true
if a saved state is defined at the session ID, and (current move ID plus move_id_offset
), returns false
otherwise.
The only expected use case for this API is for Undo and Redo buttons. This can be checked each time the screen is updated, to decide whether or not to enable (allow to be pressed) the Undo/Redo buttons.
adjust_saved_state_offset
alexgames.adjust_saved_state_offset(session_id, move_id_offset)
Returns the saved state for the session ID and (current move ID plus move_id_offset
), and increments the move ID by mode_id_offset
.
This API is expected to be used for two cases:
- Undo and Redo buttons: when the user presses one of thes buttons, call this API to get the saved state, and update the move ID.
- When a game is started, if no saved state is passed as a parameter, if get_last_session_id returns a non-nil value, then call this API with a
move_id_offset
of0
to get the last saved state.
Miscellaneous APIs
get_time_ms
alexgames.get_time_ms()
Returns the current time in milliseconds.
get_time_of_day
alexgames.get_time_of_day()
Returns the current date and time in yyyy-mm-dd HH:MM:SS
format, in the device's local timezone.
This is intended to be used to show the user when their last move was.
get_user_colour_pref
alexgames.get_user_colour_pref()
Returns the user's colour preference, either "light"
, "dark"
, or "very_dark"
.
I'd like to make this easier to use in the future, perhaps returning a list of colour preferences, so that games can only handle light and dark and not need to handle "very_dark" and every possible future value.
Main Callbacks
update
update()
Called when the screen should be rendered, or at a specific interval if the set_update_timer_ms is called. Meant to be the "main loop" of games.
start_game
start_game(session_id, serialized_state)
Called when the game is first started. If serialized_state
is nil
, the game should initialize new state. If serialized_state
is not nil
, the game should deserialize it and use that as the game state. The game should also store the session_id
, as that is used as a key when writing to the saved state database via the save_state API.
This happens in three cases:
- the user opens a URL with serialized state as a parameter,
- the user loads a previously saved game from the history browser, or
- the user is browsing previously saved games from the history browser-- this API is called to generate the previews.
get_state
get_state()
Called when the user opens the Options menu, so the state can base 64 encoded and provided as a URL to share with another user or device.
Should return the current state as a byte array (not base 64 encoded-- the game engine handles that).
get_init_state
get_init_state()
Called when the user opens the Options menu, so the state can base 64 encoded and provided as a URL to share with another user or device.
Should return the initial state as a byte array (not base 64 encoded-- the game engine handles that).
Games don't need to implement this unless it makes sense for their game (e.g. if a puzzle is randomly generated)
handle_user_clicked
handle_user_clicked(pos_y, pos_x)
Called when the user clicks (or touches, with their finger) on the screen.
This is different from a mouse (or touch) down or up event, since it should only be called if the user presses down and releases without moving too much.
pos_y, pos_x
: See coordinates for more information.
handle_mouse_evt
handle_mouse_evt(evt_id, pos_y, pos_x, buttons)
This callback is only called if enabled by calling alexgames.enable_evt("mouse_updown"). This will send events for the primary (usually left) mouse button. To receive events for the secondary (usually right) mouse button and third (usually the wheel) mouse button, enable alternate button mouse events by also calling alexgames.enable_evt("mouse_alt_updown") (you should still enable mouse_updown
events). This will also disable the context menu that normally shows up when pressing the alternate (usually right) mouse button.
If enabled, this callback is called whenever the user presses or releases their mouse over the game screen.
evt_id
: one of:alexgames.MOUSE_EVT_UP
,alexgames.MOUSE_EVT_DOWN
: primary mouse button released or pressed. Primary usually means the left mouse button, but this can be remapped in software or the mouse itself (e.g. for some left handed users)alexgames.MOUSE_EVT_LEAVE
: user's mouse has moved off screen. When it returns, different mouse buttons may be pressed.alexgames.MOUSE_EVT_ALT_DOWN
,alexgames.MOUSE_EVT_ALT_UP
: secondary mouse button released or pressed. Secondary usually means the right mouse button, but this can be changed (e.g. for some left handed users)alexgames.MOUSE_EVT_ALT2_DOWN
,alexgames.MOUSE_EVT_ALT2_UP
: third mouse button released or pressed. This is usually the middle mouse button (which is likely a wheel).
pos_y
,pos_x
: y and x position of the mouse. See coordinates for more information.buttons
: Indicates which buttons are currently pressed. This is useful if the user moves their mouse off screen, presses or releases a button (which won't fire an event), and then moves the mouse back on screen. Unfortunately it's just a passthrough of the HTML MouseEvent#buttons property for now, I should formalize this in a future update.
handle_mousemove
handle_mousemove(pos_y, pos_x, buttons)
This callback is only called if enabled by calling alexgames.enable_evt("mousemove").
If enabled, this callback is called whenever the user moves their mouse over the game screen.
pos_y, pos_x
: y and x coordinates showing where the user's mouse currently is. See coordinates for more information.buttons
: Indicates which buttons are currently pressed. This is useful if the user moves their mouse off screen, presses or releases a button (which won't fire an event), and then moves the mouse back on screen. Unfortunately it's just a passthrough of the HTML MouseEvent#buttons property for now, I should formalize this in a future update.
handle_wheel_changed
handle_wheel_changed(delta_y, delta_x)
This callback is only called if enabled by calling alexgames.enable_evt("wheel").
Mouse wheel changed. This is generally only used for scrolling or zooming.
See HTML Wheel event for more detail.
handle_key_evt
handle_key_evt(evt_id, key_code)
This callback is only called if enabled by calling alexgames.enable_evt("key").
The user pressed a button on the keyboard while focused on the game.
evt_id
: either"keydown"
for when a key is pressed, or"keyup"
for when a key is released. (Same as the HTML key event names).key_code
: indicates which key was pressed, e.g."KeyA"
for the letter A,"ArrowLeft"
for the left arrow key, or"Enter"
, or"Space"
. See KeyboardEvent.code for more detail.- Return
true
if the key is handled by this game,false
otherwise.
Should return true
if the key is handled by the game, and false
if not. Note that this doesn't mean that the key necessarily was handled, but that the game typically handles it. (e.g. don't return false here if the same key is sent multiple times, as is the case with letter keys. Otherwise, if the user holds the up arrow to move their character up, and you return false on the duplicate events, then the up arrow will be handled by the browser and may result in scrolling.
Note that some game platforms do not have the same capabilities as browsers. wxWidgets seems to be unable to distinguish between left and right Alt keys.
Note that some characters that correspond to important browser keyboard shortcuts should not be handled by the game. I have blocked certain ones (Ctrl + R), but concede that some have legitimate uses (e.g. Ctrl L for "navigate to address bar" conflicts with games where you hold control and move with HJKL keys as arrows).
handle_touch_evt
handle_touch_evt(evt_id, touches)
example_touch = { -- identifier to distinguish from other fingers touching the screen. id = 11, -- y and x position of the finger y = 75.123, x = 99.456, }
This callback is only called if enabled by calling alexgames.enable_evt("touch").
Called when the user touches the screen, either first pressing a finger to the screen, moving the finger, releasing the finger, or moving the finger off screen.
Note that touches are unlike mouse events in that the user can use multiple fingers to touch the screen at once. So you need to pay attention to the id
of each touch event.
evt_id
: either"touchstart"
,"touchmove"
,"touchend"
, or"touchcancel"
.touches
: table containing list of touches, seeexample_touch
defined above. See MDN: Touch and MDN: Touch events for more detail.
handle_btn_clicked
handle_btn_clicked(btn_id)
User pressed the button indicated by string btn_id
. These are buttons created via the create_btn.
handle_popup_btn_clicked
handle_popup_btn_clicked(popup_id, popup_btn_id)
User pressed a button (identified by integer popup_btn_id
) on a popup (identified by string popup_id
).
popup_id
: string identifying the popup. This is the popup ID passed to show_popup.popup_btn_id
: integer identifying the popup button. This is the popup button ID passed to thepopup_info
argument of show_popup.