Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 42 additions & 21 deletions cli/src/main/java/com/botwithus/bot/cli/gui/ImGuiApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
import com.botwithus.bot.cli.stream.StreamManager;
import com.botwithus.bot.core.config.ScriptProfileStore;

import imgui.ImFontAtlas;
import imgui.ImFontConfig;
import imgui.ImGui;
import imgui.ImGuiIO;
import imgui.app.Application;
import imgui.app.Configuration;
import imgui.flag.ImGuiConfigFlags;
Expand Down Expand Up @@ -68,8 +68,8 @@ public class ImGuiApp extends Application {
private boolean editorMode = false;
private BlueprintEditor blueprintEditor;

// Script config panel (floating window)
private ScriptConfigPanel configPanel;
// Script custom UI window (floating window)
private ScriptUIWindow scriptUIWindow;

// GLFW window handle for title updates
private long glfwWindow;
Expand All @@ -94,18 +94,24 @@ protected void initImGui(Configuration config) {
}
float dpiScale = Math.max(xScale[0], 1.0f);

// Rebuild font atlas at scaled pixel size so text is crisp on HiDPI.
ImGuiIO io = ImGui.getIO();
io.getFonts().clear();
ImFontConfig fontConfig = new ImFontConfig();
fontConfig.setSizePixels(14f * dpiScale);
fontConfig.setOversampleH(2);
fontConfig.setOversampleV(2);
io.getFonts().addFontDefault(fontConfig);
io.getFonts().build();
fontConfig.destroy();
float uiSize = (float) Math.round(19f * dpiScale);
ImFontAtlas atlas = ImGui.getIO().getFonts();
atlas.clear();
byte[] ttf = loadSystemFont("segoeui.ttf", "arial.ttf", "verdana.ttf");
ImFontConfig cfg = new ImFontConfig();
cfg.setOversampleH(3);
cfg.setOversampleV(3);
cfg.setPixelSnapH(true);
if (ttf != null) {
atlas.addFontFromMemoryTTF(ttf, uiSize, cfg);
} else {
cfg.setSizePixels(uiSize);
atlas.addFontDefault(cfg);
}
cfg.destroy();
atlas.build();

io.addConfigFlags(ImGuiConfigFlags.ViewportsEnable);
ImGui.getIO().addConfigFlags(ImGuiConfigFlags.ViewportsEnable);

ImGuiTheme.apply(dpiScale);

Expand Down Expand Up @@ -190,9 +196,9 @@ public void completeWithError(Object handle, String message) {
// Initialize blueprint editor
blueprintEditor = new BlueprintEditor();

// Initialize config panel and wire opener
configPanel = new ScriptConfigPanel();
ctx.setConfigPanelOpener(runner -> configPanel.open(runner));
// Initialize script UI window and wire opener
scriptUIWindow = new ScriptUIWindow();
ctx.setConfigPanelOpener(runner -> scriptUIWindow.open(runner));

// Initialize panels
panels.add(new ConsolePanel(outputBuffer, registry, executor, this::shutdown));
Expand All @@ -205,8 +211,10 @@ public void completeWithError(Object handle, String message) {

statusBar = new StatusBar();

// Grab GLFW window handle for title updates
glfwWindow = GLFW.glfwGetCurrentContext();

var oldSizeCb = GLFW.glfwSetWindowSizeCallback(glfwWindow, null);
if (oldSizeCb != null) oldSizeCb.free();
}

@Override
Expand Down Expand Up @@ -270,15 +278,28 @@ public void process() {

ImGui.end();

// Render config panel as floating window (outside the main window)
if (configPanel != null && configPanel.isOpen()) {
configPanel.render();
// Render script custom UI as a floating window (outside the main window)
if (scriptUIWindow != null && scriptUIWindow.isOpen()) {
scriptUIWindow.render();
}

// Update window title based on connection state
updateTitle();
}

private static byte[] loadSystemFont(String... candidates) {
String windir = System.getenv("WINDIR");
if (windir == null) windir = "C:\\Windows";
java.nio.file.Path fontsDir = java.nio.file.Paths.get(windir, "Fonts");
for (String name : candidates) {
java.nio.file.Path p = fontsDir.resolve(name);
if (java.nio.file.Files.exists(p)) {
try { return java.nio.file.Files.readAllBytes(p); } catch (Exception ignored) {}
}
}
return null;
}

private void updateTitle() {
if (glfwWindow == 0) return;
boolean connected = ctx.hasActiveConnection();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ public boolean isOpen() {
return open.get();
}

public void close() {
open.set(false);
}

/** Call from the main ImGui render loop. */
public void render() {
if (!open.get() || runner == null || fields == null || fields.isEmpty()) return;
Expand Down
44 changes: 44 additions & 0 deletions cli/src/main/java/com/botwithus/bot/cli/gui/ScriptUIWindow.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.botwithus.bot.cli.gui;

import com.botwithus.bot.api.ui.ScriptUI;
import com.botwithus.bot.core.runtime.ScriptRunner;

import imgui.ImGui;
import imgui.flag.ImGuiCond;
import imgui.flag.ImGuiWindowFlags;
import imgui.type.ImBoolean;

public class ScriptUIWindow {

private ScriptRunner runner;
private final ImBoolean open = new ImBoolean(false);

public void open(ScriptRunner runner) {
this.runner = runner;
open.set(true);
ImGui.setNextWindowSize(925, 690, ImGuiCond.FirstUseEver);
}

public boolean isOpen() {
return open.get();
}

public void render() {
if (!open.get() || runner == null) return;

ScriptUI ui = runner.getScript().getUI();
if (ui == null) { open.set(false); return; }

ImGui.setNextWindowSize(925, 690, ImGuiCond.FirstUseEver);
if (ImGui.begin(runner.getScriptName() + " Config###scriptUIWindow", open,
ImGuiWindowFlags.NoCollapse)) {
try {
ui.render();
} catch (Exception e) {
ImGui.textColored(ImGuiTheme.RED_R, ImGuiTheme.RED_G, ImGuiTheme.RED_B, 1f,
"UI error: " + e.getMessage());
}
}
ImGui.end();
}
}
5 changes: 3 additions & 2 deletions cli/src/main/java/com/botwithus/bot/cli/gui/ScriptsPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,10 @@ public void render(CliContext ctx) {
}
}

// Config button
// Config button — show for ConfigField-based or custom ImGui UI scripts
var configFields = runner.getConfigFields();
if (configFields != null && !configFields.isEmpty()) {
boolean hasConfig = (configFields != null && !configFields.isEmpty()) || runner.getScript().getUI() != null;
if (hasConfig) {
ImGui.sameLine();
if (ImGui.smallButton("Config")) {
ctx.openConfigPanel(runner);
Expand Down