Files
2026-07-13 13:15:05 +08:00

159 lines
5.5 KiB
C#

using System.Drawing;
using System.Numerics;
using System.Runtime.CompilerServices;
using ImGuiNET;
using SilkWindows;
namespace SilkWindows;
internal sealed class ImGuiHandler
{
private readonly IImguiDrawer _drawer;
private readonly string _windowTitle;
private readonly IntPtr? _originalContext;
private readonly object _contextLock;
private readonly FontPack? _fontPack;
private readonly string _mainWindowId;
private readonly string _childWindowId;
private ImFonts? _fontObj;
private readonly IntPtr _context;
private readonly int _myWindowId;
private static int _incrementingWindowId = 0;
public ImGuiHandler(IImguiImplementation impl, IImguiDrawer drawer, FontPack? fontPack, object? lockObj)
{
_windowTitle = impl.Title;
_mainWindowId = impl.MainWindowId;
_childWindowId = impl.ChildWindowId;
_drawer = drawer;
_fontPack = fontPack;
_contextLock = lockObj ?? new object();
_imguiController = impl;
_myWindowId = Interlocked.Increment(ref _incrementingWindowId);
lock (_contextLock)
{
var previousContext = ImGui.GetCurrentContext();
_originalContext = previousContext == IntPtr.Zero ? null : previousContext;
_context = impl.InitializeControllerContext(InitializeStyle);
_drawer.Init();
}
}
private unsafe void InitializeStyle()
{
if (_originalContext.HasValue)
{
var myContext = ImGui.GetCurrentContext();
// first we switch to the previous imgui context
ImGui.SetCurrentContext(_originalContext.Value);
// we copy the style from the previous context
ImGuiStyle copiedStyle = default;
Unsafe.Copy(destination: ref copiedStyle, source: ImGui.GetStyle().NativePtr);
// we switch back to our own context
ImGui.SetCurrentContext(myContext);
// we apply the copied style to the current context
Unsafe.Copy(ImGui.GetStyle().NativePtr, ref copiedStyle);
}
Vector4 colorVector = new Vector4(0, 1, 1, 1);// ImGui.GetStyle().Colors[(int)ImGuiCol.WindowBg];
var colorVecByteValue = colorVector * 255;
ClearColor = Color.FromArgb((int)colorVecByteValue.X, (int)colorVecByteValue.Y, (int)colorVecByteValue.Z);
// do we need or want to do this?
ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.ViewportsEnable;
if (!_fontPack.HasValue)
{
_fontObj = new ImFonts([]);
return;
}
var fontPack = _fontPack.Value;
var io = ImGui.GetIO();
var fontAtlasPtr = io.Fonts;
var fonts = new ImFontPtr[4];
fonts[0] = fontAtlasPtr.AddFontFromFileTTF(fontPack.Small.Path, fontPack.Small.PixelSize);
fonts[1] = fontAtlasPtr.AddFontFromFileTTF(fontPack.Regular.Path, fontPack.Regular.PixelSize);
fonts[2] = fontAtlasPtr.AddFontFromFileTTF(fontPack.Bold.Path, fontPack.Bold.PixelSize);
fonts[3] = fontAtlasPtr.AddFontFromFileTTF(fontPack.Large.Path, fontPack.Large.PixelSize);
if (!fontAtlasPtr.Build())
{
Console.WriteLine("Failed to build font atlas");
}
_fontObj = new ImFonts(fonts);
}
public void Draw(Vector2 windowSize, double deltaTime)
{
lock (_contextLock)
{
var contextToRestore = ImGui.GetCurrentContext();
if (contextToRestore == IntPtr.Zero || contextToRestore == _context)
{
contextToRestore = _originalContext ?? _context;
}
ImGui.SetCurrentContext(_context);
_imguiController.StartImguiFrame((float)deltaTime);
ImGui.PushID(_myWindowId);
ImGui.SetNextWindowSize(windowSize);
ImGui.SetNextWindowPos(new Vector2(0, 0));
const ImGuiWindowFlags windowFlags = ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize |
ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.AlwaysAutoResize;
ImGui.Begin(_mainWindowId, windowFlags);
ImGui.BeginChild(_childWindowId, Vector2.Zero, ImGuiChildFlags.None);
_drawer.OnRender(_windowTitle, deltaTime, _fontObj!);
ImGui.EndChild();
ImGui.End();
ImGui.PopID();
_imguiController.EndImguiFrame();
// restore
ImGui.SetCurrentContext(contextToRestore);
}
}
public void Dispose()
{
lock (_contextLock)
{
_drawer.OnClose();
_imguiController.Dispose();
}
}
private readonly IImguiImplementation _imguiController;
public Color? ClearColor { get; private set; }
// forwards window events
public void OnWindowUpdate(double deltaSeconds, out bool shouldCloseWindow)
{
_drawer.OnWindowUpdate(deltaSeconds, out shouldCloseWindow);
}
public void OnWindowFocusChanged(bool isFocused)
{
_drawer.OnWindowFocusChanged(isFocused);
}
public void OnFileDrop(string[] filePaths)
{
_drawer.OnFileDrop(filePaths);
}
}