Dashboard/Dashboard.OpenTK/PAL2/PhysicalWindow.cs

200 lines
6.0 KiB
C#

using System.Collections.Concurrent;
using System.Drawing;
using System.Net;
using System.Runtime.CompilerServices;
using Dashboard.Drawing;
using Dashboard.Events;
using Dashboard.OpenGL;
using Dashboard.Pal;
using Dashboard.Windowing;
using OpenTK.Mathematics;
using OpenTK.Platform;
using MouseMoveEventArgs = Dashboard.Events.MouseMoveEventArgs;
using TK = OpenTK.Platform.Toolkit;
namespace Dashboard.OpenTK.PAL2
{
public class PhysicalWindow : IPhysicalWindow, IEventListener, IDpiAwareWindow
{
private readonly List<IEventListener> _listeners = new List<IEventListener>();
public Application Application { get; }
public WindowHandle WindowHandle { get; }
public DeviceContext DeviceContext { get; }
public bool DoubleBuffered => true; // Always true for OpenTK windows.
public IForm? Form { get; set; } = null;
public IWindowManager? WindowManager { get; set; }
public string Title
{
get => TK.Window.GetTitle(WindowHandle);
set => TK.Window.SetTitle(WindowHandle, value);
}
public SizeF OuterSize
{
get
{
TK.Window.GetSize(WindowHandle, out Vector2i size);
return new SizeF(size.X, size.Y);
}
set => TK.Window.SetSize(WindowHandle, new Vector2i((int)value.Width, (int)value.Height));
}
public SizeF ClientSize
{
get
{
TK.Window.GetClientSize(WindowHandle, out Vector2i size);
return new SizeF(size.X, size.Y);
}
set => TK.Window.SetClientSize(WindowHandle, new Vector2i((int)value.Width, (int)value.Height));
}
public event EventHandler? EventRaised;
public PhysicalWindow(Application app, WindowHandle window)
{
Application = app;
WindowHandle = window;
DeviceContext = CreateDeviceContext(app, this, new OpenGLGraphicsApiHints());
AddWindow(this);
}
public PhysicalWindow(Application app, WindowHandle window, OpenGLContextHandle context)
{
Application = app;
WindowHandle = window;
DeviceContext = new GLDeviceContext(app, this, new Pal2GLContext(window, context));
AddWindow(this);
}
public PhysicalWindow(Application app, GraphicsApiHints hints)
{
Application = app;
WindowHandle = TK.Window.Create(hints);
DeviceContext = CreateDeviceContext(app, this, hints);
AddWindow(this);
}
private static DeviceContext CreateDeviceContext(Application app, PhysicalWindow window, GraphicsApiHints hints)
{
WindowHandle handle = window.WindowHandle;
switch (hints.Api)
{
case GraphicsApi.OpenGL:
case GraphicsApi.OpenGLES:
return new GLDeviceContext(app, window, new Pal2GLContext(handle, TK.OpenGL.CreateFromWindow(handle)));
default:
throw new Exception($"Unknown graphics API {hints.Api}.");
}
}
public bool IsDisposed { get; private set; } = false;
public void Dispose()
{
if (IsDisposed) return;
IsDisposed = true;
RemoveWindow(this);
(DeviceContext as IDisposable)?.Dispose();
TK.Window.Destroy(WindowHandle);
}
public virtual void SendEvent(object? sender, EventArgs args)
{
switch (args)
{
case UiEventArgs ui:
switch (ui.Type)
{
case UiEventType.ControlInvalidateVisual:
break;
}
break;
}
args = TransformEvent(sender, args);
EventRaised?.Invoke(this, args);
lock (_listeners)
{
foreach (IEventListener listener in _listeners)
listener.SendEvent(this, args);
}
}
private EventArgs TransformEvent(object? sender, EventArgs args)
{
// TODO: future
return args;
}
public void SubcribeEvent(IEventListener listener)
{
lock (_listeners)
{
_listeners.Add(listener);
}
}
public void UnsubscribeEvent(IEventListener listener)
{
lock (_listeners)
{
_listeners.Remove(listener);
}
}
private static readonly ConcurrentDictionary<WindowHandle, PhysicalWindow> _windows =
new ConcurrentDictionary<WindowHandle, PhysicalWindow>();
static PhysicalWindow()
{
EventQueue.EventRaised += EventQueueOnEventRaised;
}
private static void AddWindow(PhysicalWindow window)
{
_windows.TryAdd(window.WindowHandle, window);
}
private static void RemoveWindow(PhysicalWindow window)
{
_windows.TryRemove(window.WindowHandle, out _);
}
private static void EventQueueOnEventRaised(PalHandle? handle, PlatformEventType type, EventArgs args)
{
if (handle is not WindowHandle windowHandle)
return;
if (!_windows.TryGetValue(windowHandle, out PhysicalWindow? window))
return;
switch (type)
{
case PlatformEventType.MouseMove:
case PlatformEventType.Scroll:
case PlatformEventType.MouseUp:
case PlatformEventType.MouseDown:
break;
}
}
public float Dpi => Scale * 96f;
public float Scale
{
get
{
TK.Window.GetScaleFactor(WindowHandle, out float x, out float y);
return Math.Max(x, y);
}
}
}
}