https://github.com/ktsu-dev/imguiapp
https://github.com/ktsu-dev/imguiapp
c cross-platform dear-imgui desktop frame-limiter gui hexa-net imgui immediate-mode modal net node-editor node-graph opengl popups silk-net theming ui widgets windowing
Last synced: 4 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/ktsu-dev/imguiapp
- Owner: ktsu-dev
- License: mit
- Created: 2023-05-17T13:26:14.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2026-05-26T03:31:45.000Z (11 days ago)
- Last Synced: 2026-05-26T05:08:25.579Z (11 days ago)
- Topics: c, cross-platform, dear-imgui, desktop, frame-limiter, gui, hexa-net, imgui, immediate-mode, modal, net, node-editor, node-graph, opengl, popups, silk-net, theming, ui, widgets, windowing
- Language: C#
- Size: 4.62 MB
- Stars: 4
- Watchers: 1
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
- Authors: AUTHORS.md
- Copyright: COPYRIGHT.md
Awesome Lists containing this project
README
# ktsu.ImGuiApp
> A comprehensive collection of .NET libraries for building modern, feature-rich desktop applications with Dear ImGui.
[](LICENSE.md)
[](https://nuget.org/packages/ktsu.ImGui.App)
[](https://nuget.org/packages/ktsu.ImGui.App)
[](https://nuget.org/packages/ktsu.ImGui.App)
[](https://github.com/ktsu-dev/ImGuiApp/commits/main)
[](https://github.com/ktsu-dev/ImGuiApp/graphs/contributors)
[](https://github.com/ktsu-dev/ImGuiApp/actions)
## Introduction
`ktsu.ImGui.App` is a suite of .NET libraries that provides everything you need to build desktop applications with [Dear ImGui](https://github.com/ocornut/imgui). The suite includes application scaffolding, custom widgets, modal dialogs, a theming system, and a node graph editor framework. Built on Hexa.NET.ImGui bindings and Silk.NET for cross-platform windowing, it supports .NET 10, 9, and 8.
## Features
- **Application Foundation**: Complete application scaffolding with windowing, OpenGL rendering, font management, texture caching, and DPI awareness via `ktsu.ImGui.App`
- **PID Frame Limiting**: High-precision PID-controlled frame rate limiting with auto-tuning and adaptive throttling for focused, unfocused, idle, and minimized states
- **Custom Widgets**: Rich collection of UI components including TabPanel, Knob, SearchBox with fuzzy matching, RadialProgressBar with countdown/count-up timers, Grid layouts, DividerContainer with resizable sections, Combo, Tree, and Icons via `ktsu.ImGui.Widgets`
- **Modal Dialogs**: Professional popup system with MessageOK, Prompt, InputString/Int/Float, FilesystemBrowser, and SearchableList via `ktsu.ImGui.Popups`
- **Theming System**: 50+ built-in themes (Catppuccin, Tokyo Night, Gruvbox, Dracula, and more) with scoped styling, semantic text colors, button alignment, color palettes, and an interactive theme browser via `ktsu.ImGui.Styler`
- **Node Graph Framework**: Attribute-based node declaration system with UI-agnostic `ktsu.NodeGraph` metadata library and ImNodes-based visual editor `ktsu.ImGuiNodeEditor` with physics-based layout
- **Font Management**: Unicode, emoji, and Nerd Font support with GPU memory management via `FontMemoryGuard` and dynamic font scaling
- **Scoped Styling**: RAII-pattern disposable wrappers for colors, styles, fonts, themes, disable states, and UI scaling
- **Color Utilities**: HSL/HSLA color creation, accessibility-focused contrast calculations, color manipulation extensions, and semantic color palettes
## Libraries
### ImGui.App - Application Foundation
[](https://nuget.org/packages/ktsu.ImGui.App)
Complete application scaffolding for Dear ImGui applications with windowing, rendering, font/texture management, and performance tuning.
### ImGui.Widgets - Custom UI Components
[](https://nuget.org/packages/ktsu.ImGui.Widgets)
Rich collection of custom widgets: TabPanel, Knob, SearchBox, RadialProgressBar, Grid, DividerContainer, Combo, Tree, Icons, ColorIndicator, Text, Image, ScopedDisable, and ScopedId.
### ImGui.Popups - Modal Dialogs
[](https://nuget.org/packages/ktsu.ImGui.Popups)
Professional modal dialogs: MessageOK, Prompt, InputString/Int/Float with validation, FilesystemBrowser with glob filtering, and SearchableList with type-safe generics.
### ImGui.Styler - Themes and Styling
[](https://nuget.org/packages/ktsu.ImGui.Styler)
Advanced theming system with 50+ built-in themes, scoped styling, semantic text colors, button alignment, color palettes, and an interactive theme browser.
### NodeGraph - Node Metadata (UI-Agnostic)
[](https://nuget.org/packages/ktsu.NodeGraph)
Generic attribute-based system for declaring node graphs. Decorate classes, structs, and methods with node metadata (pins, execution modes, visibility, deprecation) without coupling to a specific editor implementation.
### ImGuiNodeEditor - Visual Node Editor
Attribute-driven visual node editor built on ImNodes. Includes `NodeEditorEngine` for business logic, `AttributeBasedNodeFactory` for node creation from decorated types, physics-based layout simulation, and `NodeEditorRenderer`/`NodeEditorInputHandler` for rendering and interaction.
## Installation
### Package Manager Console
```powershell
Install-Package ktsu.ImGui.App
Install-Package ktsu.ImGui.Widgets
Install-Package ktsu.ImGui.Popups
Install-Package ktsu.ImGui.Styler
Install-Package ktsu.NodeGraph
```
### .NET CLI
```bash
dotnet add package ktsu.ImGui.App
dotnet add package ktsu.ImGui.Widgets
dotnet add package ktsu.ImGui.Popups
dotnet add package ktsu.ImGui.Styler
dotnet add package ktsu.NodeGraph
```
### Package Reference
```xml
```
## Usage Examples
### Basic Application
```csharp
using ktsu.ImGui.App;
using Hexa.NET.ImGui;
ImGuiApp.Start(new ImGuiAppConfig
{
Title = "My Application",
OnRender = delta =>
{
ImGui.Text("Hello, ImGui!");
}
});
```
### Application with Menu and Performance Settings
```csharp
using ktsu.ImGui.App;
using ktsu.ImGui.Styler;
using Hexa.NET.ImGui;
ImGuiApp.Start(new ImGuiAppConfig
{
Title = "Full Application",
OnStart = () =>
{
Theme.Apply("Tokyo Night");
},
OnRender = delta =>
{
ImGui.Text("Content goes here");
},
OnAppMenu = () =>
{
if (ImGui.BeginMenu("File"))
{
if (ImGui.MenuItem("Exit"))
{
ImGuiApp.Stop();
}
ImGui.EndMenu();
}
},
PerformanceSettings = new ImGuiAppPerformanceSettings
{
FocusedFps = 60.0,
UnfocusedFps = 10.0,
IdleTimeoutSeconds = 30.0
}
});
```
### Overlay Mode (Always-On-Top HUD)
Overlay mode turns the application window into a borderless, always-on-top, translucent HUD
with optional click-through — ideal for live status displays that sit over other apps. Drive
it from your render callback; the calls are cheap to make every frame (the native window is
only restyled when something actually changes). A dedicated `OverlayFps` keeps the overlay
animating smoothly even while unfocused, bypassing the normal focus/idle/visibility throttling.
```csharp
bool overlayEnabled = true;
ImGuiApp.Start(new ImGuiAppConfig
{
Title = "Status HUD",
PerformanceSettings = new ImGuiAppPerformanceSettings { OverlayFps = 60.0 },
OnRender = delta =>
{
if (overlayEnabled)
{
// opacity 0.2–1.0, plus optional click-through (mouse passes through to apps behind it).
ImGuiApp.EnableOverlay(opacity: 0.9f, clickThrough: false);
// Optional: lock it to a corner of the monitor work area (Windows).
ImGuiApp.SetOverlayGeometry(OverlayCorner.TopRight, offsetX: 24, offsetY: 24, width: 360, height: 280);
}
else
{
ImGuiApp.DisableOverlay(); // restores the decorated window
}
ImGui.Text("Live status…");
}
});
```
Overlay window styling (borderless / topmost / translucency / click-through) is implemented on
Windows. On other platforms `IsOverlayActive` and `OverlayFps` still apply, but the window is
not restyled.
### Widgets
```csharp
using ktsu.ImGui.Widgets;
using Hexa.NET.ImGui;
// Tabbed interface
ImGuiWidgets.TabPanel tabPanel = new("MyTabs", closable: true, reorderable: true);
tabPanel.AddTab("tab1", "First Tab", () => ImGui.Text("Content 1"));
tabPanel.Draw();
// Search box with filtering
string searchTerm = "";
TextFilterType filterType = TextFilterType.Glob;
TextFilterMatchOptions matchOptions = TextFilterMatchOptions.ByWholeString;
ImGuiWidgets.SearchBox("##Search", ref searchTerm, ref filterType, ref matchOptions);
// Radial countdown timer
float timeRemaining = 300.0f;
ImGuiWidgets.RadialCountdown(timeRemaining, 300.0f);
// Resizable divider layout
ImGuiWidgets.DividerContainer divider = new("MySplit", ImGuiWidgets.DividerLayout.Columns);
divider.Add("left", 200f, true, dt => ImGui.Text("Left pane"));
divider.Add("right", 400f, true, dt => ImGui.Text("Right pane"));
divider.Tick(deltaTime);
```
### Popups and Dialogs
```csharp
using ktsu.ImGui.Popups;
// Message dialog
ImGuiPopups.MessageOK messageOK = new();
messageOK.Open("Hello!", "This is a message.");
messageOK.ShowIfOpen();
// String input dialog
ImGuiPopups.InputString inputString = new();
inputString.Open("Enter Name", "Name:", "Default", result => ProcessName(result));
inputString.ShowIfOpen();
// File browser
ImGuiPopups.FilesystemBrowser browser = new();
browser.FileOpen("Open File", path => LoadFile(path), "*.txt");
browser.ShowIfOpen();
// Searchable list
ImGuiPopups.SearchableList list = new();
list.Open("Select Item", "Choose:", items, item => OnSelected(item));
list.ShowIfOpen();
```
### Theming and Styling
```csharp
using ktsu.ImGui.Styler;
using Hexa.NET.ImGui;
// Apply a built-in theme
Theme.Apply("Catppuccin Mocha");
// Show interactive theme browser
Theme.ShowThemeSelector("Select Theme");
// Scoped color styling (auto-restored after block)
using (new ScopedColor(ImGuiCol.Text, Color.FromHex("#ff6b6b")))
{
ImGui.Text("This text is red!");
}
// Semantic text colors
using (Text.Color.Error())
{
ImGui.Text("Error message");
}
using (Text.Color.Success())
{
ImGui.Text("Success message");
}
// Center content
using (new Alignment.Center(ImGui.CalcTextSize("Centered!")))
{
ImGui.Text("Centered!");
}
// Button text alignment
using (Button.Alignment.Center())
{
ImGui.Button("Centered text", new Vector2(200, 30));
}
// Scoped theme for a section
using (new ScopedTheme(myTheme))
{
ImGui.Text("This section uses a different theme");
}
```
### Node Graph (Attribute-Based Declaration)
```csharp
using ktsu.NodeGraph;
[Node("Math Add")]
[NodeBehavior(NodeExecutionMode.OnInputChange, IsDeterministic = true)]
public class AddNode
{
[InputPin("A")]
public float A { get; set; }
[InputPin("B")]
public float B { get; set; }
[OutputPin("Result")]
public float Result { get; set; }
[NodeExecute]
public void Execute()
{
Result = A + B;
}
}
```
### Visual Node Editor
```csharp
using ktsu.ImGuiNodeEditor;
// Create engine and factory
NodeEditorEngine engine = new();
AttributeBasedNodeFactory factory = new(engine);
// Register node types
factory.RegisterNodeType();
factory.RegisterNodeTypesFromAssembly(typeof(AddNode).Assembly);
// Create nodes
Node nodeA = factory.CreateNode(new Vector2(100, 100));
// Render in ImGui loop
NodeEditorRenderer renderer = new();
NodeEditorInputHandler inputHandler = new();
renderer.Render(engine, editorSize);
```
## API Reference
### `ImGuiApp` (Static)
Application lifecycle and utilities.
#### Methods
| Name | Return Type | Description |
| ---- | ----------- | ----------- |
| `Start(ImGuiAppConfig)` | `void` | Initialize and run the application |
| `Stop()` | `void` | Close the application window |
| `Show()` / `Hide()` | `void` | Show or hide the window without stopping the render loop |
| `EnableOverlay(float, bool)` | `void` | Enter overlay mode: borderless, always-on-top, translucent, optional click-through |
| `SetOverlayGeometry(OverlayCorner, int, int, int, int)` | `void` | Lock the overlay to a work-area corner at an offset and size |
| `DisableOverlay()` | `void` | Restore the decorated, non-topmost, opaque window |
| `SetGlobalScale(float)` | `void` | Set accessibility UI scale (0.5-3.0) |
| `SetWindowIcon(string)` | `void` | Set window icon from image file |
| `GetOrLoadTexture(AbsoluteFilePath)` | `ImGuiAppTextureInfo` | Load or retrieve cached GPU texture |
| `DeleteTexture(uint)` | `void` | Remove texture from GPU |
| `EmsToPx(float)` | `int` | Convert EMs to pixels |
| `PtsToPx(int)` | `int` | Convert points to pixels |
#### Properties
| Name | Type | Description |
| ---- | ---- | ----------- |
| `IsFocused` | `bool` | Whether the window has focus |
| `IsVisible` | `bool` | Whether the window is visible |
| `IsIdle` | `bool` | Whether the app is idle |
| `IsOverlayActive` | `bool` | Whether the window is in overlay mode |
| `ScaleFactor` | `float` | DPI-based scale factor |
| `GlobalScale` | `float` | User-adjustable UI scale |
| `Invoker` | `Invoker` | Delegate invocation for window thread |
### `ImGuiAppConfig`
Configuration for `ImGuiApp.Start()`.
#### Configuration Properties
| Name | Type | Description |
| ---- | ---- | ----------- |
| `Title` | `string` | Window title (default: "ImGuiApp") |
| `IconPath` | `string` | Path to window icon |
| `OnStart` | `Action` | Initialization callback |
| `OnUpdate` | `Action` | Per-frame update callback |
| `OnRender` | `Action` | Per-frame render callback |
| `OnAppMenu` | `Action` | Menu bar rendering callback |
| `OnMoveOrResize` | `Action` | Window moved/resized callback |
| `OnGlobalScaleChanged` | `Action` | Scale changed callback |
| `Fonts` | `Dictionary` | Custom fonts to load |
| `EnableUnicodeSupport` | `bool` | Include extended Unicode ranges (default: true) |
| `PerformanceSettings` | `ImGuiAppPerformanceSettings` | Throttling configuration |
| `FontMemoryConfig` | `FontMemoryGuard.FontMemoryConfig` | Font memory limits |
| `InitialWindowState` | `ImGuiAppWindowState` | Initial window size/position |
### `ImGuiAppPerformanceSettings`
Frame rate throttling configuration.
| Name | Type | Description |
| ---- | ---- | ----------- |
| `EnableThrottledRendering` | `bool` | Enable adaptive frame limiting (default: true) |
| `FocusedFps` | `double` | Target FPS when focused (default: 30) |
| `UnfocusedFps` | `double` | Target FPS when unfocused (default: 5) |
| `IdleFps` | `double` | Target FPS when idle (default: 10) |
| `NotVisibleFps` | `double` | Target FPS when minimized (default: 2) |
| `OverlayFps` | `double` | Target FPS in overlay mode, bypassing focus/idle/visibility throttling (default: 30) |
| `IdleTimeoutSeconds` | `double` | Seconds before idle state (default: 30) |
### `ImGuiWidgets` (Static)
Custom UI components.
| Name | Return Type | Description |
| ---- | ----------- | ----------- |
| `SearchBox(...)` | `bool` | Search box with Glob/Regex/Fuzzy filtering |
| `SearchBox(...)` | `IEnumerable` | Filtered item selection |
| `SearchBoxRanked(...)` | `IEnumerable` | Fuzzy-ranked item selection |
| `Knob(...)` | `bool` | Rotary knob control (float or int) |
| `RadialProgressBar(...)` | `void` | Radial progress indicator |
| `RadialCountdown(...)` | `void` | Countdown timer display |
| `RadialCountUp(...)` | `void` | Count-up timer display |
| `Combo(...)` | `bool` | Enum selection combo |
| `Combo(...)` | `bool` | String selection combo |
| `Icon(...)` | `bool` | Icon with label and events |
| `Image(...)` | `bool` | Clickable image display |
| `ColorIndicator(...)` | `void` | Colored square indicator |
| `RowMajorGrid(...)` | `void` | Row-major grid layout |
| `ColumnMajorGrid(...)` | `void` | Column-major grid layout |
### Widget Instance Classes
| Class | Description |
| ----- | ----------- |
| `TabPanel` | Tabbed interface with closable, reorderable tabs |
| `DividerContainer` | Resizable split pane layout (columns or rows) |
| `ScopedDisable` | RAII wrapper to disable UI elements |
| `ScopedId` | RAII wrapper to push ImGui IDs |
| `Tree` | Tree view with nested children |
### `ImGuiPopups` Classes
| Class | Description |
| ----- | ----------- |
| `Modal` | Generic modal dialog |
| `MessageOK` | Simple message with OK button |
| `Prompt` | Multi-button prompt dialog |
| `InputString` | String input with confirmation |
| `InputInt` | Integer input with confirmation |
| `InputFloat` | Float input with confirmation |
| `FilesystemBrowser` | File/directory browser with glob filtering |
| `SearchableList` | Searchable item selection list |
### `Theme` (Static)
Theme management from ImGui.Styler.
| Name | Return Type | Description |
| ---- | ----------- | ----------- |
| `Apply(string)` | `bool` | Apply a named theme |
| `Apply(ISemanticTheme)` | `void` | Apply a theme instance |
| `ResetToDefault()` | `void` | Reset to default ImGui theme |
| `ShowThemeSelector(...)` | `void` | Show interactive theme browser |
| `RenderMenu(...)` | `bool` | Render theme selection menu |
| `FindTheme(string)` | `ThemeInfo?` | Look up theme by name |
| `AllThemes` | `IReadOnlyList` | All available themes |
| `DarkThemes` | `IReadOnlyList` | Dark themes only |
| `LightThemes` | `IReadOnlyList` | Light themes only |
| `Families` | `IReadOnlyList` | Theme family names |
### Styling Utilities
| Class | Description |
| ----- | ----------- |
| `ScopedColor` | RAII scoped ImGui color override |
| `ScopedTextColor` | RAII scoped text color |
| `ScopedStyleVar` | RAII scoped style variable |
| `ScopedThemeColor` | RAII scoped theme-aware color |
| `ScopedTheme` | RAII scoped full theme |
| `FontAppearance` | RAII scoped font styling |
| `UIScaler` | RAII scoped UI scaling |
| `Alignment.Center` | RAII scoped content centering |
| `Button.Alignment` | RAII scoped button text alignment |
| `Text.Color` | Semantic text colors (Error, Warning, Info, Success) |
| `Indent` | Scoped indentation utilities |
| `Color` | Color creation (Hex, RGB, HSL) with palettes |
### Color Extensions (on `ImColor`)
| Name | Description |
| ---- | ----------- |
| `DesaturateBy(float)` | Reduce saturation |
| `SaturateBy(float)` | Increase saturation |
| `LightenBy(float)` | Increase luminance |
| `DarkenBy(float)` | Decrease luminance |
| `WithAlpha(float)` | Set alpha channel |
| `ToGrayscale()` | Convert to grayscale |
| `CalculateOptimalContrastingColor()` | Get best contrast text color |
| `GetContrastRatioOver(ImColor)` | WCAG contrast ratio |
### `NodeEditorEngine`
Core node graph business logic.
| Name | Return Type | Description |
| ---- | ----------- | ----------- |
| `CreateNode(...)` | `Node` | Create a node with pins |
| `RemoveNode(int)` | `bool` | Remove a node |
| `TryCreateLink(int, int)` | `LinkCreationResult` | Create a link between pins |
| `RemoveLink(int)` | `bool` | Remove a link |
| `UpdatePhysics(float)` | `void` | Run physics simulation step |
| `Clear()` | `void` | Remove all nodes and links |
| `Nodes` | `IReadOnlyList` | All nodes |
| `Links` | `IReadOnlyList` | All links |
| `IsStable` | `bool` | Whether physics is stable |
### Node Graph Attributes
| Attribute | Target | Description |
| --------- | ------ | ----------- |
| `[Node]` | Class/Struct/Method | Marks type as a node |
| `[NodeBehavior]` | Class/Struct | Specifies execution mode |
| `[NodeExecute]` | Method | Marks execution method |
| `[InputPin]` | Property/Field/Parameter | Declares an input pin |
| `[OutputPin]` | Property/Field/Method | Declares an output pin |
| `[ExecutionInput]` | Property/Field | Declares execution input flow |
| `[ExecutionOutput]` | Property/Field | Declares execution output flow |
| `[NodeDeprecated]` | Class/Struct | Marks node as deprecated |
| `[NodeVisibility]` | Class/Struct | Controls menu visibility |
| `[WildcardPin]` | Property/Field | Accepts wildcard connections |
## Demo Applications
The repository includes demo applications showcasing all features:
```bash
# Run the main demo
dotnet run --project examples/ImGuiAppDemo
# Run individual library demos
dotnet run --project examples/ImGuiWidgetsDemo
dotnet run --project examples/ImGuiPopupsDemo
dotnet run --project examples/ImGuiStylerDemo
```
## Contributing
Contributions are welcome! Feel free to open issues or submit pull requests.
## License
This project is licensed under the MIT License. See the [LICENSE.md](LICENSE.md) file for details.