Browse Source

Add managed CaptionButtonsControl.

demo1
Dan Walmsley 6 years ago
parent
commit
e93554d0da
  1. 89
      src/Avalonia.Controls/Chrome/CaptionButtons.cs
  2. 37
      src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs
  3. 15
      src/Avalonia.Controls/Primitives/VisualLayerManager.cs
  4. 1
      src/Avalonia.Controls/Properties/AssemblyInfo.cs
  5. 70
      src/Avalonia.Themes.Default/CaptionButtons.xaml
  6. 1
      src/Avalonia.Themes.Default/DefaultTheme.xaml

89
src/Avalonia.Controls/Chrome/CaptionButtons.cs

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

37
src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs

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

15
src/Avalonia.Controls/Primitives/VisualLayerManager.cs

@ -6,7 +6,9 @@ namespace Avalonia.Controls.Primitives
public class VisualLayerManager : Decorator
{
private const int AdornerZIndex = int.MaxValue - 100;
private const int OverlayZIndex = int.MaxValue - 99;
private const int ChromeZIndex = int.MaxValue - 99;
private const int OverlayZIndex = int.MaxValue - 98;
private ILogicalRoot _logicalRoot;
private readonly List<Control> _layers = new List<Control>();
@ -24,6 +26,17 @@ namespace Avalonia.Controls.Primitives
}
}
public ChromeOverlayLayer ChromeOverlayLayer
{
get
{
var rv = FindLayer<ChromeOverlayLayer>();
if (rv == null)
AddLayer(rv = new ChromeOverlayLayer(), ChromeZIndex);
return rv;
}
}
public OverlayLayer OverlayLayer
{
get

1
src/Avalonia.Controls/Properties/AssemblyInfo.cs

@ -13,3 +13,4 @@ using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Shapes")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Templates")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Notifications")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Chrome")]

70
src/Avalonia.Themes.Default/CaptionButtons.xaml

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

1
src/Avalonia.Themes.Default/DefaultTheme.xaml

@ -9,6 +9,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.Button.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Carousel.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.CheckBox.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.CaptionButtons.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ComboBox.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ComboBoxItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ContentControl.xaml?assembly=Avalonia.Themes.Default"/>

Loading…
Cancel
Save