Refactor widowing on macOS to support screen scale and highDpi mode

This commit is contained in:
Wojtek Figat
2023-03-12 10:58:55 +01:00
parent 9fe54dc02c
commit 2c70b74814
5 changed files with 103 additions and 19 deletions

View File

@@ -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
{

View File

@@ -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;

View File

@@ -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<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
[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<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()
{
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)

View File

@@ -11,6 +11,9 @@
/// </summary>
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();

View File

@@ -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];
}
}