MacosTitleBar.axaml.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. using Avalonia;
  2. using Avalonia.Controls;
  3. using Avalonia.Controls.Shapes;
  4. using Avalonia.LogicalTree;
  5. using Avalonia.Markup.Xaml;
  6. using Avalonia.Media.Imaging;
  7. using Avalonia.Platform;
  8. using System;
  9. using System.Runtime.InteropServices;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. namespace fis
  13. {
  14. public class MacosTitleBar : UserControl
  15. {
  16. private Button closeButton;
  17. private Button minimizeButton;
  18. private Button zoomButton;
  19. private DockPanel titleBarBackground;
  20. private StackPanel titleAndWindowIconWrapper;
  21. public static readonly StyledProperty<bool> IsSeamlessProperty =
  22. AvaloniaProperty.Register<MacosTitleBar, bool>(nameof(IsSeamless));
  23. public bool IsSeamless
  24. {
  25. get { return GetValue(IsSeamlessProperty); }
  26. set {
  27. SetValue(IsSeamlessProperty, value);
  28. if (titleBarBackground != null && titleAndWindowIconWrapper != null)
  29. {
  30. titleBarBackground.IsVisible = IsSeamless ? false : true;
  31. titleAndWindowIconWrapper.IsVisible = IsSeamless ? false : true;
  32. }
  33. }
  34. }
  35. public MacosTitleBar()
  36. {
  37. this.InitializeComponent();
  38. if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) == false)
  39. {
  40. this.IsVisible = false;
  41. }
  42. else
  43. {
  44. minimizeButton = this.FindControl<Button>("MinimizeButton");
  45. zoomButton = this.FindControl<Button>("ZoomButton");
  46. closeButton = this.FindControl<Button>("CloseButton");
  47. minimizeButton.Click += MinimizeWindow;
  48. zoomButton.Click += MaximizeWindow;
  49. closeButton.Click += CloseWindow;
  50. titleBarBackground = this.FindControl<DockPanel>("TitleBarBackground");
  51. titleAndWindowIconWrapper = this.FindControl<StackPanel>("TitleAndWindowIconWrapper");
  52. SubscribeToWindowState();
  53. }
  54. }
  55. private void CloseWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
  56. {
  57. Window hostWindow = (Window)this.VisualRoot;
  58. hostWindow.Close();
  59. }
  60. private void MaximizeWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
  61. {
  62. Window hostWindow = (Window)this.VisualRoot;
  63. if (hostWindow.WindowState == WindowState.Normal)
  64. {
  65. hostWindow.WindowState = WindowState.Maximized;
  66. }
  67. else
  68. {
  69. hostWindow.WindowState = WindowState.Normal;
  70. }
  71. }
  72. private void MinimizeWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
  73. {
  74. Window hostWindow = (Window)this.VisualRoot;
  75. hostWindow.WindowState = WindowState.Minimized;
  76. }
  77. private async void SubscribeToWindowState()
  78. {
  79. Window hostWindow = (Window)this.VisualRoot;
  80. while (hostWindow == null)
  81. {
  82. hostWindow = (Window)this.VisualRoot;
  83. await Task.Delay(50);
  84. }
  85. hostWindow.ExtendClientAreaTitleBarHeightHint = 44;
  86. hostWindow.GetObservable(Window.WindowStateProperty).Subscribe(s =>
  87. {
  88. if (s != WindowState.Maximized)
  89. {
  90. hostWindow.Padding = new Thickness(0, 0, 0, 0);
  91. }
  92. if (s == WindowState.Maximized)
  93. {
  94. hostWindow.Padding = new Thickness(7, 7, 7, 7);
  95. // This should be a more universal approach in both cases, but I found it to be less reliable, when for example double-clicking the title bar.
  96. /*hostWindow.Padding = new Thickness(
  97. hostWindow.OffScreenMargin.Left,
  98. hostWindow.OffScreenMargin.Top,
  99. hostWindow.OffScreenMargin.Right,
  100. hostWindow.OffScreenMargin.Bottom);*/
  101. }
  102. });
  103. }
  104. private void InitializeComponent()
  105. {
  106. AvaloniaXamlLoader.Load(this);
  107. }
  108. }
  109. }