csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
6.3 KiB
197 lines
6.3 KiB
using System;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Input.Raw;
|
|
using Avalonia.Platform;
|
|
using MonoMac.AppKit;
|
|
using MonoMac.CoreGraphics;
|
|
using MonoMac.Foundation;
|
|
using MonoMac.ObjCRuntime;
|
|
|
|
namespace Avalonia.MonoMac
|
|
{
|
|
class WindowBaseImpl : TopLevelImpl, IWindowBaseImpl
|
|
{
|
|
private readonly ManagedWindowResizeDragHelper _managedDrag;
|
|
public CustomWindow Window { get; private set; }
|
|
|
|
public WindowBaseImpl()
|
|
{
|
|
_managedDrag = new ManagedWindowResizeDragHelper(this, _ => { }, ResizeForManagedDrag);
|
|
Window = new CustomWindow(this)
|
|
{
|
|
StyleMask = NSWindowStyle.Titled,
|
|
BackingType = NSBackingStore.Buffered,
|
|
ContentView = View,
|
|
// ReSharper disable once VirtualMemberCallInConstructor
|
|
Delegate = CreateWindowDelegate()
|
|
};
|
|
}
|
|
|
|
public class CustomWindow : NSWindow
|
|
{
|
|
readonly WindowBaseImpl _impl;
|
|
|
|
public CustomWindow(WindowBaseImpl impl)
|
|
{
|
|
_impl = impl;
|
|
}
|
|
|
|
public override void BecomeKeyWindow()
|
|
{
|
|
_impl.Activated?.Invoke();
|
|
base.BecomeKeyWindow();
|
|
}
|
|
|
|
public override void ResignKeyWindow()
|
|
{
|
|
_impl.Deactivated?.Invoke();
|
|
base.ResignKeyWindow();
|
|
}
|
|
|
|
private bool _canBecomeKeyAndMain;
|
|
public override bool CanBecomeKeyWindow => _canBecomeKeyAndMain;
|
|
public override bool CanBecomeMainWindow => _canBecomeKeyAndMain;
|
|
|
|
public void SetCanBecomeKeyAndMain() => _canBecomeKeyAndMain = true;
|
|
}
|
|
|
|
protected virtual NSWindowDelegate CreateWindowDelegate() => new WindowBaseDelegate(this);
|
|
|
|
public class WindowBaseDelegate : NSWindowDelegate
|
|
{
|
|
readonly WindowBaseImpl _impl;
|
|
public WindowBaseDelegate(WindowBaseImpl impl)
|
|
{
|
|
_impl = impl;
|
|
}
|
|
|
|
public override void DidMoved(global::MonoMac.Foundation.NSNotification notification)
|
|
{
|
|
_impl.PositionChanged?.Invoke(_impl.Position);
|
|
}
|
|
|
|
public override bool WindowShouldClose(NSObject sender)
|
|
{
|
|
bool? preventClose = _impl.Closing?.Invoke();
|
|
return preventClose != true;
|
|
}
|
|
|
|
public override void WillClose(global::MonoMac.Foundation.NSNotification notification)
|
|
{
|
|
_impl.Window.Dispose();
|
|
_impl.Window = null;
|
|
_impl.Dispose();
|
|
}
|
|
|
|
public override CGRect WillUseStandardFrame(NSWindow window, CGRect newFrame)
|
|
{
|
|
if (_impl is WindowImpl w && w.UndecoratedIsMaximized && w.UndecoratedLastUnmaximizedFrame.HasValue)
|
|
return w.UndecoratedLastUnmaximizedFrame.Value;
|
|
return window.Screen.VisibleFrame;
|
|
}
|
|
|
|
public override bool ShouldZoom(NSWindow window, CGRect newFrame)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
public Point Position
|
|
{
|
|
get => Window.Frame.ToAvaloniaRect().BottomLeft.ConvertPointY();
|
|
set => Window.SetFrameTopLeftPoint(value.ToMonoMacPoint().ConvertPointY());
|
|
}
|
|
|
|
|
|
protected virtual NSWindowStyle GetStyle() => NSWindowStyle.Borderless;
|
|
|
|
protected void UpdateStyle() => Window.StyleMask = GetStyle();
|
|
|
|
|
|
IPlatformHandle IWindowBaseImpl.Handle => new PlatformHandle(Window.Handle, "NSWindow");
|
|
public Size MaxClientSize => NSScreen.Screens[0].Frame.ToAvaloniaRect().Size;
|
|
public Action<Point> PositionChanged { get; set; }
|
|
public Action Deactivated { get; set; }
|
|
public Action Activated { get; set; }
|
|
public Func<bool> Closing { get; set; }
|
|
|
|
public override Size ClientSize => Window.ContentRectFor(Window.Frame).Size.ToAvaloniaSize();
|
|
|
|
|
|
public void Show() => Window.MakeKeyAndOrderFront(Window);
|
|
|
|
public void Hide() => Window?.OrderOut(Window);
|
|
|
|
public void SetTopmost(bool value) => Window.Level = value ? NSWindowLevel.Floating : NSWindowLevel.Normal;
|
|
|
|
public void BeginMoveDrag()
|
|
{
|
|
var ev = View.LastMouseDownEvent;
|
|
if (ev == null)
|
|
return;
|
|
var handle = Selector.GetHandle("performWindowDragWithEvent:");
|
|
Messaging.void_objc_msgSend_IntPtr(Window.Handle, handle, ev.Handle);
|
|
}
|
|
|
|
public void BeginResizeDrag(WindowEdge edge)
|
|
{
|
|
var screenPoint = NSEvent.CurrentMouseLocation.ConvertPointY().ToAvaloniaPoint();
|
|
_managedDrag.BeginResizeDrag(edge, PointToClient(screenPoint));
|
|
}
|
|
|
|
protected override void OnInput(RawInputEventArgs args)
|
|
{
|
|
if (_managedDrag.PreprocessInputEvent(ref args))
|
|
return;
|
|
base.OnInput(args);
|
|
}
|
|
|
|
public void Activate() => Window.MakeKeyWindow();
|
|
|
|
public void ResizeForManagedDrag(Rect rc)
|
|
{
|
|
var frame = new CGRect(rc.X, rc.Position.ConvertPointY().Y - rc.Height, rc.Width, rc.Height);
|
|
Window.SetFrame(frame, true);
|
|
}
|
|
|
|
public void Resize(Size clientSize)
|
|
{
|
|
var pos = Position;
|
|
Window.SetContentSize(clientSize.ToMonoMacSize());
|
|
Position = pos;
|
|
}
|
|
|
|
public void SetMinMaxSize(Size minSize, Size maxSize)
|
|
{
|
|
}
|
|
|
|
public IScreenImpl Screen
|
|
{
|
|
get;
|
|
} = new ScreenImpl();
|
|
|
|
public override Point PointToClient(Point point)
|
|
{
|
|
var cocoaScreenPoint = point.ToMonoMacPoint().ConvertPointY();
|
|
var cocoaViewPoint = Window.ConvertScreenToBase(cocoaScreenPoint).ToAvaloniaPoint();
|
|
return View.TranslateLocalPoint(cocoaViewPoint);
|
|
}
|
|
|
|
public override Point PointToScreen(Point point)
|
|
{
|
|
var cocoaViewPoint = View.TranslateLocalPoint(point).ToMonoMacPoint();
|
|
var cocoaScreenPoint = Window.ConvertBaseToScreen(cocoaViewPoint);
|
|
return cocoaScreenPoint.ConvertPointY().ToAvaloniaPoint();
|
|
}
|
|
|
|
|
|
|
|
public override void Dispose()
|
|
{
|
|
Window?.Close();
|
|
Window?.Dispose();
|
|
base.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|