200 lines
6.0 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|