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()));
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user