Allow changing the cursor, moved Window to GlitchyEngine.UI

This commit is contained in:
Simon Lübeß
2024-10-30 21:20:57 +01:00
parent 1818593394
commit 7506b8c118
11 changed files with 332 additions and 13 deletions
@@ -2,9 +2,9 @@ using Ultralight.CAPI;
namespace GlitchyEditor.Ultralight; namespace GlitchyEditor.Ultralight;
class UltralightEntityHierarchyWindow : UltralightWindow class UltralightMainWindow : UltralightWindow
{ {
public this() : base("Entity Hierarchy", "file:///react-ui-prototype/dist/index.html") public this() : base("Glitchy Engine", "file:///dist/index.html") // "file:///react-ui-prototype/dist/index.html"
//public this() : base("Entity Hierarchy", "file:///another-react-test/index.html") //public this() : base("Entity Hierarchy", "file:///another-react-test/index.html")
{ {
@@ -57,7 +57,7 @@ class UltralightEntityHierarchyWindow : UltralightWindow
/// ///
/// Create a JavaScript String containing the name of our callback. /// Create a JavaScript String containing the name of our callback.
/// ///
JSStringRef name = JSStringCreateWithUTF8CString("GetMessage"); JSStringRef name = JSStringCreateWithUTF8CString("OnCreateEntityClick");
/// ///
/// Create a garbage-collected JavaScript function that is bound to our native C callback /// Create a garbage-collected JavaScript function that is bound to our native C callback
@@ -6,14 +6,16 @@ using GlitchyEngine.Content;
using GlitchyEngine.Renderer; using GlitchyEngine.Renderer;
using Ultralight; using Ultralight;
using Ultralight.CAPI; using Ultralight.CAPI;
using DirectX.Windows;
using GlitchyEngine.UI;
namespace GlitchyEditor.Ultralight; namespace GlitchyEditor.Ultralight;
abstract class UltralightWindow abstract class UltralightWindow
{ {
protected Window _window ~ delete _; protected internal Window _window ~ delete _;
protected ULView _view; protected internal ULView _view;
private int2 _cursorPosition; private int2 _cursorPosition;
@@ -23,6 +25,7 @@ abstract class UltralightWindow
{ {
WindowDescription windowDesc = .Default; WindowDescription windowDesc = .Default;
windowDesc.Title = title; windowDesc.Title = title;
windowDesc.WindowStyle = .Borderless;
_window = new Window(windowDesc); _window = new Window(windowDesc);
_window.EventCallback = new => EventHandler; _window.EventCallback = new => EventHandler;
@@ -43,10 +46,11 @@ abstract class UltralightWindow
CreateTexture(); CreateTexture();
} }
private void InitView() protected virtual void InitView()
{ {
ULViewConfig viewConfig = ulCreateViewConfig(); ULViewConfig viewConfig = ulCreateViewConfig();
ulViewConfigSetIsAccelerated(viewConfig, false); ulViewConfigSetIsAccelerated(viewConfig, false);
ulViewConfigSetIsTransparent(viewConfig, true);
_view = ulCreateView(UltralightLayer.renderer, _window.SwapChain.Width, _window.SwapChain.Height, viewConfig, null); _view = ulCreateView(UltralightLayer.renderer, _window.SwapChain.Width, _window.SwapChain.Height, viewConfig, null);
@@ -61,6 +65,8 @@ abstract class UltralightWindow
ulViewSetFailLoadingCallback(_view, => OnFailedLoading, userData); ulViewSetFailLoadingCallback(_view, => OnFailedLoading, userData);
ulViewSetAddConsoleMessageCallback(_view, => OnAddConsoleMessage, userData); ulViewSetAddConsoleMessageCallback(_view, => OnAddConsoleMessage, userData);
ulViewSetChangeCursorCallback(_view, => OnChangeCursor, userData);
} }
#endregion Init #endregion Init
@@ -281,6 +287,116 @@ abstract class UltralightWindow
window.OnAddConsoleMessage(caller, source, level, message, line_number, column_number, source_id); window.OnAddConsoleMessage(caller, source, level, message, line_number, column_number, source_id);
} }
private static void OnChangeCursor(void* userData, C_View* caller, ULCursor ulCursor)
{
UltralightWindow window = (UltralightWindow)Internal.UnsafeCastToObject(userData);
CursorImage cursor;
switch (ulCursor)
{
case .kCursor_Pointer:
cursor = .Pointer;
case .kCursor_Cross:
cursor = .Crosshair;
case .kCursor_Hand:
cursor = .Hand;
case .kCursor_IBeam:
cursor = .IBeam;
case .kCursor_Wait:
cursor = .Wait;
case .kCursor_Help:
cursor = .Help;
case .kCursor_EastResize, .kCursor_WestResize, .kCursor_EastWestResize:
cursor = .ResizeEastWest;
case .kCursor_NorthResize, .kCursor_SouthResize, .kCursor_NorthSouthResize:
cursor = .ResizeNorthSouth;
case .kCursor_NorthEastResize, .kCursor_SouthWestResize, .kCursor_NorthEastSouthWestResize:
cursor = .ResizeNorthEastSouthWest;
case .kCursor_NorthWestResize, .kCursor_SouthEastResize, .kCursor_NorthWestSouthEastResize:
cursor = .ResizeNorthWestSouthEast;
case .kCursor_ColumnResize:
// TODO use cursor file
cursor = .ResizeColumn;
case .kCursor_RowResize:
// TODO use cursor file
cursor = .ResizeRow;
case .kCursor_MiddlePanning:
cursor = .PanMiddle;
case .kCursor_EastPanning:
cursor = .PanEast;
case .kCursor_WestPanning:
cursor = .PanWest;
case .kCursor_NorthPanning:
cursor = .PanNorth;
case .kCursor_SouthPanning:
cursor = .PanSouth;
case .kCursor_NorthEastPanning:
cursor = .PanNorthEast;
case .kCursor_NorthWestPanning:
cursor = .PanNorthWest;
case .kCursor_SouthEastPanning:
cursor = .PanSouthEast;
case .kCursor_SouthWestPanning:
cursor = .PanSouthWest;
case .kCursor_Move:
cursor = .Move;
case .kCursor_VerticalText:
cursor = .VerticalText;
case .kCursor_Cell:
cursor = .Cell;
case .kCursor_ContextMenu:
cursor = .ContextMenu;
case .kCursor_Alias:
cursor = .Alias;
case .kCursor_Progress:
cursor = .Progress;
case .kCursor_NoDrop, .kCursor_NotAllowed:
cursor = .NotAllowed;
case .kCursor_Copy:
cursor = .Copy;
case .kCursor_None:
cursor = .None;
case .kCursor_ZoomIn:
cursor = .ZoomIn;
case .kCursor_ZoomOut:
cursor = .ZoomOut;
case .kCursor_Grab:
cursor = .Grab;
case .kCursor_Grabbing:
cursor = .Grabbing;
case .kCursor_Custom:
cursor = .Custom;
}
window._window.SetCursor(cursor);
}
protected virtual void OnAddConsoleMessage(C_View* caller, ULMessageSource source, ULMessageLevel level, C_String* message, uint32 line_number, uint32 column_number, C_String* source_id) protected virtual void OnAddConsoleMessage(C_View* caller, ULMessageSource source, ULMessageLevel level, C_String* message, uint32 line_number, uint32 column_number, C_String* source_id)
{ {
GlitchLog.LogLevel logLevel = .Info; GlitchLog.LogLevel logLevel = .Info;
+4 -2
View File
@@ -17,7 +17,7 @@ class UltralightLayer : Layer
private List<UltralightWindow> _windows = new .() ~ DeleteContainerAndItems!(_); private List<UltralightWindow> _windows = new .() ~ DeleteContainerAndItems!(_);
public UltralightEntityHierarchyWindow EntityHierarchyWindow; public UltralightMainWindow EntityHierarchyWindow;
private static Self _instance; private static Self _instance;
@@ -29,7 +29,7 @@ class UltralightLayer : Layer
InitUltralight(); InitUltralight();
EntityHierarchyWindow = new UltralightEntityHierarchyWindow(); EntityHierarchyWindow = new UltralightMainWindow();
_windows.Add(EntityHierarchyWindow); _windows.Add(EntityHierarchyWindow);
_copyEffect = Content.LoadAsset("Resources/Shaders/Copy.hlsl"); _copyEffect = Content.LoadAsset("Resources/Shaders/Copy.hlsl");
@@ -56,6 +56,8 @@ class UltralightLayer : Layer
{ {
ULConfig config = ulCreateConfig(); ULConfig config = ulCreateConfig();
//ulConfigSetUserStylesheet(config);
ULString logPath = ulCreateString(@"D:\Development\Projects\Beef\GlitchyEngine\GlitchyEditor\ul.log"); ULString logPath = ulCreateString(@"D:\Development\Projects\Beef\GlitchyEngine\GlitchyEditor\ul.log");
ulEnableDefaultLogger(logPath); ulEnableDefaultLogger(logPath);
ulDestroyString(logPath); ulDestroyString(logPath);
+1
View File
@@ -1,5 +1,6 @@
using System; using System;
using GlitchyEngine.Events; using GlitchyEngine.Events;
using GlitchyEngine.UI;
using GlitchyEngine.ImGui; using GlitchyEngine.ImGui;
using GlitchyEngine.Renderer; using GlitchyEngine.Renderer;
using GlitchyEngine.Debug; using GlitchyEngine.Debug;
@@ -8,6 +8,7 @@ using System;
using System.Interop; using System.Interop;
using GlitchyEngine.Events; using GlitchyEngine.Events;
using GlitchyEngine.Math; using GlitchyEngine.Math;
using GlitchyEngine.UI;
using static System.Windows; using static System.Windows;
@@ -15,7 +15,7 @@ using static System.Windows;
using internal GlitchyEngine; using internal GlitchyEngine;
namespace GlitchyEngine namespace GlitchyEngine.UI
{ {
/// The windows specific Window implementation /// The windows specific Window implementation
public extension Window public extension Window
@@ -38,6 +38,8 @@ namespace GlitchyEngine
private bool _isActive; private bool _isActive;
private HCURSOR _cursor;
public override int32 MinWidth public override int32 MinWidth
{ {
get => _minMaxInfo.MinimumTrackingSize.x; get => _minMaxInfo.MinimumTrackingSize.x;
@@ -228,6 +230,9 @@ namespace GlitchyEngine
} }
} }
[LinkName(.C)]
static extern Windows.IntBool SetLayeredWindowAttributes(HWND hwnd, uint32 crKey, uint8 bAlpha, DWORD dwFlags);
private void Init(WindowDescription desc) private void Init(WindowDescription desc)
{ {
Debug.Profiler.ProfileFunction!(); Debug.Profiler.ProfileFunction!();
@@ -242,7 +247,18 @@ namespace GlitchyEngine
{ {
Debug.Profiler.ProfileScope!("CreateWindow"); Debug.Profiler.ProfileScope!("CreateWindow");
_windowHandle = CreateWindowExW(.None, WindowClass.ClassName, desc.Title.ToScopedNativeWChar!(), .WS_OVERLAPPEDWINDOW | .WS_VISIBLE, DirectX.Windows.WindowStyles style = .WS_VISIBLE;
switch (desc.WindowStyle)
{
case .Normal:
style |= .WS_OVERLAPPEDWINDOW | .WS_VISIBLE;
case .Borderless:
style |= .WS_POPUP | .WS_THICKFRAME | .WS_CAPTION | .WS_SYSMENU | .WS_MAXIMIZEBOX | .WS_MINIMIZEBOX;
}
_windowHandle = CreateWindowExW(.None, WindowClass.ClassName, desc.Title.ToScopedNativeWChar!(),
style,
CW_USEDEFAULT, CW_USEDEFAULT, desc.Width, desc.Height, 0, 0, (.)_instanceHandle, null); CW_USEDEFAULT, CW_USEDEFAULT, desc.Width, desc.Height, 0, 0, (.)_instanceHandle, null);
} }
@@ -522,6 +538,14 @@ namespace GlitchyEngine
delete window._title; delete window._title;
window._title = null; window._title = null;
} }
case WM_SETCURSOR:
if (GetLowOrder(lParam) == /*HTCLIENT*/ 1)
{
Winuser.SetCursor(window._cursor);
return 1;
}
break;
case WM_SYSCOMMAND: case WM_SYSCOMMAND:
{ {
/* Remove beeping sound when ALT + some key is pressed. */ /* Remove beeping sound when ALT + some key is pressed. */
@@ -609,6 +633,120 @@ namespace GlitchyEngine
_title = new String(titleSpan); _title = new String(titleSpan);
} }
public override Result<void> SetCursor(CursorImage cursorImage)
{
LPCTSTR cursor = null;
// Firefox cursors: https://hg.mozilla.org/mozilla-central/file/tip/widget/windows/res
switch (cursorImage)
{
case .Pointer:
cursor = Winuser.IDC_ARROW;
case .Crosshair:
cursor = Winuser.IDC_CROSS;
case .Hand:
cursor = Winuser.IDC_HAND;
case .IBeam:
cursor = Winuser.IDC_IBEAM;
case .Wait:
cursor = Winuser.IDC_WAIT;
case .Help:
cursor = Winuser.IDC_HELP;
case .ResizeEastWest:
cursor = Winuser.IDC_SIZEWE;
case .ResizeNorthSouth:
cursor = Winuser.IDC_SIZENS;
case .ResizeNorthEastSouthWest:
cursor = Winuser.IDC_SIZENESW;
case .ResizeNorthWestSouthEast:
cursor = Winuser.IDC_SIZENWSE;
case .ResizeColumn:
// TODO use cursor file
cursor = Winuser.IDC_SIZEWE;
case .ResizeRow:
// TODO use cursor file
cursor = Winuser.IDC_SIZENS;
case .PanMiddle:
cursor = Winuser.MAKEINTRESOURCEW(32654);
case .PanEast:
cursor = Winuser.MAKEINTRESOURCEW(32658);
case .PanWest:
cursor = Winuser.MAKEINTRESOURCEW(32657);
case .PanNorth:
cursor = Winuser.MAKEINTRESOURCEW(32655);
case .PanSouth:
cursor = Winuser.MAKEINTRESOURCEW(32656);
case .PanNorthEast:
cursor = Winuser.MAKEINTRESOURCEW(32660);
case .PanNorthWest:
cursor = Winuser.MAKEINTRESOURCEW(32659);
case .PanSouthEast:
cursor = Winuser.MAKEINTRESOURCEW(32662);
case .PanSouthWest:
cursor = Winuser.MAKEINTRESOURCEW(32661);
case .Move:
cursor = Winuser.IDC_SIZEALL;
case .VerticalText:
// TODO
case .Cell:
// TODO
case .ContextMenu:
// TODO
case .Alias:
// TODO
case .Progress:
cursor = Winuser.IDC_APPSTARTING;
case .NotAllowed:
cursor = Winuser.IDC_NO;
case .Copy:
// TODO
case .None:
cursor = null;
case .ZoomIn:
// TODO
case .ZoomOut:
case .Grab:
// TODO
case .Grabbing:
// TODO
case .Custom:
// TODO: Use cursor file specified by user
}
var hCursor = Winuser.LoadCursorW((.)0, cursor);
_cursor = hCursor;
Winuser.SetCursor(hCursor);
return .Ok;
}
} }
} }
@@ -1,6 +1,7 @@
using System; using System;
using GlitchyEngine.Core; using GlitchyEngine.Core;
using GlitchyEngine.Math; using GlitchyEngine.Math;
using GlitchyEngine.UI;
namespace GlitchyEngine.Renderer namespace GlitchyEngine.Renderer
{ {
+2
View File
@@ -1,3 +1,5 @@
using GlitchyEngine.UI;
namespace GlitchyEngine.Renderer namespace GlitchyEngine.Renderer
{ {
public class SwapChain public class SwapChain
+48
View File
@@ -0,0 +1,48 @@
namespace GlitchyEngine.UI;
enum CursorImage
{
None,
Pointer,
Crosshair,
Hand,
IBeam,
Wait,
Help,
ResizeEastWest,
ResizeNorthSouth,
ResizeNorthEastSouthWest,
ResizeNorthWestSouthEast,
ResizeColumn,
ResizeRow,
PanMiddle,
PanNorth,
PanNorthEast,
PanNorthWest,
PanSouth,
PanSouthEast,
PanSouthWest,
PanEast,
PanWest,
Move,
VerticalText,
Cell,
ContextMenu,
Alias,
Progress,
NotAllowed,
Copy,
ZoomIn,
ZoomOut,
Grab,
Grabbing,
Custom
}
@@ -3,23 +3,31 @@ using GlitchyEngine.Events;
using GlitchyEngine.Math; using GlitchyEngine.Math;
using GlitchyEngine.Renderer; using GlitchyEngine.Renderer;
namespace GlitchyEngine namespace GlitchyEngine.UI
{ {
enum WindowStyle
{
Normal,
Borderless
}
public struct WindowDescription public struct WindowDescription
{ {
public uint32 Width; public uint32 Width;
public uint32 Height; public uint32 Height;
public StringView Title; public StringView Title;
public StringView Icon; public StringView Icon;
public WindowStyle WindowStyle;
public this() => this = default; public this() => this = default;
public this(uint32 width, uint32 height, StringView title, StringView icon = default) public this(uint32 width, uint32 height, StringView title, StringView icon = default, WindowStyle windowStyle = .Normal)
{ {
Width = width; Width = width;
Height = height; Height = height;
Title = title; Title = title;
Icon = icon; Icon = icon;
WindowStyle = windowStyle;
} }
public static readonly WindowDescription Default => .(1280, 720, "Glitchy Engine") public static readonly WindowDescription Default => .(1280, 720, "Glitchy Engine")
@@ -119,6 +127,8 @@ namespace GlitchyEngine
*/ */
public extern Result<void> SetIcon(StringView filePath); public extern Result<void> SetIcon(StringView filePath);
public extern Result<void> SetCursor(CursorImage cursorImage);
private void DefaultEventHandler(Event e) private void DefaultEventHandler(Event e)
{ {
Log.EngineLogger.Error($"No event handler registered for window."); Log.EngineLogger.Error($"No event handler registered for window.");