ImTui

人気のDear ImGuiライブラリをベースにした即時モードTUIライブラリ。デバッグインターフェースやリアルタイムモニタリングツールに最適。

TUITerminalC++ImGuiImmediate-Mode

GitHub概要

ggerganov/imtui

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

スター3,332
ウォッチ46
フォーク141
作成日:2019年12月8日
言語:C++
ライセンス:MIT License

トピックス

texttuiuiuser-interface

スター履歴

ggerganov/imtui Star History
データ取得日時: 2025/7/25 11:08

ImTui

ImTuiは、人気のDear ImGuiライブラリをターミナル環境に移植した即時モードTUIライブラリです。ImGuiのシンプルで直感的なAPIを維持しながら、ターミナルアプリケーション開発を可能にします。

特徴

即時モードGUI

  • 即時モード: 状態管理が不要で、毎フレーム描画するシンプルなアプローチ
  • ImGui互換: Dear ImGuiのAPIに基づいた使い慣れたインターフェース
  • 軽量: ヘッダーオンリーライブラリで簡単統合

豊富なウィジェット

  • 基本ウィジェット: ボタン、テキスト入力、スライダー、チェックボックス
  • レイアウト: 行、列、ウィンドウ、メニューバー
  • データ表示: テーブル、リスト、ツリー
  • プロット: グラフ、チャート表示機能

インストール

vcpkg経由

vcpkg install imtui

CMake手動ビルド

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

基本的な使用方法

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;
}

システム監視ツール

#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) {
            // シミュレートしたCPU使用率
            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使用率
            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();
            
            // メモリ使用率
            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();
            
            // システム情報
            ImTui::Text("Uptime: 2 days, 4 hours");
            ImTui::Text("Load Average: 0.45, 0.38, 0.32");
            
            if (ImTui::Button("Refresh")) {
                // リフレッシュ処理
            }
            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();
        
        // メインメニュー
        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;
}

デバッグ・診断ツール

#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")) {
            // 変数ウォッチ
            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())) {
                        // 編集ダイアログを開く
                    }
                }
            }
            
            ImTui::Separator();
            
            // ログビューア
            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();
            
            // コマンド入力
            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)");
        }
    }
};

エコシステム

バックエンド

  • ncurses: Unix/Linux環境での標準バックエンド
  • Windows Console: Windows環境サポート
  • SDL: 将来的なGUIサポートの可能性

関連プロジェクト

  • Dear ImGui: オリジナルのImGuiライブラリ
  • ImPlot: プロット機能の拡張
  • ImGuiColorTextEdit: テキストエディタ機能

利点

  • 学習コストが低い: ImGuiユーザーには馴染みのあるAPI
  • 即時モード: 複雑な状態管理が不要
  • デバッグに最適: リアルタイムパラメータ調整に優れている
  • 軽量: 最小限の依存関係
  • クロスプラットフォーム: Windows、Linux、macOSサポート

制約事項

  • 限定的なウィジェット: ncursesの制約により一部機能が制限
  • パフォーマンス: 毎フレーム描画のためCPU使用率が高い
  • カスタマイズ: テーマやスタイルのカスタマイズが限定的
  • 複雑なレイアウト: 高度なレイアウト機能は限定的

他のライブラリとの比較

項目ImTuiFTXUIncurses
パラダイム即時モード宣言的手続き的
学習コスト低(ImGui経験者)
デバッグ用途★★★★★★★★☆☆★★☆☆☆
パフォーマンス★★☆☆☆★★★★☆★★★★★
カスタマイズ性★★☆☆☆★★★★☆★★★★★

まとめ

ImTuiは、Dear ImGuiの使いやすさをターミナル環境に持ち込んだ革新的なライブラリです。特にデバッグツール、プロトタイピング、リアルタイムモニタリングアプリケーションの開発に優れており、即時モードGUIの利点を活かした迅速な開発が可能です。ImGuiの経験があれば、すぐに生産性の高いTUIアプリケーション開発を始められます。