Work on creating a simple message box dialog.

This commit is contained in:
H. Utku Maden 2025-11-13 21:35:01 +03:00
parent 2932b3b85e
commit c4fe4841fe
22 changed files with 668 additions and 29 deletions

View File

@ -4,7 +4,7 @@ using BindingFlags = System.Reflection.BindingFlags;
namespace Dashboard.Pal namespace Dashboard.Pal
{ {
public abstract class AppContext : IContextBase<AppContext, IAppContextExtension> public abstract class Application : IContextBase<Application, IApplicationExtension>
{ {
public abstract string DriverName { get; } public abstract string DriverName { get; }
public abstract string DriverVendor { get; } public abstract string DriverVendor { get; }
@ -16,12 +16,17 @@ namespace Dashboard.Pal
public bool IsDisposed { get; private set; } = false; public bool IsDisposed { get; private set; } = false;
public IContextDebugger? Debugger { get; set; } public IContextDebugger? Debugger { get; set; }
private readonly TypeDictionary<IAppContextExtension> _extensions = private readonly TypeDictionary<IApplicationExtension> _extensions =
new TypeDictionary<IAppContextExtension>(true); new TypeDictionary<IApplicationExtension>(true);
private readonly TypeDictionary<IAppContextExtension, Func<IAppContextExtension>> _preloadedExtensions = private readonly TypeDictionary<IApplicationExtension, Func<IApplicationExtension>> _preloadedExtensions =
new TypeDictionary<IAppContextExtension, Func<IAppContextExtension>>(true); new TypeDictionary<IApplicationExtension, Func<IApplicationExtension>>(true);
~AppContext() public Application()
{
Current = this;
}
~Application()
{ {
InvokeDispose(false); InvokeDispose(false);
} }
@ -83,19 +88,32 @@ namespace Dashboard.Pal
window.WindowManager = wm; window.WindowManager = wm;
return window; return window;
} }
public IWindow CreateDialogWindow(IWindow? parent = null)
{
if (parent is IVirtualWindow virtualWindow)
{
IWindow? window = virtualWindow.WindowManager?.CreateWindow();
if (window != null)
return window;
}
return CreatePhysicalWindow();
}
#endregion #endregion
public bool IsExtensionAvailable<T>() where T : IAppContextExtension public bool IsExtensionAvailable<T>() where T : IApplicationExtension
{ {
return _extensions.Contains<T>() || _preloadedExtensions.Contains<T>(); return _extensions.Contains<T>() || _preloadedExtensions.Contains<T>();
} }
public bool ExtensionPreload<T>() where T : IAppContextExtension, new() public bool ExtensionPreload<T>() where T : IApplicationExtension, new()
{ {
return _preloadedExtensions.Add<T>(() => new T()); return _preloadedExtensions.Add<T>(() => new T());
} }
public T ExtensionRequire<T>() where T : IAppContextExtension public T ExtensionRequire<T>() where T : IApplicationExtension
{ {
T? extension = default; T? extension = default;
@ -107,7 +125,7 @@ namespace Dashboard.Pal
if (_extensions.TryGet(out extension)) if (_extensions.TryGet(out extension))
return extension; return extension;
if (_preloadedExtensions.Remove<T>(out Func<IAppContextExtension>? loader)) if (_preloadedExtensions.Remove<T>(out Func<IApplicationExtension>? loader))
{ {
extension = (T)loader!(); extension = (T)loader!();
} }
@ -128,7 +146,7 @@ namespace Dashboard.Pal
{ {
if (!isDisposing) return; if (!isDisposing) return;
foreach (IAppContextExtension extension in _extensions) foreach (IApplicationExtension extension in _extensions)
{ {
extension.Dispose(); extension.Dispose();
} }
@ -145,5 +163,12 @@ namespace Dashboard.Pal
} }
public void Dispose() => InvokeDispose(true); public void Dispose() => InvokeDispose(true);
[ThreadStatic] private static Application _current;
public static Application Current
{
get => _current ?? throw new InvalidOperationException("There is currently no current application.");
set => _current = value;
}
} }
} }

View File

@ -10,6 +10,9 @@ namespace Dashboard.Pal
private readonly TypeDictionary<IDeviceContextExtension, Func<IDeviceContextExtension>> _preloadedExtensions = private readonly TypeDictionary<IDeviceContextExtension, Func<IDeviceContextExtension>> _preloadedExtensions =
new TypeDictionary<IDeviceContextExtension, Func<IDeviceContextExtension>>(true); new TypeDictionary<IDeviceContextExtension, Func<IDeviceContextExtension>>(true);
private Dictionary<string, object> _attributes = new Dictionary<string, object>();
public abstract string DriverName { get; } public abstract string DriverName { get; }
public abstract string DriverVendor { get; } public abstract string DriverVendor { get; }
public abstract Version DriverVersion { get; } public abstract Version DriverVersion { get; }
@ -72,6 +75,29 @@ namespace Dashboard.Pal
return extension; return extension;
} }
public void SetAttribute(string name, object? v)
{
if (v != null)
_attributes[name] = v;
else
_attributes.Remove(name);
}
public void SetAttribute<T>(string name, T v) => SetAttribute(name, (object?)v);
public object? GetAttribute(string name)
{
return _attributes.GetValueOrDefault(name);
}
public T? GetAttribute<T>(string name)
{
object? o = GetAttribute(name);
if (o != null)
return (T?)o;
return default;
}
/// <summary> /// <summary>
/// Implement your dispose in this function. /// Implement your dispose in this function.
/// </summary> /// </summary>

View File

@ -1,7 +0,0 @@
namespace Dashboard.Pal
{
public interface IAppContextExtension : IContextExtensionBase<AppContext>
{
}
}

View File

@ -0,0 +1,7 @@
namespace Dashboard.Pal
{
public interface IApplicationExtension : IContextExtensionBase<Application>
{
}
}

View File

@ -50,6 +50,7 @@ namespace Dashboard.Windowing
/// </summary> /// </summary>
public interface IVirtualWindow : IWindow, IEventListener public interface IVirtualWindow : IWindow, IEventListener
{ {
IWindowManager? WindowManager { get; set; }
} }
/// <summary> /// <summary>

View File

@ -98,6 +98,11 @@ namespace Dashboard.Drawing.OpenGL.Pal
return; return;
} }
if (levels == 0)
{
levels = Math.Max(Math.ILogB(width), Math.ILogB(height));
}
Bind(); Bind();
SizedInternalFormat glFormat = GetFormat(format); SizedInternalFormat glFormat = GetFormat(format);
if (Extension.SupportsArbTextureStorage) if (Extension.SupportsArbTextureStorage)
@ -122,18 +127,23 @@ namespace Dashboard.Drawing.OpenGL.Pal
switch (Type) switch (Type)
{ {
case TextureType.Texture1D: case TextureType.Texture1D:
GL.TexImage1D(Target, 0, (InternalFormat)glFormat, width, 0, (OGL.PixelFormat)glFormat, PixelType.Byte, IntPtr.Zero); GL.TexImage1D(Target, 0, (InternalFormat)glFormat, width, 0, (OGL.PixelFormat)glFormat, PixelType.UnsignedByte, IntPtr.Zero);
break; break;
case TextureType.Texture2D: case TextureType.Texture2D:
GL.TexImage2D(Target, 0, (InternalFormat)glFormat, width, height, 0, (OGL.PixelFormat)glFormat, PixelType.Byte, IntPtr.Zero); GL.TexImage2D(Target, 0, (InternalFormat)glFormat, width, height, 0, (OGL.PixelFormat)glFormat, PixelType.UnsignedByte, IntPtr.Zero);
break; break;
case TextureType.Texture3D: case TextureType.Texture3D:
case TextureType.Texture2DArray: case TextureType.Texture2DArray:
case TextureType.Texture2DCube: case TextureType.Texture2DCube:
GL.TexImage3D(Target, 0, (InternalFormat)glFormat, width, height, depth, 0, (OGL.PixelFormat)glFormat, PixelType.Byte, IntPtr.Zero); GL.TexImage3D(Target, 0, (InternalFormat)glFormat, width, height, depth, 0, (OGL.PixelFormat)glFormat, PixelType.UnsignedByte, IntPtr.Zero);
break; break;
} }
} }
Width = width;
Height = height;
Depth = depth;
Levels = levels;
} }
public void Read<T>(Span<T> buffer, int level = 0, int align = 0) where T : unmanaged public void Read<T>(Span<T> buffer, int level = 0, int align = 0) where T : unmanaged
@ -160,7 +170,7 @@ namespace Dashboard.Drawing.OpenGL.Pal
PixelType glType = format switch PixelType glType = format switch
{ {
PixelFormat.R8I or PixelFormat.Rg8I or PixelFormat.Rgb8I or PixelFormat.Rgba8I => PixelType.Byte, PixelFormat.R8I or PixelFormat.Rg8I or PixelFormat.Rgb8I or PixelFormat.Rgba8I => PixelType.UnsignedByte,
PixelFormat.R16F or PixelFormat.Rg16F or PixelFormat.Rgb16F or PixelFormat.Rgba16F => PixelType.HalfFloat, PixelFormat.R16F or PixelFormat.Rg16F or PixelFormat.Rgb16F or PixelFormat.Rgba16F => PixelType.HalfFloat,
_ => throw new NotSupportedException() _ => throw new NotSupportedException()
}; };

View File

@ -1,13 +1,13 @@
using Dashboard.Drawing.OpenGL.Pal; using Dashboard.Drawing.OpenGL.Pal;
using Dashboard.Pal;
using Dashboard.Windowing; using Dashboard.Windowing;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Platform; using OpenTK.Platform;
using AppContext = Dashboard.Pal.AppContext;
using TK = OpenTK.Platform.Toolkit; using TK = OpenTK.Platform.Toolkit;
namespace Dashboard.OpenTK.PAL2 namespace Dashboard.OpenTK.PAL2
{ {
public class Pal2AppContext : AppContext public class Pal2Application : Application
{ {
public override string DriverName => "Dashboard OpenTK PAL2.0 Driver"; public override string DriverName => "Dashboard OpenTK PAL2.0 Driver";
public override string DriverVendor => "Dashboard"; public override string DriverVendor => "Dashboard";

View File

@ -6,17 +6,30 @@ namespace Dashboard.Controls
{ {
public class Control : IEventListener, IDisposable public class Control : IEventListener, IDisposable
{ {
private Form? _owner = null;
public string? Id { get; set; } public string? Id { get; set; }
public ClassSet Classes { get; } public ClassSet Classes { get; }
public Form? Owner { get; protected set; } = null; public Form Owner
{
get => _owner ?? throw NoOwnerException;
protected set
{
_owner = value;
OnOwnerChanged(value);
}
}
public Control? Parent { get; private set; } = null; public Control? Parent { get; private set; } = null;
public bool Disposed { get; private set; } public bool Disposed { get; private set; }
public virtual DrawQueue DrawQueue => Owner?.DrawQueue ?? throw NoOwnerException;
public virtual Box2d ClientArea { get; set; } public virtual Box2d ClientArea { get; set; }
public bool IsFocused => _owner?.FocusedControl == this;
public event EventHandler? Painting; public event EventHandler? Painting;
public event EventHandler? OwnerChanged; public event EventHandler? OwnerChanged;
public event EventHandler? ParentChanged; public event EventHandler? ParentChanged;
public event EventHandler? FocusGained;
public event EventHandler? FocusLost;
public event EventHandler? Disposing; public event EventHandler? Disposing;
public event EventHandler? Resized; public event EventHandler? Resized;
@ -49,6 +62,7 @@ namespace Dashboard.Controls
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (disposing) Disposing?.Invoke(this, EventArgs.Empty);
} }
public void Dispose() => InvokeDispose(true); public void Dispose() => InvokeDispose(true);
@ -61,6 +75,42 @@ namespace Dashboard.Controls
internal static void SetParent(Control parent, Control child) internal static void SetParent(Control parent, Control child)
{ {
child.Parent = parent; child.Parent = parent;
child.ParentChanged?.Invoke(child, EventArgs.Empty);
}
public virtual void Focus()
{
(Owner ?? throw NoOwnerException).Focus(this);
}
protected virtual void OnFocusGained(object sender)
{
FocusGained?.Invoke(sender, EventArgs.Empty);
}
protected virtual void OnFocusLost(object sender)
{
FocusLost?.Invoke(sender, EventArgs.Empty);
}
internal static void InvokeFocusGained(Form form, Control control)
{
control.OnFocusGained(form);
}
internal static void InvokeFocusLost(Form form, Control control)
{
control.OnFocusLost(form);
}
protected virtual void OnResize()
{
Resized?.Invoke(this, EventArgs.Empty);
}
private void OnOwnerChanged(Form value)
{
OwnerChanged?.Invoke(this, EventArgs.Empty);
} }
protected static Exception NoOwnerException => new Exception("No form owns this control"); protected static Exception NoOwnerException => new Exception("No form owns this control");

View File

@ -1,4 +1,6 @@
using System;
using Dashboard.Drawing; using Dashboard.Drawing;
using Dashboard.Resources;
using Dashboard.Windowing; using Dashboard.Windowing;
namespace Dashboard.Controls namespace Dashboard.Controls
@ -7,6 +9,10 @@ namespace Dashboard.Controls
{ {
public IWindow Window { get; } public IWindow Window { get; }
public Image? WindowIcon { get; set; }
public string? Title { get; set; } = "Untitled Form";
public Control? FocusedControl { get; private set; } = null;
public override Box2d ClientArea public override Box2d ClientArea
{ {
get => new Box2d(0, 0, Window.ClientSize.Width, Window.ClientSize.Height); get => new Box2d(0, 0, Window.ClientSize.Width, Window.ClientSize.Height);
@ -17,5 +23,15 @@ namespace Dashboard.Controls
{ {
Window = window; Window = window;
} }
public void Focus(Control control)
{
if (FocusedControl != null)
InvokeFocusLost(this, FocusedControl);
FocusedControl = control;
InvokeFocusGained(this, control);
}
} }
} }

View File

@ -30,7 +30,7 @@ namespace Dashboard.Controls
public override void OnPaint() public override void OnPaint()
{ {
base.OnPaint(); base.OnPaint();
DrawQueue.Text(new Vector3(ClientArea.Min, 0), TextBrush, Text, Font); // DrawQueue.Text(new Vector3(ClientArea.Min, 0), TextBrush, Text, Font);
} }
} }
} }

View File

@ -0,0 +1,138 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using Dashboard.Resources;
using Dashboard.Windowing;
namespace Dashboard.Controls
{
public enum MessageBoxIcon
{
Info,
Question,
Warning,
Error,
Custom,
}
public enum MessageBoxButtons
{
AbortRetryIgnore,
CancelRetryContinue,
Ok,
OkCancel,
RetryCancel,
YesNo,
YesNoCancel,
Custom,
}
/// <summary>
/// A simple message box dialog.
/// </summary>
public class MessageBox : Form
{
private Image? _icon;
private Label _label = new Label();
private readonly List<Label> _buttons = new List<Label>();
public MessageBoxIcon Icon { get; set; }
public Image? CustomImage { get; set; }
public string? Message { get; set; }
public MessageBoxButtons Buttons { get; set; }
public ObservableCollection<string> CustomButtons { get; } = new ObservableCollection<string>();
public int Result { get; private set; }
public MessageBox(IWindow window) : base(window)
{
SetParent(this, _label);
}
public static readonly Image s_questionIcon;
public static readonly Image s_infoIcon;
public static readonly Image s_warningIcon;
public static readonly Image s_errorIcon;
private static readonly ImmutableList<string> s_abortRetryContinue = ["Abort", "Retry", "Continue"];
private static readonly ImmutableList<string> s_cancelRetryContinue = ["Cancel", "Retry", "Continue"];
private static readonly ImmutableList<string> s_ok = ["OK"];
private static readonly ImmutableList<string> s_okCancel = ["OK", "Cancel"];
private static readonly ImmutableList<string> s_retryCancel = ["Retry", "Cancel"];
private static readonly ImmutableList<string> s_yesNo = ["Yes", "No"];
private static readonly ImmutableList<string> s_yesNoCancel = ["Yes", "No", "Cancel"];
static MessageBox()
{
Assembly asm = typeof(MessageBox).Assembly;
using (Stream str = asm.GetManifestResourceStream("Dashboard.Resources.question.png")!)
s_questionIcon = Image.Load(str);
using (Stream str = asm.GetManifestResourceStream("Dashboard.Resources.info.png")!)
s_infoIcon = Image.Load(str);
using (Stream str = asm.GetManifestResourceStream("Dashboard.Resources.warning.png")!)
s_warningIcon = Image.Load(str);
using (Stream str = asm.GetManifestResourceStream("Dashboard.Resources.error.png")!)
s_errorIcon = Image.Load(str);
}
public override void OnPaint()
{
base.OnPaint();
}
public static MessageBox Create(IWindow window, string message, string title, MessageBoxIcon icon, MessageBoxButtons buttons)
{
return new MessageBox(window)
{
Message = message,
Title = title,
Icon = icon,
Buttons = buttons,
};
}
// public static MessageBox Create(IWindow window, string message, string title, Image icon, IEnumerable<string> buttons)
// {
// throw new NotImplementedException();
// }
private static string GetDefaultTitle(MessageBoxIcon icon)
{
return icon switch
{
MessageBoxIcon.Error => "Error",
MessageBoxIcon.Info => "Info",
MessageBoxIcon.Question => "Question",
MessageBoxIcon.Warning => "Warning",
_ => "Message Box",
};
}
private static Image GetDefaultIcon(MessageBoxIcon icon)
{
return icon switch
{
MessageBoxIcon.Error => s_errorIcon,
MessageBoxIcon.Question => s_questionIcon,
MessageBoxIcon.Warning => s_warningIcon,
_ => s_infoIcon,
};
}
private static ImmutableList<string> GetDefaultButtons(MessageBoxButtons buttons)
{
return buttons switch
{
MessageBoxButtons.AbortRetryIgnore => s_abortRetryContinue,
MessageBoxButtons.CancelRetryContinue => s_cancelRetryContinue,
MessageBoxButtons.OkCancel => s_okCancel,
MessageBoxButtons.RetryCancel => s_retryCancel,
MessageBoxButtons.YesNo => s_yesNo,
MessageBoxButtons.YesNoCancel => s_yesNoCancel,
_ => s_ok,
};
}
}
}

View File

@ -9,6 +9,11 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Dashboard.Common\Dashboard.Common.csproj" /> <ProjectReference Include="..\Dashboard.Common\Dashboard.Common.csproj" />
<ProjectReference Include="..\Dashboard.Drawing\Dashboard.Drawing.csproj" /> <ProjectReference Include="..\Dashboard.Drawing\Dashboard.Drawing.csproj" />
<EmbeddedResource Include="Resources\**\*.png"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="ReFuel.StbImage" Version="2.1.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,81 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
using Dashboard.Drawing;
using Dashboard.Pal;
using ReFuel.Stb;
using ReFuel.Stb.Native;
namespace Dashboard.Resources
{
public class Image(PixelFormat format, int width, int height, byte[] data, bool premultiplied = false) : IDisposable
{
protected readonly ConditionalWeakTable<DeviceContext, ITexture> Textures =
new ConditionalWeakTable<DeviceContext, ITexture>();
protected virtual TextureType TextureType => TextureType.Texture2D;
public PixelFormat Format { get; } = format;
public int Width { get; } = width;
public int Height { get; } = height;
public bool Premultiplied { get; } = premultiplied;
public bool IsDisposed { get; private set; } = false;
~Image()
{
InvokeDispose(false);
}
public virtual ITexture InternTexture(DeviceContext dc)
{
if (Textures.TryGetValue(dc, out ITexture? texture))
return texture;
ITextureExtension ext = dc.ExtensionRequire<ITextureExtension>();
texture = ext.CreateTexture(TextureType.Texture2D);
texture.SetStorage(Format, Width, Height, 1, 0);
texture.Write<byte>(Format, data);
texture.Premultiplied = Premultiplied;
texture.GenerateMipmaps();
Textures.Add(dc, texture);
return texture;
}
private void InvokeDispose(bool disposing)
{
if (IsDisposed)
return;
IsDisposed = true;
Dispose(disposing);
}
protected virtual void Dispose(bool disposing)
{
foreach ((DeviceContext dc, ITexture texture) in Textures)
{
texture.Dispose();
}
}
public void Dispose() => InvokeDispose(true);
public static Image Load(Stream stream)
{
using StbImage image = StbImage.Load(stream, StbiImageFormat.Rgba);
ReadOnlySpan<byte> data = image.AsSpan<byte>();
return new Image(
image.Format switch
{
StbiImageFormat.Grey => PixelFormat.R8I,
StbiImageFormat.Rgb => PixelFormat.Rgb8I,
StbiImageFormat.Rgba => PixelFormat.Rgba8I,
// StbiImageFormat.GreyAlpha) => PixelFormat.Rg8I,
_ => throw new Exception("Unrecognized pixel format"),
},
image.Width, image.Height,
data.ToArray());
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="48"
height="48"
viewBox="0 0 12.7 12.7"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="error.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="6.0664802"
inkscape:cx="-5.7694081"
inkscape:cy="25.962336"
inkscape:window-width="2560"
inkscape:window-height="1364"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showguides="true">
<sodipodi:guide
position="6.3500001,12.7"
orientation="-1,0"
id="guide1"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
<sodipodi:guide
position="3.705891,12.686148"
orientation="-1,0"
id="guide2"
inkscape:label=""
inkscape:locked="false"
inkscape:color="rgb(0,134,229)" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
sodipodi:type="star"
style="fill:#ff0000;stroke:#d60000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path1"
inkscape:flatsided="true"
sodipodi:sides="8"
sodipodi:cx="6.3499999"
sodipodi:cy="6.3499999"
sodipodi:r1="6.8657174"
sodipodi:r2="8.2966747"
sodipodi:arg1="1.9608592"
sodipodi:arg2="2.3535583"
inkscape:rounded="0"
inkscape:randomized="0"
d="M 3.7393344,12.7 0.01385251,8.9941088 -2.0290497e-7,3.7393344 3.705891,0.01385251 8.9606654,-2.0290497e-7 12.686147,3.705891 12.7,8.9606654 8.9941088,12.686147 Z"
transform="matrix(0.92700733,0,0,0.92700733,0.46350342,0.46350342)" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:9.87777px;line-height:normal;font-family:'Rec Mono Linear';-inkscape-font-specification:'Rec Mono Linear Bold';text-align:center;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;direction:ltr;text-orientation:upright;text-anchor:middle;fill:#ffffff;stroke:none;stroke-width:0.600001"
x="6.3154373"
y="9.0071211"
id="text1"><tspan
sodipodi:role="line"
id="tspan1"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Rec Mono Linear';-inkscape-font-specification:'Rec Mono Linear Bold';fill:#ffffff;stroke-width:0.6"
x="6.3154373"
y="9.0071211">x</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="48"
height="48"
viewBox="0 0 12.7 12.7"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="info.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="15.987983"
inkscape:cx="14.823634"
inkscape:cy="21.234699"
inkscape:window-width="2560"
inkscape:window-height="1364"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#00b200;fill-opacity:1;stroke:#009900;stroke-width:0.573001;stroke-dasharray:none;stroke-opacity:1"
id="rect1"
width="12.127"
height="12.127"
x="0.28650019"
y="0.28650019"
rx="1.0105833"
ry="1.0105834" />
<text
xml:space="preserve"
style="font-style:italic;font-size:9.87777px;line-height:normal;font-family:'Rec Mono Linear';-inkscape-font-specification:'Rec Mono Linear Italic';text-align:center;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;direction:ltr;text-orientation:upright;text-anchor:middle;fill:#f9f9f9;stroke:none;stroke-width:0.600001"
x="6.3351822"
y="10.172698"
id="text1"><tspan
sodipodi:role="line"
id="tspan1"
style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Rec Mono Linear';-inkscape-font-specification:'Rec Mono Linear Bold Italic';fill:#f9f9f9;stroke-width:0.6"
x="6.3351822"
y="10.172698">i</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="48"
height="48"
viewBox="0 0 12.7 12.7"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="question.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="6.4560796"
inkscape:cx="12.701206"
inkscape:cy="14.172688"
inkscape:window-width="2560"
inkscape:window-height="1364"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showguides="true"><sodipodi:guide
position="6.3500001,12.7"
orientation="-1,0"
id="guide1"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" /><sodipodi:guide
position="3.705891,12.686148"
orientation="-1,0"
id="guide2"
inkscape:label=""
inkscape:locked="false"
inkscape:color="rgb(0,134,229)" /></sodipodi:namedview><defs
id="defs1" /><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"><circle
style="fill:#0000ff;stroke:#0000cc;stroke-width:0.9271;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path2"
cx="6.3500004"
cy="6.3500004"
r="5.8864961" /><text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:9.87777px;line-height:normal;font-family:'Rec Mono Linear';-inkscape-font-specification:'Rec Mono Linear Bold';text-align:center;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;direction:ltr;text-orientation:upright;text-anchor:middle;fill:#ffffff;stroke:none;stroke-width:0.600001"
x="6.2907381"
y="9.8615408"
id="text1"><tspan
sodipodi:role="line"
id="tspan1"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Rec Mono Linear';-inkscape-font-specification:'Rec Mono Linear Bold';fill:#ffffff;stroke-width:0.6"
x="6.2907381"
y="9.8615408">?</tspan></text></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="48"
height="48"
viewBox="0 0 12.7 12.7"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="warning.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="1"
inkscape:cx="23"
inkscape:cy="24.5"
inkscape:window-width="2560"
inkscape:window-height="1364"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showguides="true">
<sodipodi:guide
position="6.3500001,12.7"
orientation="-1,0"
id="guide1"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,134,229)" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#ffcc00;stroke:#ffbb00;stroke-width:0.9271;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 0.46350557,12.236497 6.3500001,0.46350801 12.236494,12.236497 Z"
id="path1"
sodipodi:nodetypes="cccc" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:9.87777px;line-height:normal;font-family:'Rec Mono Linear';-inkscape-font-specification:'Rec Mono Linear Bold';text-align:center;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;direction:ltr;text-orientation:upright;text-anchor:middle;fill:#ffcc00;stroke:none;stroke-width:0.600001"
x="6.2858014"
y="10.821102"
id="text1"><tspan
sodipodi:role="line"
id="tspan1"
style="fill:#000000;stroke-width:0.6;-inkscape-font-specification:'Rec Mono Linear Bold';font-family:'Rec Mono Linear';font-weight:bold;font-style:normal;font-stretch:normal;font-variant:normal"
x="6.2858014"
y="10.821102">!</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -10,10 +10,13 @@ using OpenTK.Mathematics;
using Box2d = Dashboard.Box2d; using Box2d = Dashboard.Box2d;
using TK = OpenTK.Platform.Toolkit; using TK = OpenTK.Platform.Toolkit;
using Dashboard; using Dashboard;
using Dashboard.Controls;
using Dashboard.Drawing.OpenGL.Pal; using Dashboard.Drawing.OpenGL.Pal;
using Dashboard.Pal;
using Dashboard.Windowing; using Dashboard.Windowing;
using OpenTK.Windowing.GraphicsLibraryFramework; using OpenTK.Windowing.GraphicsLibraryFramework;
using AppContext = Dashboard.Pal.AppContext; using ReFuel.Stb;
using Image = Dashboard.Resources.Image;
using Vector4 = System.Numerics.Vector4; using Vector4 = System.Numerics.Vector4;
TK.Init(new ToolkitOptions() TK.Init(new ToolkitOptions()
@ -27,7 +30,7 @@ TK.Init(new ToolkitOptions()
FeatureFlags = ToolkitFlags.EnableOpenGL, FeatureFlags = ToolkitFlags.EnableOpenGL,
}); });
AppContext app = new Pal2AppContext() Application app = new Pal2Application()
{ {
GraphicsApiHints = new OpenGLGraphicsApiHints() GraphicsApiHints = new OpenGLGraphicsApiHints()
{ {
@ -106,6 +109,8 @@ EventQueue.EventRaised += (handle, type, eventArgs) =>
TK.Window.SetMode(window.WindowHandle, WindowMode.Normal); TK.Window.SetMode(window.WindowHandle, WindowMode.Normal);
// font = Typesetter.LoadFont("Nimbus Mono", 12f); // font = Typesetter.LoadFont("Nimbus Mono", 12f);
foreach (string str in typeof(Image).Assembly.GetManifestResourceNames()) Console.WriteLine(str);
window.Painting += (sender, ea) => { window.Painting += (sender, ea) => {
TK.Window.GetSize(window.WindowHandle, out Vector2i size); TK.Window.GetSize(window.WindowHandle, out Vector2i size);
// executor.BeginFrame(); // executor.BeginFrame();
@ -173,6 +178,8 @@ window.Painting += (sender, ea) => {
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
GL.ColorMask(true, true, true, true); GL.ColorMask(true, true, true, true);
ITexture texture = MessageBox.s_questionIcon.InternTexture(context);
// executor.Draw(window.DrawQueue, new RectangleF(0, 0, size.X, size.Y), 1.5f /*(window as IDpiAwareWindow)?.Scale ?? 1*/); // executor.Draw(window.DrawQueue, new RectangleF(0, 0, size.X, size.Y), 1.5f /*(window as IDpiAwareWindow)?.Scale ?? 1*/);
// executor.EndFrame(); // executor.EndFrame();