diff --git a/Source/Editor/Options/OptionsModule.cs b/Source/Editor/Options/OptionsModule.cs index b82ad38cc..68aa11626 100644 --- a/Source/Editor/Options/OptionsModule.cs +++ b/Source/Editor/Options/OptionsModule.cs @@ -125,9 +125,12 @@ namespace FlaxEditor.Options options.CustomSettings.Add(e.Key, JsonSerializer.Serialize(e.Value())); } + float prevInterfaceScale = Options.Interface.InterfaceScale; Options = options; 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 { diff --git a/Source/Editor/Windows/SplashScreen.cpp b/Source/Editor/Windows/SplashScreen.cpp index 649f0bcff..c8424ba82 100644 --- a/Source/Editor/Windows/SplashScreen.cpp +++ b/Source/Editor/Windows/SplashScreen.cpp @@ -153,7 +153,7 @@ void SplashScreen::Show() LOG(Info, "Showing splash screen"); // Create window - const float dpiScale = (float)Platform::GetDpi() / (float)DefaultDPI; + const float dpiScale = Platform::GetDpiScale(); CreateWindowSettings settings; settings.Title = TEXT("Flax Editor"); settings.Size.X = 500 * dpiScale; diff --git a/Source/Engine/Platform/Mac/MacPlatform.cpp b/Source/Engine/Platform/Mac/MacPlatform.cpp index ab0efedac..6a3cab196 100644 --- a/Source/Engine/Platform/Mac/MacPlatform.cpp +++ b/Source/Engine/Platform/Mac/MacPlatform.cpp @@ -54,6 +54,8 @@ String UserLocale, ComputerName; double SecondsPerCycle; NSAutoreleasePool* AutoreleasePool = nullptr; +float MacPlatform::ScreenScale = 1.0f; + String MacUtils::ToString(CFStringRef str) { if (!str) @@ -77,7 +79,7 @@ CFStringRef MacUtils::ToString(const StringView& str) Float2 MacUtils::PosToCoca(const Float2& pos) { // MacOS uses y-coordinate starting at the bottom of the screen - Float2 result = pos; + Float2 result = pos;// / MacPlatform::ScreenScale; result.Y *= -1; result += GetScreensOrigin(); return result; @@ -86,10 +88,10 @@ Float2 MacUtils::PosToCoca(const Float2& pos) Float2 MacUtils::CocaToPos(const Float2& pos) { // MacOS uses y-coordinate starting at the bottom of the screen - Float2 result = pos; + Float2 result = pos;// * MacPlatform::ScreenScale; result -= GetScreensOrigin(); result.Y *= -1; - return result; + return result;// * MacPlatform::ScreenScale; } Float2 MacUtils::GetScreensOrigin() @@ -100,6 +102,7 @@ Float2 MacUtils::GetScreensOrigin() { NSRect rect = [[screenArray objectAtIndex:i] frame]; Float2 pos(rect.origin.x, rect.origin.y + rect.size.height); + pos *= MacPlatform::ScreenScale; if (pos.X < result.X) result.X = pos.X; if (pos.Y > result.Y) @@ -423,11 +426,25 @@ bool MacPlatform::Init() OnPlatformUserAdd(New(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 [NSApplication sharedApplication]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; NSMenu* mainMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; [NSApp setMainMenu:mainMenu]; + // TODO: expose main menu for app (eg. to be used by Game or Editor on macOS-only) AutoreleasePool = [[NSAutoreleasePool alloc] init]; Input::Mouse = New(); @@ -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() { CGDirectDisplayID mainDisplay = CGMainDisplayID(); @@ -551,13 +578,14 @@ void MacPlatform::SetMousePosition(const Float2& pos) Float2 MacPlatform::GetDesktopSize() { 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) { 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) diff --git a/Source/Engine/Platform/Mac/MacPlatform.h b/Source/Engine/Platform/Mac/MacPlatform.h index 0a837fe03..074fb3871 100644 --- a/Source/Engine/Platform/Mac/MacPlatform.h +++ b/Source/Engine/Platform/Mac/MacPlatform.h @@ -11,6 +11,9 @@ /// class FLAXENGINE_API MacPlatform : public UnixPlatform { +public: + static float ScreenScale; + public: // [UnixPlatform] @@ -82,6 +85,7 @@ public: static void Tick(); static void BeforeExit(); static void Exit(); + static void SetHighDpiAwarenessEnabled(bool enable); static int32 GetDpi(); static String GetUserLocaleName(); static String GetComputerName(); diff --git a/Source/Engine/Platform/Mac/MacWindow.cpp b/Source/Engine/Platform/Mac/MacWindow.cpp index 61a811b75..3f88eb9b9 100644 --- a/Source/Engine/Platform/Mac/MacWindow.cpp +++ b/Source/Engine/Platform/Mac/MacWindow.cpp @@ -167,14 +167,14 @@ Float2 GetWindowTitleSize(const MacWindow* window) NSRect frameStart = [(NSWindow*)window->GetNativePtr() frameRectForContentRect:NSMakeRect(0, 0, 0, 0)]; size.Y = frameStart.size.height; } - return size; + return size * MacPlatform::ScreenScale; } Float2 GetMousePosition(MacWindow* window, NSEvent* event) { NSRect frame = [(NSWindow*)window->GetNativePtr() frame]; 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 @@ -255,17 +255,45 @@ NSDragOperation GetDragDropOperation(DragDropEffect dragDropEffect) @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 { [self setDelegate: nil]; 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 { NSView* view = [self contentView]; - NSRect contextRect = [view frame]; - Window->CheckForResize((float)contextRect.size.width, (float)contextRect.size.height); + const float screenScale = MacPlatform::ScreenScale; + 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 @@ -565,6 +593,12 @@ MacWindow::MacWindow(const CreateWindowSettings& settings) 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 styleMask:(styleMask) backing:NSBackingStoreBuffered @@ -587,6 +621,11 @@ MacWindow::MacWindow(const CreateWindowSettings& settings) [view registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]]; } + // Rescale contents + CALayer* layer = [view layer]; + if (layer) + layer.contentsScale = screenScale; + // TODO: impl Parent for MacWindow // TODO: impl StartPosition for MacWindow // TODO: impl Fullscreen for MacWindow @@ -618,17 +657,19 @@ void MacWindow::SetIsMouseOver(bool value) if (_isMouseOver == value) return; _isMouseOver = value; + CursorType cursor = _cursor; if (value) { // Refresh cursor typet - SetCursor(_cursor); + SetCursor(CursorType::Default); + SetCursor(cursor); } else { Input::Mouse->OnMouseLeave(this); - if (_cursor == CursorType::Hidden) - [NSCursor unhide]; + SetCursor(CursorType::Default); + _cursor = cursor; } } @@ -665,6 +706,8 @@ void MacWindow::Hide() { if (_visible) { + SetCursor(CursorType::Default); + // Hide NSWindow* window = (NSWindow*)_window; [window orderOut:nil]; @@ -710,7 +753,7 @@ bool MacWindow::IsClosed() const bool MacWindow::IsForegroundWindow() const { - return Platform::GetHasFocus(); + return Platform::GetHasFocus() && IsFocused(); } void MacWindow::BringToFront(bool force) @@ -749,7 +792,7 @@ void MacWindow::SetPosition(const Float2& position) NSWindow* window = (NSWindow*)_window; if (!window) return; - Float2 pos = MacUtils::PosToCoca(position); + Float2 pos = MacUtils::PosToCoca(position) / MacPlatform::ScreenScale; NSRect rect = [window frame]; [window setFrameOrigin:NSMakePoint(pos.X, pos.Y - rect.size.height)]; } @@ -760,7 +803,7 @@ Float2 MacWindow::GetPosition() const if (!window) return Float2::Zero; 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 @@ -769,7 +812,7 @@ Float2 MacWindow::GetSize() const if (!window) return Float2::Zero; 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 @@ -836,6 +879,9 @@ DragDropEffect MacWindow::DoDragDrop(const StringView& data) void MacWindow::SetCursor(CursorType type) { + CursorType prev = _cursor; + if (prev == type) + return; WindowBase::SetCursor(type); //if (!_isMouseOver) // return; @@ -874,8 +920,11 @@ void MacWindow::SetCursor(CursorType type) } if (cursor) { + if (prev == CursorType::Hidden) + { + [NSCursor unhide]; + } [cursor set]; - [NSCursor unhide]; } }