Creating a User Interface

Scripts have the capability to present user interfaces using Dear ImGui. While this document won't provide an exhaustive tutorial on using ImGui, you can explore the imgui_demo.cpp file as a reference to understand how to create interfaces. Additionally, you can enable the in-game ImGui demo through the GUI.EnableDemoUI setting for hands-on experience.

Creating a user interface

To begin creating a user interface, you'll need to utilize two essential modules: utilityBelt.views and imgui. Let's start with a straightforward example—a window displaying text that varies based on your login state.

Open the helloworld script in your text editor and add the following code:

-- load needed modules
local ubviews = require("utilitybelt.views")
local im = require("imgui")
-- add a shortcut to ImGui api namespace
local ImGui = im.ImGui
-- Create a new hud, managed by ub view system
local hud = ubviews.Huds.CreateHud("My Script")
-- Configure the hud
-- this shows an icon for our window in the ub hud bar
hud.ShowInBar = true
-- window should always resize itself to fit its contents
hud.WindowSettings = im.ImGuiWindowFlags.AlwaysAutoResize
-- subscribe to the huds render event and draw some ui elements
hud.OnRender.Add(function ()
  if game.State == ClientState.In_Game then
    -- ImGui.Text draws text to the window
    ImGui.Text("I am logged in as " .. game.Character.Weenie.Name)
  else
    ImGui.Text("I am logged out")
  end
end)

The utilityBelt.views module provides access to the ub hud system which is a wrapping api for creating imgui windows and showing them on the ub hud bar. The imgui module gives us access to the imgui api.

When you create a hud, it exposes an OnRender method as shown above. This is called every time the ui is rendered (generally once per frame). Since imgui is an immediate-mode ui system, we need to draw our ui controls every time the OnRender event is fired.

Warning

It's important to do any heavy calculations outside of the render event, and keep it responsible for only updating the ui controls. The render event is called synchronously so any extra processing will drop the game's frame rate. If you can help it, it's best to update any ui state in another event handler, and then just draw the results during render.

Accepting user input

Here's an example of how to accept text input from a user in your ui. Start with the script above and replace the render event handler with the following (make sure to declare the myText local variable above the event handler as well):

local myText = "default text"
hud.OnRender.Add(function ()
  -- display a text input. inputChanged is a bool that tells us if the input
  -- value has changed this frame, and textResult is the new value it was set to. 500
  -- is the max length of characters this input accepts
  local inputChanged, textResult = im.InputText("myText Input", myText, 500)
  -- check if the input value was changed and print the result
  if inputChanged then
    myText = textResult
    print("myText was changed to:", myText)
  end
end)

In the above example, inputChanged is set to true every time the value of the input changes (even while typing!).