Chat about this codebase

AI-powered code exploration

Online

Project Overview

FGUI is a lightweight, game-oriented C++ GUI library optimized for DirectX and OpenGL applications. It delivers a minimal-overhead, header-only toolkit with runtime-configurable widgets using JSON, making it ideal for in-game overlays, tools, and modding interfaces.

Main Goals

  • Lightweight: Zero external dependencies outside of your graphics API.
  • Game-Oriented: Designed for low-latency, in-game overlays and utilities.
  • Graphics API Friendly: Seamless integration with DirectX 9/11/12 and OpenGL.
  • Configurable: Define layouts, styles, and themes via JSON files.
  • Header-Only: Single FGUI.hpp include for all widgets and builders.

When to Choose FGUI

  • You need a performant, in-game GUI with minimal footprint.
  • You prefer runtime theme/layout changes without recompilation.
  • You want a clean, self-contained codebase without Boost or other heavy dependencies.
  • You build game hacks, overlays, trainers, or engine tools targeting DirectX/OpenGL.

Quick Start

Include the main header and create a simple window with a button:

#include "FGUI/FGUI.hpp"
using namespace fgui;

int main()
{
    // Initialize your graphics (DirectX/OpenGL) here...
    
    // Create a GUI window
    window settings("Settings", { 400, 300 });
    
    // Add a button
    settings.add<widgets::button>("Apply")
            .setSize({ 100, 30 })
            .setPosition({ 150, 200 })
            .setCallback([]() {
                // handle button click
            });
    
    // Main loop
    while (running)
    {
        // Begin frame (your renderer)
        settings.draw();   // Render FGUI
        // Present frame...
    }
    
    return 0;
}

Licensing

FGUI is released under the MIT License. Include the LICENSE file in your distributions to comply with usage and attribution requirements.

Getting Started

This guide walks you through cloning the repo, configuring your build, and rendering your first FGUI window with a clickable button.

1. Clone the Repository

git clone https://github.com/otvv/fgui.git

2. Configure Your Build

CMake

Create CMakeLists.txt in your project root:

cmake_minimum_required(VERSION 3.10)
project(FGUIApp)

# Add the FGUI library
add_subdirectory(fgui)

# Your executable
add_executable(FGUIApp main.cpp)

# Include FGUI headers and link the library
target_include_directories(FGUIApp PRIVATE ${CMAKE_SOURCE_DIR}/fgui)
target_link_libraries(FGUIApp PRIVATE fgui)
set_target_properties(FGUIApp PROPERTIES CXX_STANDARD 17)

Then:

mkdir build && cd build
cmake ..
cmake --build . --config Release

Manual (GCC/Clang)

g++ main.cpp fgui/src/*.cpp -I fgui -std=c++17 -ld3d9 -o FGUIApp

3. Minimal Win32 + Direct3D9 Example

Create main.cpp alongside your CMakeLists.txt or compile directly.

#include <windows.h>
#include <d3d9.h>
#include "FGUI/FGUI.hpp"

// Direct3D globals
static IDirect3D9*        g_d3d   = nullptr;
static IDirect3DDevice9*  g_device= nullptr;

// Main FGUI window
static std::shared_ptr<FGUI::CContainer> g_Window;

// Forward declarations
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
bool InitD3D(HWND);
void CleanupD3D();
void RenderFrame();
void BindInput();

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, PSTR, int nShow) {
    // Register and create a Win32 window
    WNDCLASSEX wc = { sizeof(wc), CS_CLASSDC, WndProc, 0,0, hInst, nullptr, nullptr, nullptr, nullptr, "FGUIApp", nullptr };
    RegisterClassEx(&wc);
    HWND hwnd = CreateWindow("FGUIApp", "FGUI Demo", WS_OVERLAPPEDWINDOW,
                             100,100,800,600, nullptr,nullptr,wc.hInstance,nullptr);
    if (!InitD3D(hwnd)) return 0;

    // Bind Win32 input callbacks
    BindInput();

    // Configure the FGUI window
    g_Window = std::make_shared<FGUI::CContainer>();
    g_Window->SetTitle("Demo Window");
    g_Window->SetKey(VK_INSERT);
    g_Window->SetState(true);

    // Add a button via the CBuilder API
    FGUI::CBuilder()
      .Widget(std::make_shared<FGUI::CButton>())
      .Title("Click Me")
      .Position(50, 60)
      .Size(100, 30)
      .Callback([](){
          MessageBox(nullptr, "Button clicked!", "FGUI", MB_OK);
      })
      .SpawnIn(g_Window);

    ShowWindow(hwnd, nShow);

    // Main loop
    MSG msg = {};
    while (msg.message != WM_QUIT) {
        if (PeekMessage(&msg, nullptr,0,0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        } else {
            // Poll input and render
            FGUI::INPUT.PullInput();
            RenderFrame();
        }
    }

    CleanupD3D();
    UnregisterClass("FGUIApp", wc.hInstance);
    return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    if (msg == WM_DESTROY) {
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

bool InitD3D(HWND hwnd) {
    g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
    if (!g_d3d) return false;
    D3DPRESENT_PARAMETERS pp = {};
    pp.Windowed = TRUE;
    pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    pp.BackBufferFormat = D3DFMT_UNKNOWN;
    if (FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
                                   hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &pp, &g_device))) {
        return false;
    }
    return true;
}

void CleanupD3D() {
    if (g_device) g_device->Release();
    if (g_d3d)    g_d3d->Release();
}

void RenderFrame() {
    g_device->BeginScene();
    g_device->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_XRGB(30,30,30), 1.0f, 0);

    // Render all widgets in the container
    g_Window->Render(*g_device);

    g_device->EndScene();
    g_device->Present(nullptr, nullptr, nullptr, nullptr);
}

void BindInput() {
    // Pull Win32 messages into FGUI
    FGUI::INPUT.PullInput = [](){
        MSG msg;
        while (PeekMessage(&msg, nullptr,0,0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    };

    // Key edge tracking
    static bool prevState[256] = {};
    FGUI::INPUT.IsKeyHeld = [](https://github.com/otvv/fgui/blob/master/unsigned int vk){
        return (GetAsyncKeyState(vk) & 0x8000) != 0;
    };
    FGUI::INPUT.IsKeyPressed = [&](https://github.com/otvv/fgui/blob/master/unsigned int vk){
        bool down = (GetAsyncKeyState(vk)&0x8000)!=0;
        bool pressed = down && !prevState[vk];
        prevState[vk] = down;
        return pressed;
    };
    FGUI::INPUT.IsKeyReleased = [&](https://github.com/otvv/fgui/blob/master/unsigned int vk){
        bool down = (GetAsyncKeyState(vk)&0x8000)!=0;
        bool released = !down && prevState[vk];
        prevState[vk] = down;
        return released;
    };

    FGUI::INPUT.GetCursorPos = [](){
        POINT pt; GetCursorPos(&pt);
        return FGUI::POINT{pt.x, pt.y};
    };
    FGUI::INPUT.GetCursorPosDelta = [](){
        static FGUI::POINT last{0,0};
        auto cur = FGUI::INPUT.GetCursorPos();
        FGUI::POINT d{cur.x - last.x, cur.y - last.y};
        last = cur;
        return d;
    };
    FGUI::INPUT.IsCursorInArea = [](https://github.com/otvv/fgui/blob/master/FGUI::AREA a){
        auto p = FGUI::INPUT.GetCursorPos();
        return p.x >= a.x && p.x < a.x + a.w
            && p.y >= a.y && p.y < a.y + a.h;
    };

    FGUI::INPUT.SetInputType(FGUI::INPUT_TYPE::WIN_32);
}

4. Verify and Run

  • Build via CMake or your compiler command above.
  • Run the resulting executable.
  • Press INS to toggle the window, then click Click Me.

You now have a working FGUI window. Explore more widgets in FGUI/FGUI.hpp and customize rendering/input by inspecting the internal headers.

Widgets Reference

A catalogue of all ready-made controls shipped with FGUI. Each entry includes purpose, key methods, and a quick usage snippet.


CButton Widget

Purpose

Render a clickable button with built-in hover styling and optional tooltip. Invoke a user-supplied callback when clicked.

Essential API

  • Constructor
    Initializes title = “Button”, size = (100×25), no font, no tooltip, no callback.
  • void AddCallback(std::function<void()> fn)
    Register a single click handler (replaces any existing).
  • Geometry(status)
    Draws the body (default or hovered colors) and centers the title text.
  • Input()
    Invoked on click; calls your callback if set.
  • Tooltip()
    If a non-empty tooltip is set and the cursor hovers, draws a styled tooltip box.

Common Configuration Methods (inherited from CWidgets)

  • SetTitle(const std::string& title)
  • SetSize(DIMENSION size)
  • SetPosition(POINT pos)
  • SetFont(FontID font)
  • SetTooltip(const std::string& tip)

Code Examples

Instantiate and configure a button, then handle its click:

// assume `window` is your FGUI page or container
auto btn = window->AddWidget<FGUI::CButton>();    // create and add to UI
btn->SetTitle("Submit");                         // change label
btn->SetSize({120, 30});                         // wider button
btn->SetPosition({50, 100});                     // x=50, y=100
btn->SetFont(myFontHandle);                      // previously loaded font
btn->SetTooltip("Send your data to the server"); // optional hover text

btn->AddCallback([](){
    std::cout << "Submit clicked!\n";
    SendFormData();
});

Handling button state in your main loop:

while (running)
{
    renderer.BeginFrame();
    ui.ProcessInput();     // routes mouse events into widgets
    ui.UpdateWidgets();    // calls Update() on each widget
    ui.RenderWidgets();    // calls Geometry(status) and Tooltip()
    renderer.EndFrame();
}

Practical Guidance

  • Only one callback can be registered. Calling AddCallback again replaces the previous handler.
  • To disable, subclass CButton or guard your callback logic.
  • Tooltip appears only if m_strTooltip.length() > 0.
  • For custom theming, derive from CButton and override Geometry().
  • Title text auto-centers; adjust m_dmSize first if you change font or title after construction.

CComboBox Widget

Purpose

Display a drop-down list of entries with optional values, allow selection, and react via callbacks.

Essential API

  • void AddEntry(const std::string& name, unsigned int value = 0)
    Append an entry with display string and optional custom value.
  • void SetIndex(std::size_t index) / std::size_t GetIndex()
    Programmatically select or query the active entry (0-based).
  • void SetValue(std::size_t index, unsigned int value) / unsigned int GetValue()
    Modify or retrieve the custom value of an entry.
  • void AddCallback(std::function<void()> fn)
    Register a function fired whenever the user picks an entry.

Code Examples

Instantiate and populate a combo box:

auto combo = std::make_shared<FGUI::CComboBox>();
combo->SetTitle("Quality");
combo->AddEntry("Low",    1);
combo->AddEntry("Medium", 2);
combo->AddEntry("High",   3);
// Default to "Medium"
combo->SetIndex(1);

React to user selection:

combo->AddCallback([combo](){
    size_t idx   = combo->GetIndex();
    unsigned val = combo->GetValue();
    std::cout << "User picked index=" << idx
              << ", value=" << val << "\n";
});

Read the selection elsewhere:

if (combo->GetIndex() == 2) {
    enableHighQualityRendering();
}

Saving and Loading State

ComboBox implements Save/Load with nlohmann::json, using the widget’s title (spaces→underscores) as the key.

// Saving
nlohmann::json cfg;
combo->Save(cfg);
// cfg["Quality"] == combo->GetIndex()

// Loading
combo->Load(cfg);
// restores combo->GetIndex() from JSON

Practical Tips

  • Always call AddEntry before reading GetValue/GetIndex to avoid out-of-bounds.
  • Omit the value parameter to default it to 0 when you only care about the display string.
  • Use SetIndex to preset a default selection.
  • Register callbacks before entering the GUI loop for immediate handling.
  • Titles must be unique within a container if you rely on Save/Load.

CColorPicker Widget

Purpose

Integrate a color-selection widget into your GUI, configure its appearance and behavior, retrieve RGBA values, and persist state via JSON.

Instantiation & Setup

#include "FGUI/widgets/colorpicker.hpp"

// ...

auto color_picker = std::make_shared<FGUI::CColorPicker>();
color_picker->SetTitle("Background Color");         // Widget label
color_picker->SetColor({255, 128, 0, 255});         // Default RGBA (orange)
color_picker->SetPixelation(4);                     // Granularity of the color grid
color_picker->SetRelativePosition({10.f, 10.f});    // Position inside parent container
color_picker->SetTooltip("Pick your background color");

parent_container->AddWidget(color_picker);

Runtime Interaction

  • Toggling: Clicking the color swatch opens or closes the picker panel.
  • Adjusting: Drag the hue bar or alpha bar; saturation/value updates in the main square.
  • Retrieving:
FGUI::COLOR current = color_picker->GetColor();
// current.m_ucRed, current.m_ucGreen, current.m_ucBlue, current.m_ucAlpha

Pixelation Tuning

color_picker->SetPixelation(2);  // finer grid, more rectangles drawn
color_picker->SetPixelation(8);  // coarser grid, faster rendering

Persistence (Save / Load)

nlohmann::json module_json;
// Saving
color_picker->Save(module_json);
// module_json["Background_Color"] == { red, green, blue, alpha }

// Loading
if (module_json.contains("Background_Color"))
    color_picker->Load(module_json);

The widget auto-formats its title (spaces→underscores) as the JSON key.

Practical Tips

  • Choose pixelation ~2–4 for balance between smooth gradients and CPU use.
  • The picker keeps focus while open; clicking elsewhere closes it.
  • Use GetColor() in real time (e.g., update materials or shaders each frame).
  • Customize widget size via inherited SetSize(width, height) for a larger swatch.

CContainer::AddWidget

Purpose

Populate a window or groupbox (CContainer) with arbitrary child widgets, automatically handling parent assignment, optional padding, scrollbar adjustments, and draw order.

Signature

void AddWidget(std::shared_ptr<FGUI::CWidgets> widget, bool padding);

Key Details

  • Parent assignment:
    widget->SetParentWidget(shared_from_this());
  • Padding:
    • true: widget width = container width minus 2× its X offset (and minus scrollbar width if enabled)
    • false: widget width unchanged
  • Draw order:
    Containers flagged DRAW_FIRST (e.g., groupboxes) move to the front of m_prgpWidgets.

Code Example

auto mainWindow = std::make_shared<FGUI::CContainer>();
mainWindow->SetPosition({50, 50});
mainWindow->SetSize({400, 300});
mainWindow->SetKey(VK_INSERT);           // toggle with INSERT
mainWindow->AddCallback([](){             // custom draw before children
    // draw background image
});

// Add a checkbox at (10,40) with padding
auto checkbox = std::make_shared<FGUI::CCheckBox>();
checkbox->SetTitle("Enable feature");
checkbox->SetPosition({10, 40});
mainWindow->AddWidget(checkbox, true);

// Add a nested groupbox
auto groupbox = std::make_shared<FGUI::CContainer>();
groupbox->SetTitle("Options");
groupbox->SetPosition({10, 80});
groupbox->SetSize({380, 150});
groupbox->SetScrollBarState(true);       // enable scrolling
mainWindow->AddWidget(groupbox, false);

// Populate groupbox
auto option1 = std::make_shared<FGUI::CCheckBox>();
option1->SetTitle("Option A");
option1->SetPosition({10, 10});
groupbox->AddWidget(option1, true);

// In your render loop:
mainWindow->Render();

Practical Usage Guidance

  • Padding = true
    • Applies horizontal margins equal to the widget’s X position on both sides.
    • If scrollbar is on, subtract ~15px scrollbar width.
  • Padding = false
    • Retains original widget width; useful for full-width panels.
  • Nested containers
    • Use SetScrollBarState(true) to enable vertical scrolling on overflow.
    • Child positions are relative to the container’s client area; scroll offset shifts rendering and input.
  • Layout changes
    • After adding/removing widgets, the container recalculates sizes and scrollbar thumb positions on next render/update.
  • Focus and input
    • Clicking a child with CLICKABLE & FOCUSABLE flags focuses it, suspending other children until unfocused.

By following these conventions, you ensure consistent padding, scrollbar behavior, parent/child linkage, and correct draw and input ordering within FGUI containers.

Advanced Usage & Customization

Power-user patterns for large, skinnable menus: precise layout control, backend integration, and input remapping.

Widget Positioning and Sizing

Control each widget’s local and absolute coordinates in nested containers.

API

  • void SetPosition(unsigned x, unsigned y)
  • FGUI::POINT GetPosition()
  • FGUI::POINT GetAbsolutePosition()
  • void SetSize(unsigned w, unsigned h)
  • FGUI::DIMENSION GetSize()

Example

#include "FGUI/widgets/widgets.hpp"

// Create container and button
auto panel  = std::make_shared<FGUI::CContainer>();
auto button = std::make_shared<FGUI::CButton>("Submit");
panel->AddChild(button);

// Set panel layout
panel->SetPosition(100, 200);
panel->SetSize(300, 400);

// Position and size the button
button->SetPosition(20, 50);
button->SetSize(120, 30);

// Query positions
FGUI::POINT local = button->GetPosition();         // {20,50}
FGUI::POINT absolute = button->GetAbsolutePosition(); // {120,250}

Tips

  • Call setters during your container’s setup phase.
  • On window resize, update positions/sizes then invoke panel->Update().
  • Use GetAbsolutePosition() for tooltips or pop-ups in nested layouts.
  • Pass around DIMENSION when configuring bulk layouts.

Backend Hooking: Rendering and Input

Wire your engine’s draw and input functions into FGUI for backend-agnostic widgets.

Rendering

Assign your drawing primitives to FGUI::RENDER.

#include "FGUI/backend/render.hpp"

// Engine wrappers
void MyCreateFont(FGUI::FONT &f, std::string fam, int sz, int wt, bool aa) { /*...*/ }
FGUI::DIMENSION MyGetScreenSize() { return {800, 600}; }
FGUI::DIMENSION MyGetTextSize(FGUI::FONT f, const std::string &s) { /*...*/ }
void MyDrawRect(int x, int y, int w, int h, FGUI::COLOR c) { /*...*/ }
void MyDrawText(int x, int y, FGUI::FONT f, FGUI::COLOR c, const std::string &s) { /*...*/ }

void InitFGUIRenderer() {
  FGUI::RENDER.CreateFont    = MyCreateFont;
  FGUI::RENDER.GetScreenSize = MyGetScreenSize;
  FGUI::RENDER.GetTextSize   = MyGetTextSize;
  FGUI::RENDER.Rectangle     = MyDrawRect;
  FGUI::RENDER.Outline       = MyDrawRect;
  FGUI::RENDER.Gradient      = /* your gradient impl */;
  FGUI::RENDER.Line          = /* your line impl */;
  FGUI::RENDER.Text          = MyDrawText;
}

Always assign render callbacks before instantiating any widgets.

Input

Bind your input polling and queries to FGUI::INPUT.

#include "FGUI/backend/input.hpp"
#include <Windows.h>

void Win32Pull() {
  MSG m;
  while (PeekMessage(&m, 0, 0, 0, PM_REMOVE))
    DispatchMessage(&m);
}

bool Win32KeyHeld(unsigned vk) { return (GetAsyncKeyState(vk) & 0x8000); }
FGUI::POINT Win32GetCursor() {
  POINT p;
  GetCursorPos(&p);
  ScreenToClient(hWnd, &p);
  return p;
}

void InitFGUIInput() {
  FGUI::INPUT.PullInput         = Win32Pull;
  FGUI::INPUT.IsKeyHeld         = Win32KeyHeld;
  FGUI::INPUT.IsKeyPressed      = /* your press-detection logic */;
  FGUI::INPUT.IsKeyReleased     = /* your release-detection logic */;
  FGUI::INPUT.GetCursorPos      = Win32GetCursor;
  FGUI::INPUT.GetCursorPosDelta = []{ return FGUI::POINT{0,0}; }; // optional
  FGUI::INPUT.IsCursorInArea    = [](https://github.com/otvv/fgui/blob/master/FGUI::AREA a){
    auto p = FGUI::INPUT.GetCursorPos();
    return p.m_iX >= a.m_iLeft && p.m_iX <= a.m_iRight
        && p.m_iY >= a.m_iTop  && p.m_iY <= a.m_iBottom;
  };
  FGUI::INPUT.SetInputType(FGUI::INPUT_TYPE::WIN_32);
}

Usage:

  • Call FGUI::INPUT.PullInput() once per frame before UI update.
  • Query IsKeyPressed/IsKeyHeld in widget event loops.
  • Use SetInputType() to adjust widget behavior per platform.

Keycodes & Remapping

FGUI defines platform-agnostic key and mouse macros. Override them to integrate custom input APIs.

Default Macros

MOUSE_1, MOUSE_2, KEY_ESCAPE, KEY_ENTER, KEY_BACKSPACE,
KEY_LSHIFT, KEY_RSHIFT, KEY_DELETE, KEY_LEFT, KEY_RIGHT,
KEY_UP, KEY_DOWN, KEY_PAGEUP, KEY_PAGEDOWN, KEY_LCONTROL,
KEY_RCONTROL, KEY_A, KEY_SPACE

Windows maps these to VK_*; other platforms use Source Engine codes.

Custom Mapping

Create a central header to redefine before including FGUI:

// MyInputConfig.hpp
#undef KEY_SPACE
#define KEY_SPACE 0x20
#undef MOUSE_1
#define MOUSE_1 0x01

#include "FGUI/internal/helpers.hpp"

Example

#include "MyInputConfig.hpp"
#include "FGUI/widgets/widgets.hpp"

if (FGUI::INPUT.IsKeyPressed(KEY_SPACE)) {
  button->Toggle();
}

if (FGUI::INPUT.IsKeyPressed(MOUSE_1)) {
  auto pos = FGUI::INPUT.GetCursorPos();
  FGUI::RENDER.Rectangle(pos.m_iX, pos.m_iY, 10, 10, {255,0,0,255});
}

Best Practices:

  • Use macros throughout your code for single-point remapping.
  • Keep redefinitions in one header to avoid mismatches.

Contributing Guide

This guide explains how to build the FGUI library, run tests, follow coding standards, prepare pull requests, and comply with licensing requirements.

Building FGUI

Prerequisites

  • C++17-compatible compiler (MSVC 2019+, GCC 9+, Clang 10+)
  • CMake 3.15+
  • DirectX SDK (Windows)
  • nlohmann/json (optional: bundled via submodule)

Clone and Configure

git clone https://github.com/otvv/fgui.git
cd fgui
git submodule update --init --recursive

Unix/macOS

mkdir build && cd build
cmake .. \
  -DCMAKE_BUILD_TYPE=Release \
  -DFGUI_BUILD_EXAMPLES=ON \
  -DFGUI_BUILD_TESTS=ON
cmake --build . -- -j$(nproc)

Windows (PowerShell)

mkdir build; cd build
cmake .. `
  -G "Visual Studio 16 2019" `
  -A x64 `
  -DFGUI_BUILD_EXAMPLES=ON `
  -DFGUI_BUILD_TESTS=ON
cmake --build . --config Release

Running Tests

Unit Tests

FGUI uses GoogleTest for unit testing. Enable with -DFGUI_BUILD_TESTS=ON.

cd build
ctest --output-on-failure
# or invoke directly
./tests/FGUITestRunner

UI/Integration Tests

Example applications serve as manual UI tests.

# After build
./bin/ExampleApp           # Linux/macOS
.\bin\Release\ExampleApp.exe  # Windows

Coding Standards

  • Language: C++17, RAII, avoid raw pointers when possible.
  • Naming:
    • Classes/Structs: PascalCase (e.g. WidgetRenderer)
    • Methods/Variables: camelCase (e.g. renderFrame)
    • Constants/Macros: UPPER_SNAKE_CASE (e.g. FGUI_MAX_CONTROLS)
  • Indentation: 4 spaces, no tabs.
  • Bracing style: Allman (brace on new line).
  • Formatting: run clang-format against .clang-format at repo root.
    clang-format -i src/**/*.h src/**/*.cpp
    
  • Commit messages:
    TYPE(scope): brief description
    
    • More detailed description (if needed)
    • References: #<issue-number>
    

Pull Request Checklist

  • Branch off develop or issue-specific branch.
  • All unit tests pass (ctest exit code 0).
  • Examples compile and run.
  • Code formatted (clang-format) and linted.
  • Add or update unit tests for new behavior.
  • Update documentation in docs/ or README.md.
  • Include license header in new source files:
    // SPDX-License-Identifier: MIT
    // Copyright (c) <Year> otvv
    
  • Link related issue or feature request.
  • Use clear, descriptive PR title and description.

Licensing Reminder

FGUI is MIT-licensed. Derivative works must include the LICENSE file and retain copyright
and warranty disclaimer. For details, see LICENSE.