In this entry, we will show you how to create different types of UI components.

Generating your files

A swift introduction to the UVKBuildTool

The UVKBuildTool is a custom build tool we built to generate production builds, source files and more. The tool binary is located under the UVKBuildTool/build directory. Running it with the --help argument shows you the different options you have on hand:

    --generate <project path> - Regenerates all required generated files for the given project
    --install <project path> - Generates the project files when installing for the first time
    --build <project path> - Bundles the application and compiles it for production
The following arguments generate source files for UI components:
    --inline <name> <project path> - Creates an inline component
    --window <name> <project path> - Creates a window widget
    --title-bar <name> <project path> - Creates a titlebar widget

As you can see from the comments, the first flag --generate regenerates the files of a project. This is necessary for applying changes to project file templates, but most of the time we don't break the API, so you won't use it frequently.

The --install command is used to generate project files for first time installation. You shouldn't run this alone, but rather use the create-project.sh script to create a project.

The --build argument builds a given project for production.

Finally, we have the 3 component commands, when given a name and a path to a project they generate different components:

  1. --inline for creating inline components
  2. --window for creating window components
  3. --title-bar for creating title bar components

Component types

There are 3 component types:

  1. --inline
  2. --window
  3. --title-bar

Inline components are ones that are drawn directly to the framebuffer just like how standard applications render UI. Here is an application that uses inline components:

image


Window components are components that are drawn inside separate Windows. These windows can be docked, dragged out of the main window and moved by the user to create their own layout. Below is a window in floating mode:

image

Here is a window that is docked to the side:

image

Here is a window that is rendered outside the main window:

image


Finally, title bar components are components that render the main title bar, which can be seen at the top of the window in the window component examples.

Working with UI components

After you have generated your components with the UVKBuildTool, you can now start using them. The header file of a component looks like this:

#pragma once
#include <Framework.hpp>

namespace UntitledTextEditor
{
    class UIMGUI_PUBLIC_API Exit : public UImGui::WindowComponent
    {
    public:
        Exit();
        virtual void begin() override;
        virtual void tick(float deltaTime) override;
        virtual void end() override;
        virtual ~Exit() override;
    private:

    };
}

It contains the essential event functions: the constructor, destructor, begin, end and tick functions. Here is information on them:

  1. begin - gets called when the application is opened
  2. tick - gets called every frame and takes the float deltaTime parameter that is equal to the current delta time
  3. end - gets called when the application closes or the widget is destroyed
  4. The constructor - Should contain variable initialization code(event safety is unknown and depends on how you wrote your application)
  5. The destructor - Should contain cleanup code

Keep event safety in mind and preferably call most framework dependent code in the begin, end or tick functions.

Since the tick function gets called every frame, you should use it to render dear imgui code.

Writing a Hello World application

First generate an inline class:

cd UVKBuildTool/build
https://madladsquad.com/UVKBuildTool --inline hello .https://madladsquad.com/.https://madladsquad.com/Projects/YourProjectNameHere

Next, refresh your CMakeLists.txt file under your project directory and enter the Source folder. The hello.cpp and hello.hpp header will have been generated.

Open hello.cpp, it should look like this:

#include "hello.hpp"

Example::hello::hello()
{

}

void Example::hello::begin()
{
    beginAutohandle();

}

void Example::hello::tick(float deltaTime)
{
    tickAutohandle(deltaTime);

}

void Example::hello::end()
{
    endAutohandle();

}

Example::hello::~hello()
{

}

In the tick function, add the following code so that it looks like this:

void Example::hello::tick(float deltaTime)
{
    tickAutohandle(deltaTime);
    ImGui::Text("Hello, World")
}

Compile your application and run!

Oh... there is no text here. That's because you haven't initialized the framework with your component. The next wiki entry shows you how to do that!

Event safety

The begin and tick members are flagged as All ready and end is flagged as Pre-destruct. The rest are flagged as Any time.

C API

CComponentData and CComponentData_P

The UImGui_CComponentData is only used when initializing a component from C. It looks like this:

typedef struct UImGui_CComponentData
{
    UImGui_ComponentState state;

    UImGui_String name;
    uint64_t id;
} UImGui_CComponentData;

These variables will be copied into the class.


The UImGui_CComponentData_P struct is almost the same as the UImGui_CComponentData struct, except that all variables are pointers, and it is missing the name string. It looks like this:

typedef struct UImGui_CComponentData_P
{
    UImGui_ComponentState* state;
    uint64_t* id;
} UImGui_CComponentData_P;

This struct is used to give a handle to the same internal variables, part of the given component.

Creating a component through the C API

All components have the following functions:

  1. UImGui_X_makeCXComponent
  2. UImGui_X_getCXComponentData
  3. UImGui_X_getCXComponentName
  4. UImGui_X_destroyCXComponentName

Here, X is one of the following:

  1. Titlebar
  2. WindowComponent
  3. Inline

In this example, we'll be using an inline component, but the setup is the same with other components. The names are just changed in the above specified way.


To create an Inline component call UImGui_Inline_makeCInlineComponent, which looks like this:

UImGui_CComponentHandle UImGui_Inline_makeCInlineComponent(UImGui_ComponentRegularFun construct,
                                                           UImGui_ComponentRegularFun begin, UImGui_ComponentTickFun tick, UImGui_ComponentRegularFun end,
                                                           UImGui_ComponentRegularFun destruct, UImGui_CComponentData data);

It takes 5 function pointers, 4 of type UImGui_ComponentRegularFun and 1 of type UImGui_ComponentTickFun. The last parameter is a struct of type UImGui_CComponentData, which will define the data of the class.

A UImGui_ComponentRegularFun function expands to void(*)(UImGui_CComponentData_P*), while UImGui_ComponentTickFun expands to void(*)(UImGui_CComponentData_P*, float).

These are the functions' event placement:

  1. construct - Called in the constructor
  2. begin - Called on begin event
  3. tick - Called on tick event
  4. end - Called on end event
  5. destruct - Called in the destructor

Finally, the function returns a component handle of type UImGui_CComponentHandle. You need to store this handle to interact with this component.

Other functions

There are 2 data-related functions that can be used on any component:

  1. UImGui_X_getCXComponentData - given a valid handle, returns a pointer to the UImGui_CComponentData_P struct of the class
  2. UImGui_X_getCXComponentName - given a valid handle, returns the name of the class as an UImGui_String

There is also the UImGui_X_destroyCXComponent function, which, given a handle, deallocates and destroys the component.