6 changed files with 212 additions and 1 deletions
@ -0,0 +1,89 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reactive.Disposables; |
|||
using System.Text; |
|||
using Avalonia.Controls.Primitives; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.Controls.Chrome |
|||
{ |
|||
public class CaptionButtons : TemplatedControl |
|||
{ |
|||
private CompositeDisposable _disposables; |
|||
private Window _hostWindow; |
|||
|
|||
public CaptionButtons(Window hostWindow) |
|||
{ |
|||
_hostWindow = hostWindow; |
|||
} |
|||
|
|||
public void Attach() |
|||
{ |
|||
if (_disposables == null) |
|||
{ |
|||
var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); |
|||
|
|||
layer.Children.Add(this); |
|||
|
|||
_disposables = new CompositeDisposable |
|||
{ |
|||
_hostWindow.GetObservable(Window.WindowDecorationMarginsProperty) |
|||
.Subscribe(x => |
|||
{ |
|||
Height = x.Top; |
|||
}), |
|||
|
|||
|
|||
_hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty) |
|||
.Subscribe(x => InvalidateSize()), |
|||
|
|||
_hostWindow.GetObservable(Window.OffScreenMarginProperty) |
|||
.Subscribe(x => InvalidateSize()), |
|||
|
|||
_hostWindow.GetObservable(Window.WindowStateProperty) |
|||
.Subscribe(x => |
|||
{ |
|||
PseudoClasses.Set(":minimized", x == WindowState.Minimized); |
|||
PseudoClasses.Set(":normal", x == WindowState.Normal); |
|||
PseudoClasses.Set(":maximized", x == WindowState.Maximized); |
|||
PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen); |
|||
}) |
|||
}; |
|||
} |
|||
} |
|||
|
|||
void InvalidateSize () |
|||
{ |
|||
Margin = new Thickness(1, _hostWindow.OffScreenMargin.Top, 1, 1); |
|||
Height = _hostWindow.WindowDecorationMargins.Top - _hostWindow.OffScreenMargin.Top; |
|||
} |
|||
|
|||
public void Detach() |
|||
{ |
|||
if (_disposables != null) |
|||
{ |
|||
var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow); |
|||
|
|||
layer.Children.Remove(this); |
|||
|
|||
_disposables.Dispose(); |
|||
_disposables = null; |
|||
} |
|||
} |
|||
|
|||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) |
|||
{ |
|||
base.OnApplyTemplate(e); |
|||
|
|||
var closeButton = e.NameScope.Find<Panel>("PART_CloseButton"); |
|||
var restoreButton = e.NameScope.Find<Panel>("PART_RestoreButton"); |
|||
var minimiseButton = e.NameScope.Find<Panel>("PART_MinimiseButton"); |
|||
var fullScreenButton = e.NameScope.Find<Panel>("PART_FullScreenButton"); |
|||
|
|||
closeButton.PointerPressed += (sender, e) => _hostWindow.Close(); |
|||
restoreButton.PointerPressed += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; |
|||
minimiseButton.PointerPressed += (sender, e) => _hostWindow.WindowState = WindowState.Minimized; |
|||
fullScreenButton.PointerPressed += (sender, e) => _hostWindow.WindowState = _hostWindow.WindowState == WindowState.FullScreen ? WindowState.Normal : WindowState.FullScreen; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
using System.Linq; |
|||
using Avalonia.Rendering; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.Controls.Primitives |
|||
{ |
|||
public class ChromeOverlayLayer : Canvas, ICustomSimpleHitTest |
|||
{ |
|||
public Size AvailableSize { get; private set; } |
|||
|
|||
public static ChromeOverlayLayer GetOverlayLayer(IVisual visual) |
|||
{ |
|||
foreach (var v in visual.GetVisualAncestors()) |
|||
if (v is VisualLayerManager vlm) |
|||
if (vlm.OverlayLayer != null) |
|||
return vlm.ChromeOverlayLayer; |
|||
|
|||
if (visual is TopLevel tl) |
|||
{ |
|||
var layers = tl.GetVisualDescendants().OfType<VisualLayerManager>().FirstOrDefault(); |
|||
return layers?.ChromeOverlayLayer; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public bool HitTest(Point point) => Children.HitTestCustom(point); |
|||
|
|||
protected override Size ArrangeOverride(Size finalSize) |
|||
{ |
|||
// We are saving it here since child controls might need to know the entire size of the overlay
|
|||
// and Bounds won't be updated in time
|
|||
AvailableSize = finalSize; |
|||
return base.ArrangeOverride(finalSize); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
|||
<Style Selector="CaptionButtons"> |
|||
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/> |
|||
<Setter Property="Canvas.Right" Value="0" /> |
|||
<Setter Property="MaxHeight" Value="30" /> |
|||
<Setter Property="Template"> |
|||
<ControlTemplate> |
|||
<StackPanel Spacing="2" Margin="0 0 7 0" Background="#7F00FF00" VerticalAlignment="Stretch" TextBlock.FontSize="10" Orientation="Horizontal"> |
|||
<StackPanel.Styles> |
|||
<Style Selector="Panel"> |
|||
<Setter Property="Width" Value="45" /> |
|||
<Setter Property="Background" Value="Transparent" /> |
|||
</Style> |
|||
<Style Selector="Path"> |
|||
<Setter Property="Fill" Value="White" /> |
|||
</Style> |
|||
<Style Selector="Panel:pointerover"> |
|||
<Setter Property="Background" Value="#1FFFFFFF" /> |
|||
</Style> |
|||
<Style Selector="Panel#PART_CloseButton:pointerover"> |
|||
<Setter Property="Background" Value="#AFFF0000" /> |
|||
</Style> |
|||
<Style Selector="Viewbox"> |
|||
<Setter Property="Width" Value="11" /> |
|||
<Setter Property="Margin" Value="2" /> |
|||
</Style> |
|||
</StackPanel.Styles> |
|||
<Panel x:Name="PART_FullScreenButton"> |
|||
<Viewbox> |
|||
<Path Stretch="UniformToFill" /> |
|||
</Viewbox> |
|||
</Panel> |
|||
|
|||
<Panel x:Name="PART_MinimiseButton"> |
|||
<Viewbox> |
|||
<Path Stretch="UniformToFill" Data="M2048 1229v-205h-2048v205h2048z" /> |
|||
</Viewbox> |
|||
</Panel> |
|||
|
|||
<Panel x:Name="PART_RestoreButton"> |
|||
<Viewbox> |
|||
<Viewbox.RenderTransform> |
|||
<RotateTransform Angle="-90" /> |
|||
</Viewbox.RenderTransform> |
|||
<Path Stretch="UniformToFill"/> |
|||
</Viewbox> |
|||
</Panel> |
|||
|
|||
<Panel x:Name="PART_CloseButton"> |
|||
<Viewbox> |
|||
<Path Stretch="UniformToFill" Data="M1169 1024l879 -879l-145 -145l-879 879l-879 -879l-145 145l879 879l-879 879l145 145l879 -879l879 879l145 -145z" /> |
|||
</Viewbox> |
|||
</Panel> |
|||
</StackPanel> |
|||
</ControlTemplate> |
|||
</Setter> |
|||
</Style> |
|||
<Style Selector="CaptionButtons Panel#PART_RestoreButton Path"> |
|||
<Setter Property="Data" Value="M2048 2048v-2048h-2048v2048h2048zM1843 1843h-1638v-1638h1638v1638z" /> |
|||
</Style> |
|||
<Style Selector="CaptionButtons:maximized Panel#PART_RestoreButton Path"> |
|||
<Setter Property="Data" Value="M2048 410h-410v-410h-1638v1638h410v410h1638v-1638zM1434 1434h-1229v-1229h1229v1229zM1843 1843h-1229v-205h1024v-1024h205v1229z" /> |
|||
</Style> |
|||
<Style Selector="CaptionButtons Panel#PART_FullScreenButton Path"> |
|||
<Setter Property="Data" Value="M2048 2048v-819h-205v469l-1493 -1493h469v-205h-819v819h205v-469l1493 1493h-469v205h819z" /> |
|||
</Style> |
|||
<Style Selector="CaptionButtons:fullscreen Panel#PART_FullScreenButton Path"> |
|||
<Setter Property="Data" Value="M205 1024h819v-819h-205v469l-674 -674l-145 145l674 674h-469v205zM1374 1229h469v-205h-819v819h205v-469l674 674l145 -145z" /> |
|||
</Style> |
|||
</Styles> |
|||
Loading…
Reference in new issue