Refactor widowing on macOS to support screen scale and highDpi mode
This commit is contained in:
@@ -125,9 +125,12 @@ namespace FlaxEditor.Options
|
|||||||
options.CustomSettings.Add(e.Key, JsonSerializer.Serialize(e.Value()));
|
options.CustomSettings.Add(e.Key, JsonSerializer.Serialize(e.Value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float prevInterfaceScale = Options.Interface.InterfaceScale;
|
||||||
Options = options;
|
Options = options;
|
||||||
OnOptionsChanged();
|
OnOptionsChanged();
|
||||||
Platform.CustomDpiScale = Options.Interface.InterfaceScale;
|
|
||||||
|
// Scale interface relative to the current value (eg. when using system-provided Dpi Scale)
|
||||||
|
Platform.CustomDpiScale *= Options.Interface.InterfaceScale / prevInterfaceScale;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ void SplashScreen::Show()
|
|||||||
LOG(Info, "Showing splash screen");
|
LOG(Info, "Showing splash screen");
|
||||||
|
|
||||||
// Create window
|
// Create window
|
||||||
const float dpiScale = (float)Platform::GetDpi() / (float)DefaultDPI;
|
const float dpiScale = Platform::GetDpiScale();
|
||||||
CreateWindowSettings settings;
|
CreateWindowSettings settings;
|
||||||
settings.Title = TEXT("Flax Editor");
|
settings.Title = TEXT("Flax Editor");
|
||||||
settings.Size.X = 500 * dpiScale;
|
settings.Size.X = 500 * dpiScale;
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ String UserLocale, ComputerName;
|
|||||||
double SecondsPerCycle;
|
double SecondsPerCycle;
|
||||||
NSAutoreleasePool* AutoreleasePool = nullptr;
|
NSAutoreleasePool* AutoreleasePool = nullptr;
|
||||||
|
|
||||||
|
float MacPlatform::ScreenScale = 1.0f;
|
||||||
|
|
||||||
String MacUtils::ToString(CFStringRef str)
|
String MacUtils::ToString(CFStringRef str)
|
||||||
{
|
{
|
||||||
if (!str)
|
if (!str)
|
||||||
@@ -77,7 +79,7 @@ CFStringRef MacUtils::ToString(const StringView& str)
|
|||||||
Float2 MacUtils::PosToCoca(const Float2& pos)
|
Float2 MacUtils::PosToCoca(const Float2& pos)
|
||||||
{
|
{
|
||||||
// MacOS uses y-coordinate starting at the bottom of the screen
|
// MacOS uses y-coordinate starting at the bottom of the screen
|
||||||
Float2 result = pos;
|
Float2 result = pos;// / MacPlatform::ScreenScale;
|
||||||
result.Y *= -1;
|
result.Y *= -1;
|
||||||
result += GetScreensOrigin();
|
result += GetScreensOrigin();
|
||||||
return result;
|
return result;
|
||||||
@@ -86,10 +88,10 @@ Float2 MacUtils::PosToCoca(const Float2& pos)
|
|||||||
Float2 MacUtils::CocaToPos(const Float2& pos)
|
Float2 MacUtils::CocaToPos(const Float2& pos)
|
||||||
{
|
{
|
||||||
// MacOS uses y-coordinate starting at the bottom of the screen
|
// MacOS uses y-coordinate starting at the bottom of the screen
|
||||||
Float2 result = pos;
|
Float2 result = pos;// * MacPlatform::ScreenScale;
|
||||||
result -= GetScreensOrigin();
|
result -= GetScreensOrigin();
|
||||||
result.Y *= -1;
|
result.Y *= -1;
|
||||||
return result;
|
return result;// * MacPlatform::ScreenScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
Float2 MacUtils::GetScreensOrigin()
|
Float2 MacUtils::GetScreensOrigin()
|
||||||
@@ -100,6 +102,7 @@ Float2 MacUtils::GetScreensOrigin()
|
|||||||
{
|
{
|
||||||
NSRect rect = [[screenArray objectAtIndex:i] frame];
|
NSRect rect = [[screenArray objectAtIndex:i] frame];
|
||||||
Float2 pos(rect.origin.x, rect.origin.y + rect.size.height);
|
Float2 pos(rect.origin.x, rect.origin.y + rect.size.height);
|
||||||
|
pos *= MacPlatform::ScreenScale;
|
||||||
if (pos.X < result.X)
|
if (pos.X < result.X)
|
||||||
result.X = pos.X;
|
result.X = pos.X;
|
||||||
if (pos.Y > result.Y)
|
if (pos.Y > result.Y)
|
||||||
@@ -423,11 +426,25 @@ bool MacPlatform::Init()
|
|||||||
OnPlatformUserAdd(New<User>(username));
|
OnPlatformUserAdd(New<User>(username));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the maximum scale of the display to handle high-dpi displays scaling factor
|
||||||
|
{
|
||||||
|
NSArray* screenArray = [NSScreen screens];
|
||||||
|
for (int32 i = 0; i < (int32)[screenArray count]; i++)
|
||||||
|
{
|
||||||
|
if ([[screenArray objectAtIndex:i] respondsToSelector:@selector(backingScaleFactor)])
|
||||||
|
{
|
||||||
|
ScreenScale = Math::Max(ScreenScale, (float)[[screenArray objectAtIndex:i] backingScaleFactor]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CustomDpiScale *= ScreenScale;
|
||||||
|
}
|
||||||
|
|
||||||
// Init application
|
// Init application
|
||||||
[NSApplication sharedApplication];
|
[NSApplication sharedApplication];
|
||||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||||
NSMenu* mainMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
|
NSMenu* mainMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
|
||||||
[NSApp setMainMenu:mainMenu];
|
[NSApp setMainMenu:mainMenu];
|
||||||
|
// TODO: expose main menu for app (eg. to be used by Game or Editor on macOS-only)
|
||||||
AutoreleasePool = [[NSAutoreleasePool alloc] init];
|
AutoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
Input::Mouse = New<MacMouse>();
|
Input::Mouse = New<MacMouse>();
|
||||||
@@ -479,6 +496,16 @@ void MacPlatform::Exit()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacPlatform::SetHighDpiAwarenessEnabled(bool enable)
|
||||||
|
{
|
||||||
|
// Disable resolution scaling in low dpi mode
|
||||||
|
if (!enable)
|
||||||
|
{
|
||||||
|
CustomDpiScale /= ScreenScale;
|
||||||
|
ScreenScale = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int32 MacPlatform::GetDpi()
|
int32 MacPlatform::GetDpi()
|
||||||
{
|
{
|
||||||
CGDirectDisplayID mainDisplay = CGMainDisplayID();
|
CGDirectDisplayID mainDisplay = CGMainDisplayID();
|
||||||
@@ -551,13 +578,14 @@ void MacPlatform::SetMousePosition(const Float2& pos)
|
|||||||
Float2 MacPlatform::GetDesktopSize()
|
Float2 MacPlatform::GetDesktopSize()
|
||||||
{
|
{
|
||||||
CGDirectDisplayID mainDisplay = CGMainDisplayID();
|
CGDirectDisplayID mainDisplay = CGMainDisplayID();
|
||||||
return Float2((float)CGDisplayPixelsWide(mainDisplay), (float)CGDisplayPixelsHigh(mainDisplay));
|
return Float2((float)CGDisplayPixelsWide(mainDisplay) * ScreenScale, (float)CGDisplayPixelsHigh(mainDisplay) * ScreenScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle GetDisplayBounds(CGDirectDisplayID display)
|
Rectangle GetDisplayBounds(CGDirectDisplayID display)
|
||||||
{
|
{
|
||||||
CGRect rect = CGDisplayBounds(display);
|
CGRect rect = CGDisplayBounds(display);
|
||||||
return Rectangle(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
float screnScale = MacPlatform::ScreenScale;
|
||||||
|
return Rectangle(rect.origin.x * screnScale, rect.origin.y * screnScale, rect.size.width * screnScale, rect.size.height * screnScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle MacPlatform::GetMonitorBounds(const Float2& screenPos)
|
Rectangle MacPlatform::GetMonitorBounds(const Float2& screenPos)
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class FLAXENGINE_API MacPlatform : public UnixPlatform
|
class FLAXENGINE_API MacPlatform : public UnixPlatform
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
static float ScreenScale;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// [UnixPlatform]
|
// [UnixPlatform]
|
||||||
@@ -82,6 +85,7 @@ public:
|
|||||||
static void Tick();
|
static void Tick();
|
||||||
static void BeforeExit();
|
static void BeforeExit();
|
||||||
static void Exit();
|
static void Exit();
|
||||||
|
static void SetHighDpiAwarenessEnabled(bool enable);
|
||||||
static int32 GetDpi();
|
static int32 GetDpi();
|
||||||
static String GetUserLocaleName();
|
static String GetUserLocaleName();
|
||||||
static String GetComputerName();
|
static String GetComputerName();
|
||||||
|
|||||||
@@ -167,14 +167,14 @@ Float2 GetWindowTitleSize(const MacWindow* window)
|
|||||||
NSRect frameStart = [(NSWindow*)window->GetNativePtr() frameRectForContentRect:NSMakeRect(0, 0, 0, 0)];
|
NSRect frameStart = [(NSWindow*)window->GetNativePtr() frameRectForContentRect:NSMakeRect(0, 0, 0, 0)];
|
||||||
size.Y = frameStart.size.height;
|
size.Y = frameStart.size.height;
|
||||||
}
|
}
|
||||||
return size;
|
return size * MacPlatform::ScreenScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
Float2 GetMousePosition(MacWindow* window, NSEvent* event)
|
Float2 GetMousePosition(MacWindow* window, NSEvent* event)
|
||||||
{
|
{
|
||||||
NSRect frame = [(NSWindow*)window->GetNativePtr() frame];
|
NSRect frame = [(NSWindow*)window->GetNativePtr() frame];
|
||||||
NSPoint point = [event locationInWindow];
|
NSPoint point = [event locationInWindow];
|
||||||
return Float2(point.x, frame.size.height - point.y) - GetWindowTitleSize(window);
|
return Float2(point.x, frame.size.height - point.y) * MacPlatform::ScreenScale - GetWindowTitleSize(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MacDropData : public IGuiData
|
class MacDropData : public IGuiData
|
||||||
@@ -255,17 +255,45 @@ NSDragOperation GetDragDropOperation(DragDropEffect dragDropEffect)
|
|||||||
|
|
||||||
@implementation MacWindowImpl
|
@implementation MacWindowImpl
|
||||||
|
|
||||||
|
- (void)windowDidBecomeKey:(NSNotification*)notification
|
||||||
|
{
|
||||||
|
// Handle resizing to be sure that content has valid size when window was resized
|
||||||
|
[self windowDidResize:notification];
|
||||||
|
|
||||||
|
Window->OnGotFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidResignKey:(NSNotification*)notification
|
||||||
|
{
|
||||||
|
Window->OnLostFocus();
|
||||||
|
}
|
||||||
|
|
||||||
- (void)windowWillClose:(NSNotification*)notification
|
- (void)windowWillClose:(NSNotification*)notification
|
||||||
{
|
{
|
||||||
[self setDelegate: nil];
|
[self setDelegate: nil];
|
||||||
Window->Close(ClosingReason::User);
|
Window->Close(ClosingReason::User);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
||||||
|
{
|
||||||
|
r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)windowDidResize:(NSNotification*)notification
|
- (void)windowDidResize:(NSNotification*)notification
|
||||||
{
|
{
|
||||||
NSView* view = [self contentView];
|
NSView* view = [self contentView];
|
||||||
NSRect contextRect = [view frame];
|
const float screenScale = MacPlatform::ScreenScale;
|
||||||
Window->CheckForResize((float)contextRect.size.width, (float)contextRect.size.height);
|
NSWindow* nswindow = (NSWindow*)Window->GetNativePtr();
|
||||||
|
NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
|
||||||
|
ConvertNSRect([nswindow screen], &rect);
|
||||||
|
|
||||||
|
// Rescale contents
|
||||||
|
CALayer* layer = [view layer];
|
||||||
|
if (layer)
|
||||||
|
layer.contentsScale = screenScale;
|
||||||
|
|
||||||
|
// Resize window
|
||||||
|
Window->CheckForResize((float)rect.size.width * screenScale, (float)rect.size.height * screenScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setWindow:(MacWindow*)window
|
- (void)setWindow:(MacWindow*)window
|
||||||
@@ -565,6 +593,12 @@ MacWindow::MacWindow(const CreateWindowSettings& settings)
|
|||||||
styleMask &= ~NSWindowStyleMaskFullSizeContentView;
|
styleMask &= ~NSWindowStyleMaskFullSizeContentView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const float screenScale = MacPlatform::ScreenScale;
|
||||||
|
frame.origin.x /= screenScale;
|
||||||
|
frame.origin.y /= screenScale;
|
||||||
|
frame.size.width /= screenScale;
|
||||||
|
frame.size.height /= screenScale;
|
||||||
|
|
||||||
MacWindowImpl* window = [[MacWindowImpl alloc] initWithContentRect:frame
|
MacWindowImpl* window = [[MacWindowImpl alloc] initWithContentRect:frame
|
||||||
styleMask:(styleMask)
|
styleMask:(styleMask)
|
||||||
backing:NSBackingStoreBuffered
|
backing:NSBackingStoreBuffered
|
||||||
@@ -587,6 +621,11 @@ MacWindow::MacWindow(const CreateWindowSettings& settings)
|
|||||||
[view registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
|
[view registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rescale contents
|
||||||
|
CALayer* layer = [view layer];
|
||||||
|
if (layer)
|
||||||
|
layer.contentsScale = screenScale;
|
||||||
|
|
||||||
// TODO: impl Parent for MacWindow
|
// TODO: impl Parent for MacWindow
|
||||||
// TODO: impl StartPosition for MacWindow
|
// TODO: impl StartPosition for MacWindow
|
||||||
// TODO: impl Fullscreen for MacWindow
|
// TODO: impl Fullscreen for MacWindow
|
||||||
@@ -618,17 +657,19 @@ void MacWindow::SetIsMouseOver(bool value)
|
|||||||
if (_isMouseOver == value)
|
if (_isMouseOver == value)
|
||||||
return;
|
return;
|
||||||
_isMouseOver = value;
|
_isMouseOver = value;
|
||||||
|
CursorType cursor = _cursor;
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
// Refresh cursor typet
|
// Refresh cursor typet
|
||||||
SetCursor(_cursor);
|
SetCursor(CursorType::Default);
|
||||||
|
SetCursor(cursor);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Input::Mouse->OnMouseLeave(this);
|
Input::Mouse->OnMouseLeave(this);
|
||||||
if (_cursor == CursorType::Hidden)
|
SetCursor(CursorType::Default);
|
||||||
[NSCursor unhide];
|
_cursor = cursor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,6 +706,8 @@ void MacWindow::Hide()
|
|||||||
{
|
{
|
||||||
if (_visible)
|
if (_visible)
|
||||||
{
|
{
|
||||||
|
SetCursor(CursorType::Default);
|
||||||
|
|
||||||
// Hide
|
// Hide
|
||||||
NSWindow* window = (NSWindow*)_window;
|
NSWindow* window = (NSWindow*)_window;
|
||||||
[window orderOut:nil];
|
[window orderOut:nil];
|
||||||
@@ -710,7 +753,7 @@ bool MacWindow::IsClosed() const
|
|||||||
|
|
||||||
bool MacWindow::IsForegroundWindow() const
|
bool MacWindow::IsForegroundWindow() const
|
||||||
{
|
{
|
||||||
return Platform::GetHasFocus();
|
return Platform::GetHasFocus() && IsFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacWindow::BringToFront(bool force)
|
void MacWindow::BringToFront(bool force)
|
||||||
@@ -749,7 +792,7 @@ void MacWindow::SetPosition(const Float2& position)
|
|||||||
NSWindow* window = (NSWindow*)_window;
|
NSWindow* window = (NSWindow*)_window;
|
||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
Float2 pos = MacUtils::PosToCoca(position);
|
Float2 pos = MacUtils::PosToCoca(position) / MacPlatform::ScreenScale;
|
||||||
NSRect rect = [window frame];
|
NSRect rect = [window frame];
|
||||||
[window setFrameOrigin:NSMakePoint(pos.X, pos.Y - rect.size.height)];
|
[window setFrameOrigin:NSMakePoint(pos.X, pos.Y - rect.size.height)];
|
||||||
}
|
}
|
||||||
@@ -760,7 +803,7 @@ Float2 MacWindow::GetPosition() const
|
|||||||
if (!window)
|
if (!window)
|
||||||
return Float2::Zero;
|
return Float2::Zero;
|
||||||
NSRect rect = [window frame];
|
NSRect rect = [window frame];
|
||||||
return MacUtils::CocaToPos(Float2(rect.origin.x, rect.origin.y + rect.size.height));
|
return MacUtils::CocaToPos(Float2(rect.origin.x, rect.origin.y + rect.size.height) * MacPlatform::ScreenScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
Float2 MacWindow::GetSize() const
|
Float2 MacWindow::GetSize() const
|
||||||
@@ -769,7 +812,7 @@ Float2 MacWindow::GetSize() const
|
|||||||
if (!window)
|
if (!window)
|
||||||
return Float2::Zero;
|
return Float2::Zero;
|
||||||
NSRect rect = [window frame];
|
NSRect rect = [window frame];
|
||||||
return Float2(rect.size.width, rect.size.height);
|
return Float2(rect.size.width, rect.size.height) * MacPlatform::ScreenScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
Float2 MacWindow::GetClientSize() const
|
Float2 MacWindow::GetClientSize() const
|
||||||
@@ -836,6 +879,9 @@ DragDropEffect MacWindow::DoDragDrop(const StringView& data)
|
|||||||
|
|
||||||
void MacWindow::SetCursor(CursorType type)
|
void MacWindow::SetCursor(CursorType type)
|
||||||
{
|
{
|
||||||
|
CursorType prev = _cursor;
|
||||||
|
if (prev == type)
|
||||||
|
return;
|
||||||
WindowBase::SetCursor(type);
|
WindowBase::SetCursor(type);
|
||||||
//if (!_isMouseOver)
|
//if (!_isMouseOver)
|
||||||
// return;
|
// return;
|
||||||
@@ -874,8 +920,11 @@ void MacWindow::SetCursor(CursorType type)
|
|||||||
}
|
}
|
||||||
if (cursor)
|
if (cursor)
|
||||||
{
|
{
|
||||||
|
if (prev == CursorType::Hidden)
|
||||||
|
{
|
||||||
|
[NSCursor unhide];
|
||||||
|
}
|
||||||
[cursor set];
|
[cursor set];
|
||||||
[NSCursor unhide];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user