Browse Source

managed chrome compatible with fs.

demo1
Dan Walmsley 6 years ago
parent
commit
64b2fdc80b
  1. 12
      src/Avalonia.Controls/Chrome/CaptionButtons.cs
  2. 99
      src/Avalonia.Controls/Chrome/TitleBar.cs
  3. 2
      src/Avalonia.Controls/Primitives/ChromeOverlayLayer.cs
  4. 12
      src/Avalonia.Controls/Window.cs
  5. 11
      src/Avalonia.Themes.Default/CaptionButtons.xaml
  6. 19
      src/Avalonia.Themes.Default/TitleBar.xaml
  7. 67
      src/Avalonia.Themes.Fluent/CaptionButtons.xaml
  8. 4
      src/Avalonia.Themes.Fluent/FluentTheme.xaml
  9. 68
      src/Avalonia.Themes.Fluent/TitleBar.xaml
  10. 4
      src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs
  11. 5
      src/Windows/Avalonia.Win32/WindowImpl.cs

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

@ -12,18 +12,11 @@ namespace Avalonia.Controls.Chrome
private CompositeDisposable _disposables;
private Window _hostWindow;
public CaptionButtons(Window hostWindow)
{
_hostWindow = hostWindow;
}
public void Attach()
public void Attach(Window hostWindow)
{
if (_disposables == null)
{
var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow);
layer.Children.Add(this);
_hostWindow = hostWindow;
_disposables = new CompositeDisposable
{
@ -33,7 +26,6 @@ namespace Avalonia.Controls.Chrome
Height = x.Top;
}),
_hostWindow.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty)
.Subscribe(x => InvalidateSize()),

99
src/Avalonia.Controls/Chrome/TitleBar.cs

@ -0,0 +1,99 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Media;
namespace Avalonia.Controls.Chrome
{
public class TitleBar : TemplatedControl
{
private CompositeDisposable _disposables;
private Window _hostWindow;
private CaptionButtons _captionButtons;
public TitleBar(Window hostWindow)
{
_hostWindow = hostWindow;
}
public TitleBar()
{
}
protected override Size MeasureOverride(Size availableSize)
{
return base.MeasureOverride(availableSize);
}
protected override Size ArrangeOverride(Size finalSize)
{
return base.ArrangeOverride(finalSize);
}
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;
}
public void Detach()
{
if (_disposables != null)
{
var layer = ChromeOverlayLayer.GetOverlayLayer(_hostWindow);
layer.Children.Remove(this);
_disposables.Dispose();
_disposables = null;
_captionButtons?.Detach();
}
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_captionButtons = e.NameScope.Find<CaptionButtons>("PART_CaptionButtons");
_captionButtons.Attach(_hostWindow);
}
}
}

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

@ -4,7 +4,7 @@ using Avalonia.VisualTree;
namespace Avalonia.Controls.Primitives
{
public class ChromeOverlayLayer : Canvas, ICustomSimpleHitTest
public class ChromeOverlayLayer : Panel, ICustomSimpleHitTest
{
public Size AvailableSize { get; private set; }

12
src/Avalonia.Controls/Window.cs

@ -71,7 +71,7 @@ namespace Avalonia.Controls
public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot
{
private readonly List<(Window child, bool isDialog)> _children = new List<(Window, bool)>();
private CaptionButtons _managedCaptions;
private TitleBar _managedTitleBar;
private bool _isExtendedIntoWindowDecorations;
@ -911,18 +911,18 @@ namespace Avalonia.Controls
{
if(hints.HasFlag(ExtendClientAreaChromeHints.ManagedChromeButtons))
{
if(_managedCaptions == null)
if(_managedTitleBar == null)
{
_managedCaptions = new CaptionButtons(this);
_managedTitleBar = new TitleBar(this);
}
_managedCaptions.Attach();
_managedTitleBar.Attach();
}
else
{
if(_managedCaptions != null)
if(_managedTitleBar != null)
{
_managedCaptions.Detach();
_managedTitleBar.Detach();
}
}
}

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

@ -11,9 +11,6 @@
<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>
@ -27,13 +24,13 @@
</StackPanel.Styles>
<Panel x:Name="PART_FullScreenButton">
<Viewbox>
<Path Stretch="UniformToFill" />
<Path Stretch="UniformToFill" Fill="{TemplateBinding Foreground}" />
</Viewbox>
</Panel>
<Panel x:Name="PART_MinimiseButton">
<Viewbox>
<Path Stretch="UniformToFill" Data="M2048 1229v-205h-2048v205h2048z" />
<Path Stretch="UniformToFill" Fill="{TemplateBinding Foreground}" Data="M2048 1229v-205h-2048v205h2048z" />
</Viewbox>
</Panel>
@ -42,13 +39,13 @@
<Viewbox.RenderTransform>
<RotateTransform Angle="-90" />
</Viewbox.RenderTransform>
<Path Stretch="UniformToFill"/>
<Path Stretch="UniformToFill" Fill="{TemplateBinding Foreground}"/>
</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" />
<Path Stretch="UniformToFill" Fill="{TemplateBinding Foreground}" Data="M1169 1024l879 -879l-145 -145l-879 879l-879 -879l-145 145l879 879l-879 879l145 145l879 -879l879 879l145 -145z" />
</Viewbox>
</Panel>
</StackPanel>

19
src/Avalonia.Themes.Default/TitleBar.xaml

@ -0,0 +1,19 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border>
<TitleBar Background="SkyBlue" Height="30" Width="300" Foreground="Black" />
</Border>
</Design.PreviewWith>
<Style Selector="TitleBar">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="MaxHeight" Value="30" />
<Setter Property="Background" Value="Red" />
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}" HorizontalAlignment="Stretch">
<CaptionButtons Name="PART_CaptionButtons" HorizontalAlignment="Right" Foreground="{TemplateBinding Foreground}" />
</Border>
</ControlTemplate>
</Setter>
</Style>
</Styles>

67
src/Avalonia.Themes.Fluent/CaptionButtons.xaml

@ -0,0 +1,67 @@
<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" 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="Panel:pointerover">
<Setter Property="Background" Value="#CFFFFFFF" />
</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" Fill="{TemplateBinding Foreground}" />
</Viewbox>
</Panel>
<Panel x:Name="PART_MinimiseButton">
<Viewbox>
<Path Stretch="UniformToFill" Fill="{TemplateBinding Foreground}" Data="M2048 1229v-205h-2048v205h2048z" />
</Viewbox>
</Panel>
<Panel x:Name="PART_RestoreButton">
<Viewbox>
<Viewbox.RenderTransform>
<RotateTransform Angle="-90" />
</Viewbox.RenderTransform>
<Path Stretch="UniformToFill" Fill="{TemplateBinding Foreground}"/>
</Viewbox>
</Panel>
<Panel x:Name="PART_CloseButton">
<Viewbox>
<Path Stretch="UniformToFill" Fill="{TemplateBinding Foreground}" 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>

4
src/Avalonia.Themes.Fluent/FluentTheme.xaml

@ -7,7 +7,8 @@
<StyleInclude Source="resm:Avalonia.Themes.Fluent.FocusAdorner.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Button.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Carousel.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.CaptionButtons.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Carousel.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.CheckBox.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.ComboBox.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.ComboBoxItem.xaml?assembly=Avalonia.Themes.Fluent"/>
@ -36,6 +37,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Fluent.TextBox.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.ToggleButton.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Expander.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.TitleBar.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.TreeView.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.TreeViewItem.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.UserControl.xaml?assembly=Avalonia.Themes.Fluent"/>

68
src/Avalonia.Themes.Fluent/TitleBar.xaml

@ -0,0 +1,68 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border>
<TitleBar Background="SkyBlue" Height="30" Width="300" Foreground="Black" />
</Border>
</Design.PreviewWith>
<Style Selector="TitleBar">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="Background" Value="Red" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Template">
<ControlTemplate>
<Panel HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="Stretch">
<Panel x:Name="PART_MouseTracker" Height="15" VerticalAlignment="Top" />
<Panel x:Name="PART_Container">
<Border x:Name="PART_Background" Background="{TemplateBinding Background}" />
<CaptionButtons x:Name="PART_CaptionButtons" VerticalAlignment="Top" HorizontalAlignment="Right" Foreground="{TemplateBinding Foreground}" />
</Panel>
</Panel>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="TitleBar /template/ Border#PART_Background">
<Setter Property="IsHitTestVisible" Value="False" />
</Style>
<Style Selector="TitleBar:fullscreen /template/ Border#PART_Background">
<Setter Property="IsHitTestVisible" Value="True" />
</Style>
<Style Selector="TitleBar:fullscreen /template/ Panel#PART_MouseTracker">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="TitleBar:fullscreen:not(:pointerover) /template/ Panel#PART_Container">
<Style.Animations>
<Animation Duration="0:0:.5" Easing="SineEaseInOut">
<KeyFrame Cue="0%">
<Setter Property="TranslateTransform.Y" Value="0"/>
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="TranslateTransform.Y" Value="-30"/>
</KeyFrame>
</Animation>
</Style.Animations>
<Setter Property="TranslateTransform.Y" Value="-30" />
</Style>
<Style Selector="TitleBar:fullscreen:pointerover /template/ Panel#PART_Container">
<Style.Animations>
<Animation Duration="0:0:.5" Easing="SineEaseInOut">
<KeyFrame Cue="0%">
<Setter Property="TranslateTransform.Y" Value="-30"/>
</KeyFrame>
<KeyFrame Cue="100%">
<Setter Property="TranslateTransform.Y" Value="0"/>
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
</Styles>

4
src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs

@ -90,6 +90,10 @@ namespace Avalonia.Win32
case WindowsMessage.WM_NCHITTEST:
if (lRet == IntPtr.Zero)
{
if(WindowState == WindowState.FullScreen)
{
return (IntPtr)HitTestValues.HTCLIENT;
}
var hittestResult = HitTestNCA(hWnd, wParam, lParam);
lRet = (IntPtr)hittestResult;

5
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -181,6 +181,11 @@ namespace Avalonia.Win32
{
get
{
if(_isFullScreenActive)
{
return WindowState.FullScreen;
}
var placement = default(WINDOWPLACEMENT);
GetWindowPlacement(_hwnd, ref placement);

Loading…
Cancel
Save