ImTui

An immediate mode TUI library based on the popular Dear ImGui. Ideal for debug interfaces and real-time monitoring tools.

TUITerminalC++ImGuiImmediate-Mode

GitHub Overview

ggerganov/imtui

ImTui: Immediate Mode Text-based User Interface C++ Library

Stars3,332
Watchers46
Forks141
Created:December 8, 2019
Language:C++
License:MIT License

Topics

texttuiuiuser-interface

Star History

ggerganov/imtui Star History
Data as of: 7/25/2025, 11:08 AM

ImTui

ImTui is an immediate mode TUI library that ports the popular Dear ImGui library to terminal environments. It maintains ImGui's simple and intuitive API while enabling terminal application development.

Features

Immediate Mode GUI

  • Immediate Mode: Simple approach requiring no state management, drawing every frame
  • ImGui Compatible: Familiar interface based on Dear ImGui's API
  • Lightweight: Header-only library for easy integration

Rich Widgets

  • Basic Widgets: Buttons, text input, sliders, checkboxes
  • Layout: Rows, columns, windows, menu bars
  • Data Display: Tables, lists, trees
  • Plotting: Graph and chart display functionality

Installation

Via vcpkg

vcpkg install imtui

Manual CMake Build

git clone https://github.com/ggerganov/imtui
cd imtui
mkdir build && cd build
cmake ..
make -j4

Basic Usage

Hello World

#include "imtui/imtui.h"
#include "imtui/imtui-impl-ncurses.h"

int main() {
    IMTUI_CHECKVERSION();
    ImTui::CreateContext();
    
    auto screen = ImTui_ImplNcurses_Init(true);
    ImTui_ImplText_Init();
    
    bool demo_open = true;
    
    while (demo_open) {
        ImTui_ImplNcurses_NewFrame();
        ImTui_ImplText_NewFrame();
        ImTui::NewFrame();
        
        ImTui::SetNextWindowPos(ImVec2(4, 2), ImGuiCond_Once);
        ImTui::SetNextWindowSize(ImVec2(50, 10), ImGuiCond_Once);
        
        if (ImTui::Begin("Hello ImTui!")) {
            ImTui::Text("Hello, Terminal UI!");
            
            static float value = 0.5f;
            ImTui::SliderFloat("Value", &value, 0.0f, 1.0f);
            
            if (ImTui::Button("Exit")) {
                demo_open = false;
            }
        }
        ImTui::End();
        
        ImTui::Render();
        ImTui_ImplText_RenderDrawData(ImTui::GetDrawData(), screen);
        ImTui_ImplNcurses_DrawScreen();
    }
    
    ImTui_ImplText_Shutdown();
    ImTui_ImplNcurses_Shutdown();
    ImTui::DestroyContext();
    
    return 0;
}

System Monitor Tool

#include "imtui/imtui.h"
#include "imtui/imtui-impl-ncurses.h"
#include <vector>
#include <cmath>
#include <chrono>

class SystemMonitor {
private:
    std::vector<float> cpu_history;
    std::vector<float> memory_history;
    std::chrono::steady_clock::time_point last_update;
    
public:
    SystemMonitor() : last_update(std::chrono::steady_clock::now()) {
        cpu_history.reserve(100);
        memory_history.reserve(100);
    }
    
    void update() {
        auto now = std::chrono::steady_clock::now();
        if (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_update).count() > 100) {
            // Simulated CPU usage
            float cpu_usage = 30.0f + 20.0f * sin(cpu_history.size() * 0.1f);
            float memory_usage = 60.0f + 15.0f * cos(memory_history.size() * 0.05f);
            
            if (cpu_history.size() >= 100) cpu_history.erase(cpu_history.begin());
            if (memory_history.size() >= 100) memory_history.erase(memory_history.begin());
            
            cpu_history.push_back(cpu_usage);
            memory_history.push_back(memory_usage);
            
            last_update = now;
        }
    }
    
    void render() {
        ImTui::SetNextWindowPos(ImVec2(2, 1), ImGuiCond_Once);
        ImTui::SetNextWindowSize(ImVec2(76, 20), ImGuiCond_Once);
        
        if (ImTui::Begin("System Monitor")) {
            // CPU usage
            if (!cpu_history.empty()) {
                ImTui::Text("CPU Usage: %.1f%%", cpu_history.back());
                ImTui::PlotLines("##cpu", cpu_history.data(), cpu_history.size(), 
                               0, nullptr, 0.0f, 100.0f, ImVec2(0, 40));
            }
            
            ImTui::Separator();
            
            // Memory usage
            if (!memory_history.empty()) {
                ImTui::Text("Memory Usage: %.1f%%", memory_history.back());
                ImTui::PlotLines("##memory", memory_history.data(), memory_history.size(),
                               0, nullptr, 0.0f, 100.0f, ImVec2(0, 40));
            }
            
            ImTui::Separator();
            
            // System information
            ImTui::Text("Uptime: 2 days, 4 hours");
            ImTui::Text("Load Average: 0.45, 0.38, 0.32");
            
            if (ImTui::Button("Refresh")) {
                // Refresh logic
            }
            ImTui::SameLine();
            if (ImTui::Button("Clear History")) {
                cpu_history.clear();
                memory_history.clear();
            }
        }
        ImTui::End();
    }
};

int main() {
    IMTUI_CHECKVERSION();
    ImTui::CreateContext();
    
    auto screen = ImTui_ImplNcurses_Init(true);
    ImTui_ImplText_Init();
    
    SystemMonitor monitor;
    bool running = true;
    
    while (running) {
        ImTui_ImplNcurses_NewFrame();
        ImTui_ImplText_NewFrame();
        ImTui::NewFrame();
        
        monitor.update();
        monitor.render();
        
        // Main menu
        if (ImTui::BeginMainMenuBar()) {
            if (ImTui::BeginMenu("File")) {
                if (ImTui::MenuItem("Exit", "Ctrl+Q")) {
                    running = false;
                }
                ImTui::EndMenu();
            }
            ImTui::EndMainMenuBar();
        }
        
        ImTui::Render();
        ImTui_ImplText_RenderDrawData(ImTui::GetDrawData(), screen);
        ImTui_ImplNcurses_DrawScreen();
    }
    
    ImTui_ImplText_Shutdown();
    ImTui_ImplNcurses_Shutdown();
    ImTui::DestroyContext();
    
    return 0;
}

Debug & Diagnostic Tool

#include "imtui/imtui.h"
#include "imtui/imtui-impl-ncurses.h"
#include <map>
#include <string>
#include <sstream>

class DebugConsole {
private:
    std::vector<std::string> log_messages;
    std::map<std::string, float> variables;
    char input_buffer[256] = "";
    
public:
    DebugConsole() {
        variables["frame_time"] = 16.67f;
        variables["fps"] = 60.0f;
        variables["memory_mb"] = 256.0f;
        
        log("Debug console initialized");
    }
    
    void log(const std::string& message) {
        log_messages.push_back(message);
        if (log_messages.size() > 1000) {
            log_messages.erase(log_messages.begin());
        }
    }
    
    void set_variable(const std::string& name, float value) {
        variables[name] = value;
        log("Variable '" + name + "' set to " + std::to_string(value));
    }
    
    void render() {
        ImTui::SetNextWindowPos(ImVec2(1, 1), ImGuiCond_Once);
        ImTui::SetNextWindowSize(ImVec2(78, 22), ImGuiCond_Once);
        
        if (ImTui::Begin("Debug Console")) {
            // Variable watch
            if (ImTui::CollapsingHeader("Variables", ImGuiTreeNodeFlags_DefaultOpen)) {
                for (auto& [name, value] : variables) {
                    ImTui::Text("%-20s: %.3f", name.c_str(), value);
                    ImTui::SameLine();
                    if (ImTui::SmallButton(("Edit##" + name).c_str())) {
                        // Open edit dialog
                    }
                }
            }
            
            ImTui::Separator();
            
            // Log viewer
            if (ImTui::CollapsingHeader("Log", ImGuiTreeNodeFlags_DefaultOpen)) {
                ImTui::BeginChild("LogScrolling", ImVec2(0, 120), false, ImGuiWindowFlags_HorizontalScrollbar);
                for (const auto& message : log_messages) {
                    ImTui::Text("%s", message.c_str());
                }
                if (ImTui::GetScrollY() >= ImTui::GetScrollMaxY()) {
                    ImTui::SetScrollHereY(1.0f);
                }
                ImTui::EndChild();
            }
            
            ImTui::Separator();
            
            // Command input
            ImTui::Text("Command:");
            ImTui::SameLine();
            if (ImTui::InputText("##command", input_buffer, sizeof(input_buffer), 
                               ImGuiInputTextFlags_EnterReturnsTrue)) {
                process_command(input_buffer);
                input_buffer[0] = '\0';
                ImTui::SetKeyboardFocusHere(-1);
            }
            
            ImTui::SameLine();
            if (ImTui::Button("Execute")) {
                process_command(input_buffer);
                input_buffer[0] = '\0';
            }
            
            ImTui::SameLine();
            if (ImTui::Button("Clear Log")) {
                log_messages.clear();
            }
        }
        ImTui::End();
    }
    
private:
    void process_command(const std::string& command) {
        log("> " + command);
        
        std::istringstream iss(command);
        std::string cmd;
        iss >> cmd;
        
        if (cmd == "set") {
            std::string var_name;
            float value;
            if (iss >> var_name >> value) {
                set_variable(var_name, value);
            } else {
                log("Usage: set <variable> <value>");
            }
        } else if (cmd == "get") {
            std::string var_name;
            if (iss >> var_name) {
                auto it = variables.find(var_name);
                if (it != variables.end()) {
                    log(var_name + " = " + std::to_string(it->second));
                } else {
                    log("Variable '" + var_name + "' not found");
                }
            } else {
                log("Usage: get <variable>");
            }
        } else if (cmd == "help") {
            log("Available commands:");
            log("  set <var> <value> - Set variable value");
            log("  get <var>         - Get variable value");
            log("  help              - Show this help");
            log("  clear             - Clear log");
        } else if (cmd == "clear") {
            log_messages.clear();
        } else if (!cmd.empty()) {
            log("Unknown command: " + cmd + " (type 'help' for commands)");
        }
    }
};

Ecosystem

Backends

  • ncurses: Standard backend for Unix/Linux environments
  • Windows Console: Windows environment support
  • SDL: Potential future GUI support

Related Projects

  • Dear ImGui: Original ImGui library
  • ImPlot: Plotting functionality extension
  • ImGuiColorTextEdit: Text editor functionality

Advantages

  • Low learning curve: Familiar API for ImGui users
  • Immediate mode: No complex state management required
  • Ideal for debugging: Excellent for real-time parameter adjustment
  • Lightweight: Minimal dependencies
  • Cross-platform: Windows, Linux, macOS support

Limitations

  • Limited widgets: Some functionality restricted by ncurses constraints
  • Performance: Higher CPU usage due to per-frame rendering
  • Customization: Limited theme and style customization
  • Complex layouts: Advanced layout features are limited

Comparison with Other Libraries

FeatureImTuiFTXUIncurses
ParadigmImmediate ModeDeclarativeProcedural
Learning CurveLow (ImGui experience)MediumHigh
Debug Use★★★★★★★★☆☆★★☆☆☆
Performance★★☆☆☆★★★★☆★★★★★
Customizability★★☆☆☆★★★★☆★★★★★

Summary

ImTui is an innovative library that brings Dear ImGui's ease of use to terminal environments. It excels particularly in debug tools, prototyping, and real-time monitoring application development, enabling rapid development that leverages the benefits of immediate mode GUI. With ImGui experience, you can immediately start productive TUI application development.