mirror of
https://github.com/Ryubing/RyujinxHelper.git
synced 2025-05-12 18:20:36 +01:00
Themes are no longer passed by ref, and instead are passed by pointer.
Layers are now added AFTER UiManager is initialized and the instance is set. TryCreateUi no longer automatically starts the UI thread, for you to add layers & do any custom ImGui setup before starting the thread.
This commit is contained in:
parent
adc3dc0513
commit
7e3b65266d
13 changed files with 227 additions and 170 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,7 +1,7 @@
|
|||
.idea/
|
||||
.vs/
|
||||
src/Bot/bin
|
||||
src/Bot/obj
|
||||
src/Bot/bin/
|
||||
src/Bot/obj/
|
||||
src/Bot/Properties/
|
||||
src/UI/bin/
|
||||
src/UI/obj/
|
||||
|
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"FSharp.suggestGitignore": false
|
||||
"FSharp.suggestGitignore": false,
|
||||
"editor.fontFamily": "JetBrains Mono, monospace"
|
||||
}
|
|
@ -9,8 +9,13 @@ public sealed partial class BotOwnerModule
|
|||
public Task<ActionResult> UiAsync(
|
||||
[Description("Desired font size of the UI.")] int fontSize = 17)
|
||||
{
|
||||
return UiManager.TryCreateUi(VolteBot.GetUiParams(fontSize), out var err)
|
||||
? None(() => Context.Message.AddReactionAsync(Emojis.BallotBoxWithCheck))
|
||||
: BadRequest($"Could not create UI thread: {err?.Message}");
|
||||
var uiParams = VolteBot.GetUiParams(fontSize);
|
||||
if (!UiManager.TryCreateUi(uiParams, out var err))
|
||||
return BadRequest($"Could not create UI thread: {err?.Message}");
|
||||
|
||||
UiManager.AddView(new VolteUiView(Context.Services));
|
||||
UiManager.StartThread(uiParams.ThreadName);
|
||||
return None(() => Context.Message.AddReactionAsync(Emojis.BallotBoxWithCheck));
|
||||
|
||||
}
|
||||
}
|
|
@ -81,7 +81,7 @@ public class TagModule : VolteModule
|
|||
return Ok($"Successfully modified the content of tag **{tag.Name}**.");
|
||||
}
|
||||
|
||||
[Command("Delete", "Del", "Rem")]
|
||||
[Command("Delete", "Remove", "Del", "Rem")]
|
||||
[Description("Deletes a tag if it exists.")]
|
||||
[RequireGuildModerator]
|
||||
public async Task<ActionResult> TagDeleteAsync([Remainder, Description("The tag to delete.")]
|
||||
|
|
|
@ -26,7 +26,7 @@ public class WelcomeModule : VolteModule
|
|||
public Task<ActionResult> WelcomeMessageAsync([Remainder] string message = null)
|
||||
{
|
||||
if (message is null)
|
||||
return Ok($"The current welcome message for this guild is: {Format.Code(Context.GuildData.Configuration.Welcome.WelcomeMessage, string.Empty)}");
|
||||
return Ok($"The current welcome message for this guild is: {Format.Code(Context.GuildData.Configuration.Welcome.WelcomeMessage ?? "None", string.Empty)}");
|
||||
|
||||
Context.Modify(data => data.Configuration.Welcome.WelcomeMessage = message);
|
||||
var welcomeChannel = Context.Guild.GetTextChannel(Context.GuildData.Configuration.Welcome.WelcomeChannel);
|
||||
|
@ -59,7 +59,7 @@ public class WelcomeModule : VolteModule
|
|||
if (message is null)
|
||||
return Ok(new StringBuilder()
|
||||
.AppendLine(
|
||||
$"The current leaving message for this guild is: {Format.Code(Context.GuildData.Configuration.Welcome.LeavingMessage, string.Empty)}"));
|
||||
$"The current leaving message for this guild is: {Format.Code(Context.GuildData.Configuration.Welcome.LeavingMessage ?? "None", string.Empty)}"));
|
||||
|
||||
Context.GuildData.Configuration.Welcome.LeavingMessage = message;
|
||||
Db.Save(Context.GuildData);
|
||||
|
@ -86,7 +86,7 @@ public class WelcomeModule : VolteModule
|
|||
{
|
||||
if (message is null)
|
||||
return Ok(
|
||||
$"Unset the WelcomeDmMessage that was previously set to: {Format.Code(Context.GuildData.Configuration.Welcome.WelcomeDmMessage)}");
|
||||
$"Unset the WelcomeDmMessage that was previously set to: {Format.Code(Context.GuildData.Configuration.Welcome.WelcomeDmMessage ?? "None")}");
|
||||
|
||||
Context.GuildData.Configuration.Welcome.WelcomeDmMessage = message;
|
||||
Db.Save(Context.GuildData);
|
||||
|
|
|
@ -42,11 +42,8 @@ public class VolteBot
|
|||
|
||||
IsRunning = true;
|
||||
|
||||
if (Program.CommandLineArguments.TryGetValue("ui", out var sizeStr)
|
||||
&& !UiManager.TryCreateUi(GetUiParams(sizeStr.TryParse<int>(out var fsz) ? fsz : 17),
|
||||
out var uiStartError)
|
||||
) Error(LogSource.UI, $"Could not create UI: {uiStartError!.Message}");
|
||||
|
||||
if (Program.CommandLineArguments.TryGetValue("ui", out var sizeStr))
|
||||
CreateUi(sizeStr);
|
||||
|
||||
_client = ServiceProvider.Get<DiscordSocketClient>();
|
||||
_cts = ServiceProvider.Get<CancellationTokenSource>();
|
||||
|
@ -120,39 +117,51 @@ public class VolteBot
|
|||
videoMode: VideoMode.Default
|
||||
);
|
||||
|
||||
private static void CreateUi(string sizeStr)
|
||||
{
|
||||
var uiParams = GetUiParams(sizeStr.TryParse<int>(out var fsz) ? fsz : 17);
|
||||
|
||||
if (UiManager.TryCreateUi(uiParams,out var uiStartError))
|
||||
{
|
||||
UiManager.AddView(new VolteUiView(ServiceProvider));
|
||||
UiManager.StartThread(uiParams.ThreadName);
|
||||
}
|
||||
else Error(LogSource.UI, $"Could not create UI: {uiStartError!.Message}");
|
||||
}
|
||||
public static UiManager.CreateParams GetUiParams(int fontSize)
|
||||
{
|
||||
return new UiManager.CreateParams
|
||||
unsafe //Spectrum.Dark/Light are pointers
|
||||
{
|
||||
Font = getFont(),
|
||||
WindowIcon = getIcon(),
|
||||
WOptions = DefaultWindowOptions,
|
||||
Layers = [new VolteUiLayer(ServiceProvider)],
|
||||
ThreadName = "Volte UI Thread"
|
||||
};
|
||||
|
||||
ImGuiFontConfig getFont()
|
||||
{
|
||||
var ttf = FilePath.Data / "UiFont.ttf";
|
||||
if (!ttf.ExistsAsFile)
|
||||
return new UiManager.CreateParams
|
||||
{
|
||||
using var embeddedFont = Assembly.GetExecutingAssembly().GetManifestResourceStream("UIFont");
|
||||
if (embeddedFont != null)
|
||||
OnConfigureIO = io =>
|
||||
{
|
||||
using var fs = ttf.OpenCreate();
|
||||
embeddedFont.Seek(0, SeekOrigin.Begin);
|
||||
embeddedFont.CopyTo(fs);
|
||||
}
|
||||
}
|
||||
|
||||
return new ImGuiFontConfig(ttf.ToString(), fontSize);
|
||||
var ttf = FilePath.Data / "UiFont.ttf";
|
||||
if (!ttf.ExistsAsFile)
|
||||
{
|
||||
using var embeddedFont = Assembly.GetExecutingAssembly().GetManifestResourceStream("UIFont");
|
||||
if (embeddedFont != null)
|
||||
{
|
||||
using var fs = ttf.OpenCreate();
|
||||
embeddedFont.Seek(0, SeekOrigin.Begin);
|
||||
embeddedFont.CopyTo(fs);
|
||||
}
|
||||
}
|
||||
|
||||
io.Fonts.AddFontFromFileTTF(ttf.ToString(), fontSize);
|
||||
},
|
||||
WindowIcon = getIcon(),
|
||||
WOptions = DefaultWindowOptions,
|
||||
Theme = Spectrum.Dark,
|
||||
ThreadName = "Volte UI Thread"
|
||||
};
|
||||
}
|
||||
|
||||
Image<Rgba32> getIcon()
|
||||
{
|
||||
Stream iconStream;
|
||||
return (iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("VolteIcon")) == null
|
||||
? null
|
||||
return (iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("VolteIcon")) == null
|
||||
? null
|
||||
: Image.Load<Rgba32>(iconStream);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public static partial class Extensions
|
|||
LogLevel = Config.DebugEnabled || Version.IsDevelopment
|
||||
? LogSeverity.Debug
|
||||
: LogSeverity.Verbose,
|
||||
GatewayIntents = _intents,
|
||||
GatewayIntents = Intents,
|
||||
AlwaysDownloadUsers = true,
|
||||
ConnectionTimeout = 10000,
|
||||
MessageCacheSize = 50
|
||||
|
@ -48,7 +48,7 @@ public static partial class Extensions
|
|||
Info(LogSource.Volte, $"Injected {l.Count()} services into the provider.");
|
||||
});
|
||||
|
||||
private const GatewayIntents _intents
|
||||
private const GatewayIntents Intents
|
||||
= GatewayIntents.Guilds | GatewayIntents.GuildMessageReactions | GatewayIntents.GuildMembers |
|
||||
GatewayIntents.GuildMessages | GatewayIntents.GuildPresences | GatewayIntents.MessageContent;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ using Color = System.Drawing.Color;
|
|||
|
||||
namespace Volte.UI;
|
||||
|
||||
public partial class VolteUiLayer
|
||||
public partial class VolteUiView
|
||||
{
|
||||
private void CommandStats(double _)
|
||||
{
|
||||
|
@ -28,21 +28,22 @@ public partial class VolteUiLayer
|
|||
{
|
||||
//using var __ = PushStyle(ImGuiStyleVar.WindowMinSize, new Vector2(385, 299));
|
||||
ImGui.Text("Discord Gateway:");
|
||||
ImGui.SameLine();
|
||||
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
|
||||
// default is a meaningless case here i dont fucking care rider
|
||||
switch (_state.Client.ConnectionState)
|
||||
{
|
||||
case ConnectionState.Connected:
|
||||
ColoredText(" Connected", Color.LawnGreen);
|
||||
ColoredText("Connected", Color.LawnGreen);
|
||||
break;
|
||||
case ConnectionState.Connecting:
|
||||
ColoredText(" Connecting...", Color.Yellow);
|
||||
ColoredText("Connecting...", Color.Yellow);
|
||||
break;
|
||||
case ConnectionState.Disconnecting:
|
||||
ColoredText(" Disconnecting...", Color.OrangeRed);
|
||||
ColoredText("Disconnecting...", Color.OrangeRed);
|
||||
break;
|
||||
case ConnectionState.Disconnected:
|
||||
ColoredText(" Disconnected!", Color.Red);
|
||||
ColoredText("Disconnected!", Color.Red);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -92,9 +93,15 @@ public partial class VolteUiLayer
|
|||
ImGui.Text($"Owner: @{selectedGuild.Owner}");
|
||||
ImGui.Text($"Text Channels: {selectedGuild.TextChannels.Count}");
|
||||
ImGui.Text($"Voice Channels: {selectedGuild.VoiceChannels.Count}");
|
||||
ImGui.Text($"{selectedGuildMembers.Length} members");
|
||||
ColoredText($" + {selectedGuildMembers.Length - botMembers} users", Color.LawnGreen);
|
||||
ColoredText($" - {botMembers} bots", Color.OrangeRed);
|
||||
|
||||
ImGui.Text($"{selectedGuildMembers.Length} members |");
|
||||
ImGui.SameLine();
|
||||
ColoredText($"{selectedGuildMembers.Length - botMembers} users", Color.LawnGreen);
|
||||
ImGui.SameLine();
|
||||
ImGui.Text("|");
|
||||
ImGui.SameLine();
|
||||
ColoredText($"{botMembers} bots", Color.OrangeRed);
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
var destructiveMenuEnabled = AllKeysPressed(Key.ShiftLeft, Key.ControlLeft);
|
|
@ -25,11 +25,11 @@ public sealed class VolteUiState
|
|||
public ulong SelectedGuildId = 0;
|
||||
}
|
||||
|
||||
public partial class VolteUiLayer : UiLayer
|
||||
public partial class VolteUiView : UiView
|
||||
{
|
||||
private readonly VolteUiState _state;
|
||||
|
||||
public VolteUiLayer(IServiceProvider provider)
|
||||
public VolteUiView(IServiceProvider provider)
|
||||
{
|
||||
_state = new VolteUiState(provider);
|
||||
|
||||
|
@ -64,9 +64,7 @@ public partial class VolteUiLayer : UiLayer
|
|||
ImGui.MenuItem($"{Io.Framerate:###} FPS ({1000f / Io.Framerate:0.##} ms/frame)", false);
|
||||
|
||||
if (Config.DebugEnabled || Version.IsDevelopment)
|
||||
{
|
||||
ImGui.MenuItem($"Delta: {delta:0.00000}", false);
|
||||
}
|
||||
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
@ -76,9 +74,11 @@ public partial class VolteUiLayer : UiLayer
|
|||
if (ImGui.MenuItem(_state.SelectedTheme ? "Swap to Light" : "Swap to Dark"))
|
||||
{
|
||||
_state.SelectedTheme = !_state.SelectedTheme;
|
||||
if (_state.SelectedTheme)
|
||||
SetColors(ref Spectrum.Dark, true);
|
||||
else SetColors(ref Spectrum.Light, false);
|
||||
unsafe
|
||||
{
|
||||
UiManager.SetColors(_state.SelectedTheme ? Spectrum.Dark : Spectrum.Light);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ImGui.RadioButton("Show Style Editor", _state.ShowStyleEditor))
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Gommon;
|
||||
|
@ -14,7 +13,7 @@ using Silk.NET.Windowing;
|
|||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Advanced;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
using Color = Silk.NET.SDL.Color;
|
||||
|
||||
namespace Volte.UI;
|
||||
|
||||
|
@ -25,7 +24,7 @@ public sealed partial class UiManager : IDisposable
|
|||
private bool _isActive;
|
||||
|
||||
private readonly IWindow _window;
|
||||
private readonly ImGuiFontConfig? _fontConfig;
|
||||
private readonly Action<ImGuiIOPtr> _onConfigureIO;
|
||||
private Image<Rgba32>? _windowIcon;
|
||||
|
||||
private ImGuiController? _controller;
|
||||
|
@ -36,19 +35,24 @@ public sealed partial class UiManager : IDisposable
|
|||
{
|
||||
_gl = GL.GetApi(_window);
|
||||
_inputContext = _window.CreateInput();
|
||||
_controller = new ImGuiController(_gl, _window, _inputContext, _fontConfig, () =>
|
||||
_controller = new ImGuiController(_gl, _window, _inputContext, default, () =>
|
||||
{
|
||||
var io = ImGui.GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags.DockingEnable;
|
||||
io.ConfigDockingWithShift = false;
|
||||
|
||||
UiLayer.SetColors(ref Spectrum.Dark, true);
|
||||
unsafe
|
||||
{
|
||||
if (Theme != null)
|
||||
SetColors(Theme);
|
||||
}
|
||||
|
||||
var fonts = FilePath.Data.Resolve("fonts", true);
|
||||
if (fonts.ExistsAsDirectory)
|
||||
fonts.GetFiles()
|
||||
.Where(x => x.Extension is "ttf")
|
||||
.ForEach(fp => io.Fonts.AddFontFromFileTTF(fp.Path, 17));
|
||||
_onConfigureIO(io);
|
||||
|
||||
FilePath.Data.Resolve("fonts", true)
|
||||
.GetFiles()?
|
||||
.Where(x => x.Extension is "ttf")?
|
||||
.ForEach(fp => io.Fonts.AddFontFromFileTTF(fp.Path, 17));
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -77,4 +81,75 @@ public sealed partial class UiManager : IDisposable
|
|||
|
||||
_window.SetWindowIcon(ref rawIcon);
|
||||
}
|
||||
|
||||
public static unsafe void SetColors(ThemedColors* theme)
|
||||
{
|
||||
var style = ImGui.GetStyle();
|
||||
|
||||
style.GrabRounding = 4f;
|
||||
style.FrameRounding = 6f;
|
||||
style.WindowMenuButtonPosition = ImGuiDir.None;
|
||||
style.FrameBorderSize = 1f;
|
||||
style.TabBorderSize = 1f;
|
||||
style.WindowTitleAlign = new Vector2(0.5f);
|
||||
style.SeparatorTextBorderSize = 9f;
|
||||
|
||||
set(ImGuiCol.Text, theme->Gray800);
|
||||
set(ImGuiCol.TextDisabled, theme->Gray500);
|
||||
set(ImGuiCol.WindowBg, theme->Gray100);
|
||||
set(ImGuiCol.ChildBg, Spectrum.Static.None);
|
||||
set(ImGuiCol.PopupBg, theme->Gray50);
|
||||
set(ImGuiCol.Border, theme->Gray300);
|
||||
set(ImGuiCol.BorderShadow, Spectrum.Static.None);
|
||||
set(ImGuiCol.FrameBg, theme->Gray75);
|
||||
set(ImGuiCol.FrameBgHovered, theme->Gray50);
|
||||
set(ImGuiCol.FrameBgActive, theme->Gray200);
|
||||
set(ImGuiCol.TitleBg, theme->Gray300);
|
||||
set(ImGuiCol.TitleBgActive, theme->Gray200);
|
||||
set(ImGuiCol.TitleBgCollapsed, theme->Gray400);
|
||||
set(ImGuiCol.TabUnfocusedActive, theme->Blue400);
|
||||
set(ImGuiCol.MenuBarBg, theme->Gray100);
|
||||
set(ImGuiCol.ScrollbarBg, theme->Gray100);
|
||||
set(ImGuiCol.ScrollbarGrab, theme->Gray400);
|
||||
set(ImGuiCol.ScrollbarGrabHovered, theme->Gray600);
|
||||
set(ImGuiCol.ScrollbarGrabActive, theme->Gray700);
|
||||
set(ImGuiCol.CheckMark, theme->Blue500);
|
||||
set(ImGuiCol.SliderGrab, theme->Gray700);
|
||||
set(ImGuiCol.SliderGrabActive, theme->Gray800);
|
||||
set(ImGuiCol.Button, theme->Gray75);
|
||||
set(ImGuiCol.ButtonHovered, theme->Gray50);
|
||||
set(ImGuiCol.ButtonActive, theme->Gray200);
|
||||
set(ImGuiCol.Header, theme->Blue400);
|
||||
set(ImGuiCol.HeaderHovered, theme->Blue500);
|
||||
set(ImGuiCol.HeaderActive, theme->Blue600);
|
||||
set(ImGuiCol.Separator, theme->Gray400);
|
||||
set(ImGuiCol.SeparatorHovered, theme->Gray600);
|
||||
set(ImGuiCol.SeparatorActive, theme->Gray700);
|
||||
set(ImGuiCol.ResizeGrip, theme->Gray400);
|
||||
set(ImGuiCol.ResizeGripHovered, theme->Gray600);
|
||||
set(ImGuiCol.ResizeGripActive, theme->Gray700);
|
||||
set(ImGuiCol.PlotLines, theme->Blue400);
|
||||
set(ImGuiCol.PlotLinesHovered, theme->Blue600);
|
||||
set(ImGuiCol.PlotHistogram, theme->Blue400);
|
||||
set(ImGuiCol.PlotHistogramHovered, theme->Blue600);
|
||||
|
||||
setVec(ImGuiCol.TextSelectedBg, ImGui.ColorConvertU32ToFloat4((colorValue(theme->Blue400) & 0x00FFFFFF) | 0x33000000));
|
||||
setVec(ImGuiCol.DragDropTarget, new Vector4(1.00f, 1.00f, 0.00f, 0.90f));
|
||||
setVec(ImGuiCol.NavHighlight, ImGui.ColorConvertU32ToFloat4((colorValue(theme->Gray900) & 0x00FFFFFF) | 0x0A000000));
|
||||
setVec(ImGuiCol.NavWindowingHighlight, new Vector4(1.00f, 1.00f, 1.00f, 0.70f));
|
||||
setVec(ImGuiCol.NavWindowingDimBg, new Vector4(0.80f, 0.80f, 0.80f, 0.20f));
|
||||
setVec(ImGuiCol.ModalWindowDimBg, new Vector4(0.20f, 0.20f, 0.20f, 0.35f));
|
||||
|
||||
return;
|
||||
|
||||
void set(ImGuiCol colorVar, Color color)
|
||||
=> setVec(colorVar, new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, 1f));
|
||||
|
||||
void setVec(ImGuiCol colorVar, Vector4 colorVec)
|
||||
=> style.Colors[(int)colorVar] = colorVec;
|
||||
|
||||
uint colorValue(Color color) => ((uint)color.R << 16)
|
||||
| ((uint)color.G << 8)
|
||||
| color.B;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Gommon;
|
||||
using ImGuiNET;
|
||||
using Silk.NET.OpenGL.Extensions.ImGui;
|
||||
using Silk.NET.Windowing;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
@ -19,22 +19,27 @@ public sealed partial class UiManager
|
|||
{
|
||||
public readonly ConcurrentQueue<Func<Task>> TaskQueue = new();
|
||||
|
||||
public UiLayer[] Layers { get; }
|
||||
public readonly List<UiView> Views = [];
|
||||
|
||||
private int CurrentLayerIdx { get; set; }
|
||||
public unsafe ThemedColors* Theme { get; }
|
||||
|
||||
private void SetLayer(int layerIndex) =>
|
||||
CurrentLayerIdx = layerIndex.CoerceAtLeast(0).CoerceAtMost(Layers.Length - 1);
|
||||
private int CurrentViewIdx { get; set; }
|
||||
|
||||
private void SetView(int viewIndex) =>
|
||||
CurrentViewIdx = viewIndex.CoerceAtLeast(0).CoerceAtMost(Views.Count - 1);
|
||||
|
||||
public UiLayer CurrentLayer => Layers[CurrentLayerIdx];
|
||||
public UiView CurrentView => Views[CurrentViewIdx];
|
||||
|
||||
private UiManager(CreateParams @params)
|
||||
{
|
||||
Layers = @params.Layers;
|
||||
unsafe
|
||||
{
|
||||
Theme = @params.Theme;
|
||||
}
|
||||
|
||||
_window = Window.Create(@params.WOptions);
|
||||
|
||||
_fontConfig = @params.Font;
|
||||
_onConfigureIO = @params.OnConfigureIO;
|
||||
_windowIcon = @params.WindowIcon;
|
||||
|
||||
_window.Load += OnWindowLoad;
|
||||
|
@ -73,33 +78,35 @@ public sealed partial class UiManager
|
|||
// shoutout https://gist.github.com/moebiussurfing/8dbc7fef5964adcd29428943b78e45d2
|
||||
// for showing me how to properly setup dock space
|
||||
|
||||
const ImGuiWindowFlags windowFlags =
|
||||
ImGuiWindowFlags.MenuBar | ImGuiWindowFlags.NoDocking | ImGuiWindowFlags.NoTitleBar |
|
||||
var windowFlags =
|
||||
ImGuiWindowFlags.NoDocking | ImGuiWindowFlags.NoTitleBar |
|
||||
ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove |
|
||||
ImGuiWindowFlags.NoBringToFrontOnFocus | ImGuiWindowFlags.NoNavFocus;
|
||||
|
||||
var currView = CurrentView;
|
||||
if (currView.MainMenuBar != null)
|
||||
windowFlags |= ImGuiWindowFlags.MenuBar;
|
||||
|
||||
var viewport = ImGui.GetMainViewport();
|
||||
|
||||
ImGui.SetNextWindowPos(viewport.WorkPos);
|
||||
ImGui.SetNextWindowSize(viewport.WorkSize);
|
||||
ImGui.SetNextWindowViewport(viewport.ID);
|
||||
|
||||
using (var _ = new ScopedStyleVar(ImGuiStyleVar.WindowRounding, 0f))
|
||||
using (var __ = new ScopedStyleVar(ImGuiStyleVar.WindowBorderSize, 0f))
|
||||
using (new ScopedStyleVar(ImGuiStyleVar.WindowRounding, 0f))
|
||||
using (new ScopedStyleVar(ImGuiStyleVar.WindowBorderSize, 0f))
|
||||
ImGui.Begin("Dock Space", windowFlags);
|
||||
|
||||
ImGui.DockSpace(ImGui.GetID("DockSpace"), Vector2.Zero);
|
||||
|
||||
var currentLayer = CurrentLayer;
|
||||
|
||||
if (currentLayer.MainMenuBar is { } menuBar)
|
||||
if (currView.MainMenuBar is { } menuBar)
|
||||
if (ImGui.BeginMenuBar())
|
||||
{
|
||||
menuBar(delta);
|
||||
ImGui.EndMenuBar();
|
||||
}
|
||||
|
||||
currentLayer.RenderInternal(delta);
|
||||
currView.RenderInternal(delta);
|
||||
|
||||
ImGui.End();
|
||||
|
||||
|
@ -112,11 +119,13 @@ public sealed partial class UiManager
|
|||
|
||||
public readonly struct CreateParams
|
||||
{
|
||||
public readonly WindowOptions WOptions { get; init; }
|
||||
public readonly UiLayer[] Layers { get; init; }
|
||||
public readonly ImGuiFontConfig Font { get; init; }
|
||||
public readonly Image<Rgba32>? WindowIcon { get; init; }
|
||||
public readonly string ThreadName { get; init; }
|
||||
public WindowOptions WOptions { get; init; }
|
||||
public Action<ImGuiIOPtr> OnConfigureIO { get; init; }
|
||||
public Image<Rgba32>? WindowIcon { get; init; }
|
||||
|
||||
public unsafe ThemedColors* Theme { get; init; }
|
||||
|
||||
public string ThreadName { get; init; }
|
||||
}
|
||||
|
||||
public static bool TryCreateUi(CreateParams createParams, out Exception? error)
|
||||
|
@ -130,14 +139,6 @@ public sealed partial class UiManager
|
|||
try
|
||||
{
|
||||
Instance = new UiManager(createParams);
|
||||
|
||||
// declared as illegal code by the Silk God (Main thread isn't the controller of the Window)
|
||||
new Thread(() =>
|
||||
{
|
||||
Instance.Run(); //returns when UI is closed
|
||||
Instance.Dispose();
|
||||
Instance = null;
|
||||
}) { Name = createParams.ThreadName }.Start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -149,4 +150,17 @@ public sealed partial class UiManager
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void StartThread(string threadName)
|
||||
{
|
||||
// declared as illegal code by the Silk God (Main thread isn't the controller of the Window)
|
||||
new Thread(() =>
|
||||
{
|
||||
Instance?.Run(); //returns when UI is closed
|
||||
Instance?.Dispose();
|
||||
Instance = null;
|
||||
}) { Name = threadName }.Start();
|
||||
}
|
||||
|
||||
public static void AddView(UiView view) => Instance!.Views.Add(view);
|
||||
}
|
|
@ -5,11 +5,27 @@ namespace Volte.UI;
|
|||
// https://github.com/adobe/imgui/blob/master/imgui_spectrum.h
|
||||
public static class Spectrum
|
||||
{
|
||||
public static ThemedColors Dark = new DarkThemedColors();
|
||||
public static ThemedColors Light = new LightThemeColors();
|
||||
public static unsafe ThemedColors* Dark
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (DarkThemedColors* ptr = &DarkThemedColors.Instance)
|
||||
return (ThemedColors*)ptr;
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe ThemedColors* Light
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (LightThemedColors* ptr = &LightThemedColors.Instance)
|
||||
return (ThemedColors*)ptr;
|
||||
}
|
||||
}
|
||||
|
||||
public class DarkThemedColors : ThemedColors
|
||||
{
|
||||
internal static DarkThemedColors Instance = new();
|
||||
internal override Color Gray50 => Color(0x252525);
|
||||
internal override Color Gray75 => Color(0x2F2F2F);
|
||||
internal override Color Gray100 => Color(0x323232);
|
||||
|
@ -71,8 +87,9 @@ public static class Spectrum
|
|||
internal override Color Purple700 => Color(0xB483F0);
|
||||
}
|
||||
|
||||
public class LightThemeColors : ThemedColors
|
||||
public class LightThemedColors : ThemedColors
|
||||
{
|
||||
internal static LightThemedColors Instance = new();
|
||||
internal override Color Gray50 => Color(0xFFFFFF);
|
||||
internal override Color Gray75 => Color(0xFAFAFA);
|
||||
internal override Color Gray100 => Color(0xF5F5F5);
|
||||
|
|
|
@ -9,7 +9,7 @@ using Silk.NET.SDL;
|
|||
|
||||
namespace Volte.UI;
|
||||
|
||||
public abstract class UiLayer
|
||||
public abstract class UiView
|
||||
{
|
||||
private readonly List<Action<double>> _panels = [];
|
||||
|
||||
|
@ -56,77 +56,6 @@ public abstract class UiLayer
|
|||
foreach (var renderPanel in _panels)
|
||||
renderPanel(delta);
|
||||
}
|
||||
|
||||
public static void SetColors(ref ThemedColors theme, bool dark)
|
||||
{
|
||||
var style = ImGui.GetStyle();
|
||||
|
||||
style.GrabRounding = 4f;
|
||||
style.FrameRounding = 6f;
|
||||
style.WindowMenuButtonPosition = ImGuiDir.None;
|
||||
style.FrameBorderSize = 1f;
|
||||
style.TabBorderSize = 1f;
|
||||
style.WindowTitleAlign = new Vector2(0.5f);
|
||||
style.SeparatorTextBorderSize = 9f;
|
||||
|
||||
set(ImGuiCol.Text, theme.Gray800);
|
||||
set(ImGuiCol.TextDisabled, theme.Gray500);
|
||||
set(ImGuiCol.WindowBg, theme.Gray100);
|
||||
set(ImGuiCol.ChildBg, Spectrum.Static.None);
|
||||
set(ImGuiCol.PopupBg, theme.Gray50);
|
||||
set(ImGuiCol.Border, theme.Gray300);
|
||||
set(ImGuiCol.BorderShadow, Spectrum.Static.None);
|
||||
set(ImGuiCol.FrameBg, theme.Gray75);
|
||||
set(ImGuiCol.FrameBgHovered, theme.Gray50);
|
||||
set(ImGuiCol.FrameBgActive, theme.Gray200);
|
||||
set(ImGuiCol.TitleBg, theme.Gray300);
|
||||
set(ImGuiCol.TitleBgActive, theme.Gray200);
|
||||
set(ImGuiCol.TitleBgCollapsed, theme.Gray400);
|
||||
set(ImGuiCol.TabUnfocusedActive, theme.Blue400);
|
||||
set(ImGuiCol.MenuBarBg, theme.Gray100);
|
||||
set(ImGuiCol.ScrollbarBg, theme.Gray100);
|
||||
set(ImGuiCol.ScrollbarGrab, theme.Gray400);
|
||||
set(ImGuiCol.ScrollbarGrabHovered, theme.Gray600);
|
||||
set(ImGuiCol.ScrollbarGrabActive, theme.Gray700);
|
||||
set(ImGuiCol.CheckMark, theme.Blue500);
|
||||
set(ImGuiCol.SliderGrab, theme.Gray700);
|
||||
set(ImGuiCol.SliderGrabActive, theme.Gray800);
|
||||
set(ImGuiCol.Button, theme.Gray75);
|
||||
set(ImGuiCol.ButtonHovered, theme.Gray50);
|
||||
set(ImGuiCol.ButtonActive, theme.Gray200);
|
||||
set(ImGuiCol.Header, theme.Blue400);
|
||||
set(ImGuiCol.HeaderHovered, theme.Blue500);
|
||||
set(ImGuiCol.HeaderActive, theme.Blue600);
|
||||
set(ImGuiCol.Separator, theme.Gray400);
|
||||
set(ImGuiCol.SeparatorHovered, theme.Gray600);
|
||||
set(ImGuiCol.SeparatorActive, theme.Gray700);
|
||||
set(ImGuiCol.ResizeGrip, theme.Gray400);
|
||||
set(ImGuiCol.ResizeGripHovered, theme.Gray600);
|
||||
set(ImGuiCol.ResizeGripActive, theme.Gray700);
|
||||
set(ImGuiCol.PlotLines, theme.Blue400);
|
||||
set(ImGuiCol.PlotLinesHovered, theme.Blue600);
|
||||
set(ImGuiCol.PlotHistogram, theme.Blue400);
|
||||
set(ImGuiCol.PlotHistogramHovered, theme.Blue600);
|
||||
|
||||
setVec(ImGuiCol.TextSelectedBg, ImGui.ColorConvertU32ToFloat4((colorValue(theme.Blue400) & 0x00FFFFFF) | 0x33000000));
|
||||
setVec(ImGuiCol.DragDropTarget, new Vector4(1.00f, 1.00f, 0.00f, 0.90f));
|
||||
setVec(ImGuiCol.NavHighlight, ImGui.ColorConvertU32ToFloat4((colorValue(theme.Gray900) & 0x00FFFFFF) | 0x0A000000));
|
||||
setVec(ImGuiCol.NavWindowingHighlight, new Vector4(1.00f, 1.00f, 1.00f, 0.70f));
|
||||
setVec(ImGuiCol.NavWindowingDimBg, new Vector4(0.80f, 0.80f, 0.80f, 0.20f));
|
||||
setVec(ImGuiCol.ModalWindowDimBg, new Vector4(0.20f, 0.20f, 0.20f, 0.35f));
|
||||
|
||||
return;
|
||||
|
||||
void set(ImGuiCol colorVar, Color color)
|
||||
=> setVec(colorVar, new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, 1f));
|
||||
|
||||
void setVec(ImGuiCol colorVar, Vector4 colorVec)
|
||||
=> style.Colors[(int)colorVar] = colorVec;
|
||||
|
||||
uint colorValue(Color color) => ((uint)color.R << 16)
|
||||
| ((uint)color.G << 8)
|
||||
| color.B;
|
||||
}
|
||||
|
||||
protected static void Await(Func<Task> task) => UiManager.Instance!.TaskQueue.Enqueue(task);
|
||||
protected static void Await(Task task) => Await(() => task);
|
Loading…
Reference in a new issue