Skip to content

4. UI and windows

one-nora edited this page May 10, 2026 · 2 revisions

Scheme

  • WKLibWindow for independent windows
  • ModTab for mod-list UI
  • UIUtility for reusable controls and popups

Creating a WKLib Window

WKLibWindow is an abstract base class for a custom window.

It has 2 overridable methods

  • Draw(ImGui gui, bool isRootPanelOpen) is called each frame (inside Update()), isRootPanelOpen dictates whether the overlay is currently open or not
  • HandleInput(ImGui gui) is called before any drawing happens, just after the keyboard state is updated, this function is meant to handle things like keybinds modifying values

And 1 member

  • isOpen whether the window is currently open, it defaults to false

The window is meant to be registered inside your WKLibAPI instance. Using WKLibAPI.AddWindow(WKLibWindow window)

Examples

Creating the window

using WKLib.API.UI;

public class MyWindow : WKLibWindow
{
    public bool TestBool = false;
    public float TestValue = 20f;
    public static ConfigValue<bool> TestConfigValue = new ConfigValue<bool>(WKLibAPI, nameof(TestConfigValue), true);
    
	public MyWindow()
	{
		isOpen = false; // By default its false, it can be changed to true here
	}
	
	public override void Draw(ImGui gui, bool isRootPanelOpen)
    {
		if (!isRootPanelOpen)
            return;
        
        if (!gui.BeginWindow("My window name", ref isOpen, new ImSize(400, 400), ImWindowFlag.None))
            return;

        gui.Separator("My separator");
        gui.Text("Hello");
        if (gui.Checkbox(ref TestBool, "Test bool"))
        {
            // do something
        }

        if (TestBool)
        {
            gui.NumericEdit(ref TestValue, min: 0f, max: float.MaxValue, format: "0.0", flags: ImNumericEditFlag.Slider);
        }

		if (gui.Checkbox(ref TestConfigValue.RefValue, "Test bool"))
		{
			// do something
			// like saving
			WKLibAPI.DefaultConfigFile.SaveSync();
		}

        gui.EndWindow();
    }

    public override void HandleInput(ImGui gui)
    {
		var pressedKey = InputUtility.GetKeyDown(KeyCode.LeftControl); // Also works on draw
		if (pressedKey)
		{
			// do something
		}
    }
}

Registering the window

//... Somewhere in your code
public static MyWindowObject = new MyWindow();

//... Somewhere inside your plugin Awake() function
WKLibAPI.AddWindow(MyWindowObject);

For more examples checkout this code

Adding a plugin to the Mod List

ModTab is an abstract base class used for adding a tab to the Mod List window. There can only be 1 ModTab per WKLibAPI instance

It has 1 overridable method

  • DrawSubMenu(ImGui gui) its called when drawing the tab submenu

And 1 overridable member

  • DisplayName the label that will be used when drawing the menu tab

So the structure will be something like this

Mod list window
- DisplayName
	- DrawSubMenu(gui)
- DisplayName // next mod
	- DrawSubMenu(gui)
// and so on

Examples

using WKLib.API.UI;

public class MyModListTab : ModTab
{  
    public override string DisplayName => "My mod tab";  
      
    public override void DrawSubMenu(ImGui gui)  
    {  
	    gui.Text("My text");
        if (gui.Button("My button"))  
        {  
	        // do something
        }
    }  
}

Adding the tab to the mod list

//... Somewhere inside your plugin Awake() function
WKLibAPI.AddToModList(new MyModListTab());

UI Utility

Utility methods for common UI interactions.

Creating a Popup

  • UIUtility.ShowPopupForTime(string text, float seconds = 2.5f) creates a window with the specified text that last for seconds amount

Labeled Scope

Helper for labeled horizontal layouts.

So instead of having

"My slider"
(Slider component)

It will look like

"My slider" (Slider component)

Example

private static float myValue = 5f;

using (new LabeledScope(gui, "My slider", 0.6f)) // 0.6f is the width percentage that the text will use (1f being the total width)
{
	gui.Slider(ref myValue, 0.0f, 10.0f); // the rest of the width (0.4f) will be used by the next element (in this case the slider)
}

Clone this wiki locally