Browse Source

Rename PipsPager button theme APIs (#20954)

* Rename PipsPager button theme

* Updated PipsPager render tests

* Updated tests

* Updated Avalonia.nupkg.xml
master
Javier Suárez 7 hours ago
committed by GitHub
parent
commit
d30779c5a6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 96
      api/Avalonia.nupkg.xml
  2. 26
      samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonThemesPage.xaml
  3. 11
      samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonThemesPage.xaml.cs
  4. 11
      samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonsPage.xaml.cs
  5. 6
      samples/ControlCatalog/Pages/PipsPagerPage.xaml.cs
  6. 17
      src/Avalonia.Controls/Page/NavigationPage.cs
  7. 28
      src/Avalonia.Controls/PipsPager/PipsPager.cs
  8. 59
      src/Avalonia.Themes.Fluent/Controls/PipsPager.xaml
  9. 4
      src/Avalonia.Themes.Simple/Controls/PipsPager.xaml
  10. 2
      tests/Avalonia.Controls.UnitTests/DrawerPageTests.cs
  11. 28
      tests/Avalonia.Controls.UnitTests/NavigationPageTests.cs
  12. 40
      tests/Avalonia.Controls.UnitTests/PipsPagerTests.cs
  13. 27
      tests/Avalonia.RenderTests/Controls/PipsPagerTests.cs
  14. BIN
      tests/TestFiles/Skia/Controls/PipsPager/PipsPager_Default.expected.png
  15. BIN
      tests/TestFiles/Skia/Controls/PipsPager/PipsPager_Preselected_Index.expected.png

96
api/Avalonia.nupkg.xml

@ -5641,4 +5641,100 @@
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left> <Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right> <Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression> </Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.NavigationPage.IsBackButtonEffectivelyVisibleProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.NavigationPage.get_IsBackButtonEffectivelyVisible</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.PipsPager.PreviousButtonStyleProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.PipsPager.NextButtonStyleProperty</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.get_PreviousButtonStyle</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.set_PreviousButtonStyle(Avalonia.Styling.ControlTheme)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.get_NextButtonStyle</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.set_NextButtonStyle(Avalonia.Styling.ControlTheme)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.NavigationPage.IsBackButtonEffectivelyVisibleProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.NavigationPage.get_IsBackButtonEffectivelyVisible</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.PipsPager.PreviousButtonStyleProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Controls.PipsPager.NextButtonStyleProperty</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.get_PreviousButtonStyle</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.set_PreviousButtonStyle(Avalonia.Styling.ControlTheme)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.get_NextButtonStyle</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Controls.PipsPager.set_NextButtonStyle(Avalonia.Styling.ControlTheme)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
</Suppression>
</Suppressions> </Suppressions>

26
samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonsPage.xaml → samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonThemesPage.xaml

@ -1,17 +1,17 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.PipsPagerCustomButtonsPage"> x:Class="ControlCatalog.Pages.PipsPagerCustomButtonThemesPage">
<DockPanel> <DockPanel>
<ScrollViewer DockPanel.Dock="Right" Width="220"> <ScrollViewer DockPanel.Dock="Right" Width="220">
<StackPanel Margin="12" Spacing="8"> <StackPanel Margin="12" Spacing="8">
<TextBlock Text="Custom Buttons" FontSize="16" FontWeight="SemiBold" <TextBlock Text="Custom Button Themes" FontSize="16" FontWeight="SemiBold"
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> Foreground="{DynamicResource SystemControlHighlightAccentBrush}" />
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7" <TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7"
Text="Replace the default chevron navigation buttons with custom styled buttons using PreviousButtonStyle and NextButtonStyle." /> Text="Replace the default chevron navigation buttons with custom button themes using PreviousButtonTheme and NextButtonTheme." />
<Separator /> <Separator />
<TextBlock Text="Properties" FontSize="13" FontWeight="SemiBold" /> <TextBlock Text="Properties" FontSize="13" FontWeight="SemiBold" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="PreviousButtonStyle" /> <TextBlock FontSize="12" TextWrapping="Wrap" Text="PreviousButtonTheme" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="NextButtonStyle" /> <TextBlock FontSize="12" TextWrapping="Wrap" Text="NextButtonTheme" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="IsPreviousButtonVisible" /> <TextBlock FontSize="12" TextWrapping="Wrap" Text="IsPreviousButtonVisible" />
<TextBlock FontSize="12" TextWrapping="Wrap" Text="IsNextButtonVisible" /> <TextBlock FontSize="12" TextWrapping="Wrap" Text="IsNextButtonVisible" />
</StackPanel> </StackPanel>
@ -27,7 +27,7 @@
<PipsPager NumberOfPages="5" MaxVisiblePips="5" <PipsPager NumberOfPages="5" MaxVisiblePips="5"
IsPreviousButtonVisible="True" IsNextButtonVisible="True"> IsPreviousButtonVisible="True" IsNextButtonVisible="True">
<PipsPager.Resources> <PipsPager.Resources>
<ControlTheme x:Key="CustomPreviousButtonStyle" TargetType="Button"> <ControlTheme x:Key="CustomPreviousButtonTheme" TargetType="Button">
<Setter Property="Content" Value="Prev" /> <Setter Property="Content" Value="Prev" />
<Setter Property="Background" Value="LightGray" /> <Setter Property="Background" Value="LightGray" />
<Setter Property="Foreground" Value="Black" /> <Setter Property="Foreground" Value="Black" />
@ -41,7 +41,7 @@
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</ControlTheme> </ControlTheme>
<ControlTheme x:Key="CustomNextButtonStyle" TargetType="Button"> <ControlTheme x:Key="CustomNextButtonTheme" TargetType="Button">
<Setter Property="Content" Value="Next" /> <Setter Property="Content" Value="Next" />
<Setter Property="Background" Value="LightGray" /> <Setter Property="Background" Value="LightGray" />
<Setter Property="Foreground" Value="Black" /> <Setter Property="Foreground" Value="Black" />
@ -56,12 +56,12 @@
</Setter> </Setter>
</ControlTheme> </ControlTheme>
</PipsPager.Resources> </PipsPager.Resources>
<PipsPager.PreviousButtonStyle> <PipsPager.PreviousButtonTheme>
<StaticResource ResourceKey="CustomPreviousButtonStyle" /> <StaticResource ResourceKey="CustomPreviousButtonTheme" />
</PipsPager.PreviousButtonStyle> </PipsPager.PreviousButtonTheme>
<PipsPager.NextButtonStyle> <PipsPager.NextButtonTheme>
<StaticResource ResourceKey="CustomNextButtonStyle" /> <StaticResource ResourceKey="CustomNextButtonTheme" />
</PipsPager.NextButtonStyle> </PipsPager.NextButtonTheme>
</PipsPager> </PipsPager>
</StackPanel> </StackPanel>

11
samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonThemesPage.xaml.cs

@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace ControlCatalog.Pages;
public partial class PipsPagerCustomButtonThemesPage : UserControl
{
public PipsPagerCustomButtonThemesPage()
{
InitializeComponent();
}
}

11
samples/ControlCatalog/Pages/PipsPager/PipsPagerCustomButtonsPage.xaml.cs

@ -1,11 +0,0 @@
using Avalonia.Controls;
namespace ControlCatalog.Pages;
public partial class PipsPagerCustomButtonsPage : UserControl
{
public PipsPagerCustomButtonsPage()
{
InitializeComponent();
}
}

6
samples/ControlCatalog/Pages/PipsPagerPage.xaml.cs

@ -25,9 +25,9 @@ namespace ControlCatalog.Pages
("Appearance", "Custom Colors", ("Appearance", "Custom Colors",
"Override pip indicator colors using resource keys for normal, selected, and hover states.", "Override pip indicator colors using resource keys for normal, selected, and hover states.",
() => new PipsPagerCustomColorsPage()), () => new PipsPagerCustomColorsPage()),
("Appearance", "Custom Buttons", ("Appearance", "Custom Button Themes",
"Replace the default chevron navigation buttons with custom styled buttons.", "Replace the default chevron navigation buttons with custom button themes.",
() => new PipsPagerCustomButtonsPage()), () => new PipsPagerCustomButtonThemesPage()),
("Appearance", "Custom Templates", ("Appearance", "Custom Templates",
"Override pip item templates to create squares, pills, numbers, or any custom shape.", "Override pip item templates to create squares, pills, numbers, or any custom shape.",
() => new PipsPagerCustomTemplatesPage()), () => new PipsPagerCustomTemplatesPage()),

17
src/Avalonia.Controls/Page/NavigationPage.cs

@ -63,13 +63,14 @@ namespace Avalonia.Controls
private ContentPresenter? _modalPresenter; private ContentPresenter? _modalPresenter;
private ContentPresenter? _topCommandBarPresenter; private ContentPresenter? _topCommandBarPresenter;
private IDisposable? _hasNavigationBarSub; private IDisposable? _hasNavigationBarSub;
private IDisposable? _hasBackButtonSub;
private IDisposable? _isBackButtonEnabledSub; private IDisposable? _isBackButtonEnabledSub;
private IDisposable? _barLayoutBehaviorSub; private IDisposable? _barLayoutBehaviorSub;
private IDisposable? _barHeightSub; private IDisposable? _barHeightSub;
private IDisposable? _backButtonContentSub; private IDisposable? _backButtonContentSub;
private bool _isNavigating; private bool _isNavigating;
private bool _canGoBack; private bool _canGoBack;
private bool? _isBackButtonEffectivelyVisible; private bool _isBackButtonEffectivelyVisible;
private bool _isNavBarEffectivelyVisible; private bool _isNavBarEffectivelyVisible;
private double _effectiveBarHeight; private double _effectiveBarHeight;
private bool _isBackButtonEffectivelyEnabled; private bool _isBackButtonEffectivelyEnabled;
@ -110,8 +111,8 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="IsBackButtonEffectivelyVisible"/> property. /// Defines the <see cref="IsBackButtonEffectivelyVisible"/> property.
/// </summary> /// </summary>
public static readonly DirectProperty<NavigationPage, bool?> IsBackButtonEffectivelyVisibleProperty = public static readonly DirectProperty<NavigationPage, bool> IsBackButtonEffectivelyVisibleProperty =
AvaloniaProperty.RegisterDirect<NavigationPage, bool?>(nameof(IsBackButtonEffectivelyVisible), o => o.IsBackButtonEffectivelyVisible); AvaloniaProperty.RegisterDirect<NavigationPage, bool>(nameof(IsBackButtonEffectivelyVisible), o => o.IsBackButtonEffectivelyVisible);
/// <summary> /// <summary>
/// Defines the <see cref="IsNavBarEffectivelyVisible"/> property. /// Defines the <see cref="IsNavBarEffectivelyVisible"/> property.
@ -330,7 +331,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets the effective back-button visibility. /// Gets the effective back-button visibility.
/// </summary> /// </summary>
public bool? IsBackButtonEffectivelyVisible public bool IsBackButtonEffectivelyVisible
{ {
get => _isBackButtonEffectivelyVisible; get => _isBackButtonEffectivelyVisible;
private set => SetAndRaise(IsBackButtonEffectivelyVisibleProperty, ref _isBackButtonEffectivelyVisible, value); private set => SetAndRaise(IsBackButtonEffectivelyVisibleProperty, ref _isBackButtonEffectivelyVisible, value);
@ -730,6 +731,8 @@ namespace Avalonia.Controls
_hasNavigationBarSub?.Dispose(); _hasNavigationBarSub?.Dispose();
_hasNavigationBarSub = null; _hasNavigationBarSub = null;
_hasBackButtonSub?.Dispose();
_hasBackButtonSub = null;
_isBackButtonEnabledSub?.Dispose(); _isBackButtonEnabledSub?.Dispose();
_isBackButtonEnabledSub = null; _isBackButtonEnabledSub = null;
_barLayoutBehaviorSub?.Dispose(); _barLayoutBehaviorSub?.Dispose();
@ -1840,6 +1843,9 @@ namespace Avalonia.Controls
_hasNavigationBarSub?.Dispose(); _hasNavigationBarSub?.Dispose();
_hasNavigationBarSub = null; _hasNavigationBarSub = null;
_hasBackButtonSub?.Dispose();
_hasBackButtonSub = null;
_isBackButtonEnabledSub?.Dispose(); _isBackButtonEnabledSub?.Dispose();
_isBackButtonEnabledSub = null; _isBackButtonEnabledSub = null;
@ -1857,6 +1863,9 @@ namespace Avalonia.Controls
_hasNavigationBarSub = page.GetObservable(HasNavigationBarProperty) _hasNavigationBarSub = page.GetObservable(HasNavigationBarProperty)
.Subscribe(new AnonymousObserver<bool>(_ => UpdateIsNavBarEffectivelyVisible())); .Subscribe(new AnonymousObserver<bool>(_ => UpdateIsNavBarEffectivelyVisible()));
_hasBackButtonSub = page.GetObservable(HasBackButtonProperty)
.Subscribe(new AnonymousObserver<bool>(_ => UpdateIsBackButtonEffectivelyVisible()));
_isBackButtonEnabledSub = page.GetObservable(IsBackButtonEnabledProperty) _isBackButtonEnabledSub = page.GetObservable(IsBackButtonEnabledProperty)
.Subscribe(new AnonymousObserver<bool>(_ => UpdateIsBackButtonEffectivelyEnabled())); .Subscribe(new AnonymousObserver<bool>(_ => UpdateIsBackButtonEffectivelyEnabled()));

28
src/Avalonia.Controls/PipsPager/PipsPager.cs

@ -87,16 +87,16 @@ namespace Avalonia.Controls
x => x.TemplateSettings); x => x.TemplateSettings);
/// <summary> /// <summary>
/// Defines the <see cref="PreviousButtonStyle"/> property. /// Defines the <see cref="PreviousButtonTheme"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<ControlTheme?> PreviousButtonStyleProperty = public static readonly StyledProperty<ControlTheme?> PreviousButtonThemeProperty =
AvaloniaProperty.Register<PipsPager, ControlTheme?>(nameof(PreviousButtonStyle)); AvaloniaProperty.Register<PipsPager, ControlTheme?>(nameof(PreviousButtonTheme));
/// <summary> /// <summary>
/// Defines the <see cref="NextButtonStyle"/> property. /// Defines the <see cref="NextButtonTheme"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<ControlTheme?> NextButtonStyleProperty = public static readonly StyledProperty<ControlTheme?> NextButtonThemeProperty =
AvaloniaProperty.Register<PipsPager, ControlTheme?>(nameof(NextButtonStyle)); AvaloniaProperty.Register<PipsPager, ControlTheme?>(nameof(NextButtonTheme));
/// <summary> /// <summary>
/// Defines the <see cref="SelectedIndexChanged"/> event. /// Defines the <see cref="SelectedIndexChanged"/> event.
@ -195,21 +195,21 @@ namespace Avalonia.Controls
} }
/// <summary> /// <summary>
/// Gets or sets the style for the previous button. /// Gets or sets the theme for the previous button.
/// </summary> /// </summary>
public ControlTheme? PreviousButtonStyle public ControlTheme? PreviousButtonTheme
{ {
get => GetValue(PreviousButtonStyleProperty); get => GetValue(PreviousButtonThemeProperty);
set => SetValue(PreviousButtonStyleProperty, value); set => SetValue(PreviousButtonThemeProperty, value);
} }
/// <summary> /// <summary>
/// Gets or sets the style for the next button. /// Gets or sets the theme for the next button.
/// </summary> /// </summary>
public ControlTheme? NextButtonStyle public ControlTheme? NextButtonTheme
{ {
get => GetValue(NextButtonStyleProperty); get => GetValue(NextButtonThemeProperty);
set => SetValue(NextButtonStyleProperty, value); set => SetValue(NextButtonThemeProperty, value);
} }
/// <inheritdoc/> /// <inheritdoc/>

59
src/Avalonia.Themes.Fluent/Controls/PipsPager.xaml

@ -13,12 +13,12 @@
<StreamGeometry x:Key="PipsPagerPreviousPageButtonVerticalData">M 2.29,8.12 L 7.00,3.41 C 7.27,3.14 7.71,3.14 7.98,3.41 L 12.69,8.12 C 13.14,8.57 12.82,9.33 12.19,9.33 L 2.79,9.33 C 2.16,9.33 1.84,8.57 2.29,8.12 Z</StreamGeometry> <StreamGeometry x:Key="PipsPagerPreviousPageButtonVerticalData">M 2.29,8.12 L 7.00,3.41 C 7.27,3.14 7.71,3.14 7.98,3.41 L 12.69,8.12 C 13.14,8.57 12.82,9.33 12.19,9.33 L 2.79,9.33 C 2.16,9.33 1.84,8.57 2.29,8.12 Z</StreamGeometry>
<StreamGeometry x:Key="PipsPagerNextPageButtonVerticalData">M 2.29,3.88 L 7.00,8.59 C 7.27,8.86 7.71,8.86 7.98,8.59 L 12.69,3.88 C 13.14,3.43 12.82,2.67 12.19,2.67 L 2.79,2.67 C 2.16,2.67 1.84,3.43 2.29,3.88 Z</StreamGeometry> <StreamGeometry x:Key="PipsPagerNextPageButtonVerticalData">M 2.29,3.88 L 7.00,8.59 C 7.27,8.86 7.71,8.86 7.98,8.59 L 12.69,3.88 C 13.14,3.43 12.82,2.67 12.19,2.67 L 2.79,2.67 C 2.16,2.67 1.84,3.43 2.29,3.88 Z</StreamGeometry>
<!-- Base navigation button theme (for custom button styles to inherit from) --> <!-- Base navigation button theme (for custom button themes to inherit from) -->
<ControlTheme x:Key="PipsPagerNavigationButtonTheme" TargetType="Button"> <ControlTheme x:Key="PipsPagerNavigationButtonTheme" TargetType="Button">
<Setter Property="Background" Value="Transparent" /> <Setter Property="Background" Value="{DynamicResource PipsPagerNavigationButtonBackground}" />
<Setter Property="Foreground" Value="{DynamicResource PipsPagerNavigationButtonForeground}" /> <Setter Property="Foreground" Value="{DynamicResource PipsPagerNavigationButtonForeground}" />
<Setter Property="BorderBrush" Value="Transparent" /> <Setter Property="BorderBrush" Value="{DynamicResource PipsPagerNavigationButtonBorderBrush}" />
<Setter Property="BorderThickness" Value="0" /> <Setter Property="BorderThickness" Value="1" />
<Setter Property="Width" Value="24" /> <Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" /> <Setter Property="Height" Value="24" />
<Setter Property="Padding" Value="0" /> <Setter Property="Padding" Value="0" />
@ -41,16 +41,20 @@
</Setter> </Setter>
<Style Selector="^:pointerover /template/ ContentPresenter#PART_ContentPresenter"> <Style Selector="^:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent" /> <Setter Property="Background" Value="{DynamicResource PipsPagerNavigationButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource PipsPagerNavigationButtonBorderBrushPointerOver}" />
<Setter Property="Foreground" Value="{DynamicResource PipsPagerNavigationButtonForegroundPointerOver}" /> <Setter Property="Foreground" Value="{DynamicResource PipsPagerNavigationButtonForegroundPointerOver}" />
</Style> </Style>
<Style Selector="^:pressed /template/ ContentPresenter#PART_ContentPresenter"> <Style Selector="^:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent" /> <Setter Property="Background" Value="{DynamicResource PipsPagerNavigationButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource PipsPagerNavigationButtonBorderBrushPressed}" />
<Setter Property="Foreground" Value="{DynamicResource PipsPagerNavigationButtonForegroundPressed}" /> <Setter Property="Foreground" Value="{DynamicResource PipsPagerNavigationButtonForegroundPressed}" />
</Style> </Style>
<Style Selector="^:disabled /template/ ContentPresenter#PART_ContentPresenter"> <Style Selector="^:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource PipsPagerNavigationButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource PipsPagerNavigationButtonBorderBrushDisabled}" />
<Setter Property="Foreground" Value="{DynamicResource PipsPagerNavigationButtonForegroundDisabled}" /> <Setter Property="Foreground" Value="{DynamicResource PipsPagerNavigationButtonForegroundDisabled}" />
</Style> </Style>
</ControlTheme> </ControlTheme>
@ -73,6 +77,21 @@
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Grid Background="Transparent"> <Grid Background="Transparent">
<Ellipse Name="PipBackground"
Width="10"
Height="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="{DynamicResource PipsPagerSelectionIndicatorBackground}"
Stroke="{DynamicResource PipsPagerSelectionIndicatorBorderBrush}"
StrokeThickness="1">
<Ellipse.Transitions>
<Transitions>
<BrushTransition Property="Fill" Duration="0:0:0.167" />
<BrushTransition Property="Stroke" Duration="0:0:0.167" />
</Transitions>
</Ellipse.Transitions>
</Ellipse>
<Ellipse Name="Pip" <Ellipse Name="Pip"
Width="4" Width="4"
Height="4" Height="4"
@ -96,25 +115,45 @@
<Setter Property="Height" Value="6" /> <Setter Property="Height" Value="6" />
<Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorForegroundPointerOver}" /> <Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorForegroundPointerOver}" />
</Style> </Style>
<Style Selector="^:pointerover /template/ Ellipse#PipBackground">
<Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorBackgroundPointerOver}" />
<Setter Property="Stroke" Value="{DynamicResource PipsPagerSelectionIndicatorBorderBrushPointerOver}" />
</Style>
<Style Selector="^:pressed /template/ Ellipse#Pip"> <Style Selector="^:pressed /template/ Ellipse#Pip">
<Setter Property="Width" Value="4" /> <Setter Property="Width" Value="4" />
<Setter Property="Height" Value="4" /> <Setter Property="Height" Value="4" />
<Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorForegroundPressed}" /> <Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorForegroundPressed}" />
</Style> </Style>
<Style Selector="^:pressed /template/ Ellipse#PipBackground">
<Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorBackgroundPressed}" />
<Setter Property="Stroke" Value="{DynamicResource PipsPagerSelectionIndicatorBorderBrushPressed}" />
</Style>
<Style Selector="^:selected /template/ Ellipse#Pip"> <Style Selector="^:selected /template/ Ellipse#Pip">
<Setter Property="Width" Value="6" /> <Setter Property="Width" Value="6" />
<Setter Property="Height" Value="6" /> <Setter Property="Height" Value="6" />
<Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorForegroundSelected}" /> <Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorForegroundSelected}" />
</Style> </Style>
<Style Selector="^:selected /template/ Ellipse#PipBackground">
<Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorBackgroundSelected}" />
<Setter Property="Stroke" Value="{DynamicResource PipsPagerSelectionIndicatorBorderBrushSelected}" />
</Style>
<Style Selector="^:selected:pointerover /template/ Ellipse#Pip"> <Style Selector="^:selected:pointerover /template/ Ellipse#Pip">
<Setter Property="Width" Value="6" /> <Setter Property="Width" Value="6" />
<Setter Property="Height" Value="6" /> <Setter Property="Height" Value="6" />
<Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorForegroundPointerOver}" /> <Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorForegroundPointerOver}" />
</Style> </Style>
<Style Selector="^:selected:pointerover /template/ Ellipse#PipBackground">
<Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorBackgroundPointerOver}" />
<Setter Property="Stroke" Value="{DynamicResource PipsPagerSelectionIndicatorBorderBrushPointerOver}" />
</Style>
<Style Selector="^:disabled /template/ Ellipse#Pip"> <Style Selector="^:disabled /template/ Ellipse#Pip">
<Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorForegroundDisabled}" /> <Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorForegroundDisabled}" />
</Style> </Style>
<Style Selector="^:disabled /template/ Ellipse#PipBackground">
<Setter Property="Fill" Value="{DynamicResource PipsPagerSelectionIndicatorBackgroundDisabled}" />
<Setter Property="Stroke" Value="{DynamicResource PipsPagerSelectionIndicatorBorderBrushDisabled}" />
</Style>
</ControlTheme> </ControlTheme>
<ControlTheme x:Key="{x:Type PipsPager}" TargetType="PipsPager"> <ControlTheme x:Key="{x:Type PipsPager}" TargetType="PipsPager">
@ -122,8 +161,8 @@
<Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Top" /> <Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="IsTabStop" Value="False" /> <Setter Property="IsTabStop" Value="False" />
<Setter Property="PreviousButtonStyle" Value="{StaticResource PipsPagerPreviousButtonTheme}" /> <Setter Property="PreviousButtonTheme" Value="{StaticResource PipsPagerPreviousButtonTheme}" />
<Setter Property="NextButtonStyle" Value="{StaticResource PipsPagerNextButtonTheme}" /> <Setter Property="NextButtonTheme" Value="{StaticResource PipsPagerNextButtonTheme}" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<StackPanel Name="PART_RootPanel" <StackPanel Name="PART_RootPanel"
@ -131,7 +170,7 @@
Background="{TemplateBinding Background}" Background="{TemplateBinding Background}"
ClipToBounds="False"> ClipToBounds="False">
<Button Name="PART_PreviousButton" <Button Name="PART_PreviousButton"
Theme="{TemplateBinding PreviousButtonStyle}" Theme="{TemplateBinding PreviousButtonTheme}"
IsVisible="{TemplateBinding IsPreviousButtonVisible}" IsVisible="{TemplateBinding IsPreviousButtonVisible}"
VerticalAlignment="Center" VerticalAlignment="Center"
HorizontalAlignment="Center"> HorizontalAlignment="Center">
@ -168,7 +207,7 @@
</ListBox> </ListBox>
<Button Name="PART_NextButton" <Button Name="PART_NextButton"
Theme="{TemplateBinding NextButtonStyle}" Theme="{TemplateBinding NextButtonTheme}"
IsVisible="{TemplateBinding IsNextButtonVisible}" IsVisible="{TemplateBinding IsNextButtonVisible}"
VerticalAlignment="Center" VerticalAlignment="Center"
HorizontalAlignment="Center"> HorizontalAlignment="Center">

4
src/Avalonia.Themes.Simple/Controls/PipsPager.xaml

@ -10,6 +10,8 @@
<Setter Property="BorderBrush" Value="Transparent" /> <Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" /> <Setter Property="BorderThickness" Value="0" />
<Setter Property="IsTabStop" Value="False" /> <Setter Property="IsTabStop" Value="False" />
<Setter Property="PreviousButtonTheme" Value="{StaticResource {x:Type Button}}" />
<Setter Property="NextButtonTheme" Value="{StaticResource {x:Type Button}}" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<StackPanel Name="PART_RootPanel" <StackPanel Name="PART_RootPanel"
@ -19,6 +21,7 @@
ClipToBounds="False"> ClipToBounds="False">
<Button Name="PART_PreviousButton" <Button Name="PART_PreviousButton"
Theme="{TemplateBinding PreviousButtonTheme}"
Width="24" Width="24"
Height="24" Height="24"
Padding="0" Padding="0"
@ -99,6 +102,7 @@
</ListBox> </ListBox>
<Button Name="PART_NextButton" <Button Name="PART_NextButton"
Theme="{TemplateBinding NextButtonTheme}"
Width="24" Width="24"
Height="24" Height="24"
Padding="0" Padding="0"

2
tests/Avalonia.Controls.UnitTests/DrawerPageTests.cs

@ -1321,7 +1321,7 @@ public class DrawerPageTests
Assert.True(nav.IsBackButtonEffectivelyVisible); Assert.True(nav.IsBackButtonEffectivelyVisible);
root.Child = null; root.Child = null;
Assert.False(nav.IsBackButtonEffectivelyVisible ?? false); Assert.False(nav.IsBackButtonEffectivelyVisible);
root.Child = dp; root.Child = dp;
Assert.True(nav.IsBackButtonEffectivelyVisible); Assert.True(nav.IsBackButtonEffectivelyVisible);

28
tests/Avalonia.Controls.UnitTests/NavigationPageTests.cs

@ -429,7 +429,7 @@ public class NavigationPageTests
{ {
var nav = new NavigationPage(); var nav = new NavigationPage();
await nav.PushAsync(new ContentPage()); await nav.PushAsync(new ContentPage());
Assert.Equal(false, nav.IsBackButtonEffectivelyVisible); Assert.False(nav.IsBackButtonEffectivelyVisible);
} }
[Fact] [Fact]
@ -438,7 +438,7 @@ public class NavigationPageTests
var nav = new NavigationPage(); var nav = new NavigationPage();
await nav.PushAsync(new ContentPage()); await nav.PushAsync(new ContentPage());
await nav.PushAsync(new ContentPage()); await nav.PushAsync(new ContentPage());
Assert.Equal(true, nav.IsBackButtonEffectivelyVisible); Assert.True(nav.IsBackButtonEffectivelyVisible);
} }
[Fact] [Fact]
@ -447,7 +447,7 @@ public class NavigationPageTests
var nav = new NavigationPage { IsBackButtonVisible = false }; var nav = new NavigationPage { IsBackButtonVisible = false };
await nav.PushAsync(new ContentPage()); await nav.PushAsync(new ContentPage());
await nav.PushAsync(new ContentPage()); await nav.PushAsync(new ContentPage());
Assert.Equal(false, nav.IsBackButtonEffectivelyVisible); Assert.False(nav.IsBackButtonEffectivelyVisible);
} }
[Fact] [Fact]
@ -458,7 +458,7 @@ public class NavigationPageTests
var top = new ContentPage(); var top = new ContentPage();
NavigationPage.SetHasBackButton(top, false); NavigationPage.SetHasBackButton(top, false);
await nav.PushAsync(top); await nav.PushAsync(top);
Assert.Equal(false, nav.IsBackButtonEffectivelyVisible); Assert.False(nav.IsBackButtonEffectivelyVisible);
} }
[Fact] [Fact]
@ -468,7 +468,25 @@ public class NavigationPageTests
await nav.PushAsync(new ContentPage()); await nav.PushAsync(new ContentPage());
await nav.PushAsync(new ContentPage()); await nav.PushAsync(new ContentPage());
nav.IsBackButtonVisible = true; nav.IsBackButtonVisible = true;
Assert.Equal(true, nav.IsBackButtonEffectivelyVisible); Assert.True(nav.IsBackButtonEffectivelyVisible);
}
[Fact]
public async Task BackButtonVisible_UpdatesWhenCurrentPageHasBackButtonChanges()
{
var nav = new NavigationPage();
await nav.PushAsync(new ContentPage());
var top = new ContentPage();
await nav.PushAsync(top);
Assert.True(nav.IsBackButtonEffectivelyVisible);
NavigationPage.SetHasBackButton(top, false);
Assert.False(nav.IsBackButtonEffectivelyVisible);
NavigationPage.SetHasBackButton(top, true);
Assert.True(nav.IsBackButtonEffectivelyVisible);
} }
} }

40
tests/Avalonia.Controls.UnitTests/PipsPagerTests.cs

@ -5,6 +5,8 @@ using Avalonia.Interactivity;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Styling;
using Avalonia.Themes.Simple;
using System.Linq; using System.Linq;
using Xunit; using Xunit;
@ -201,6 +203,44 @@ namespace Avalonia.Controls.UnitTests
Assert.True(target.IsNextButtonVisible); Assert.True(target.IsNextButtonVisible);
} }
[Fact]
public void SimpleTheme_Should_Forward_Custom_Button_Themes()
{
using var unittestApplication = UnitTestApplication.Start(TestServices.StyledWindow);
var previousTheme = new ControlTheme(typeof(Button));
var nextTheme = new ControlTheme(typeof(Button));
var simpleTheme = new SimpleTheme();
var target = new PipsPager
{
NumberOfPages = 5,
PreviousButtonTheme = previousTheme,
NextButtonTheme = nextTheme
};
var root = new TestRoot
{
Child = target,
Styles =
{
simpleTheme
}
};
Assert.True(simpleTheme.TryGetResource(typeof(PipsPager), ThemeVariant.Default, out var theme));
target.Theme = Assert.IsType<ControlTheme>(theme);
target.ApplyTemplate();
root.LayoutManager.ExecuteInitialLayoutPass();
var previousButton = target.GetVisualDescendants().OfType<Button>().First(b => b.Name == "PART_PreviousButton");
var nextButton = target.GetVisualDescendants().OfType<Button>().First(b => b.Name == "PART_NextButton");
Assert.Same(previousTheme, previousButton.Theme);
Assert.Same(nextTheme, nextButton.Theme);
}
[Fact] [Fact]
public void Rapid_Page_Changes_Should_Maintain_Integrity() public void Rapid_Page_Changes_Should_Maintain_Integrity()
{ {

27
tests/Avalonia.RenderTests/Controls/PipsPagerTests.cs

@ -1,21 +1,25 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Presenters; using Avalonia.Controls.Presenters;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Controls.Shapes;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.Threading; using Avalonia.Threading;
using Xunit; using Xunit;
#if AVALONIA_SKIA
namespace Avalonia.Skia.RenderTests namespace Avalonia.Skia.RenderTests
#else
namespace Avalonia.Direct2D1.RenderTests.Controls
#endif
{ {
public class PipsPagerTests : TestBase public class PipsPagerTests : TestBase
{ {
public PipsPagerTests() public PipsPagerTests()
: base(@"Controls/PipsPager") : base(@"Controls\PipsPager")
{ {
} }
@ -26,7 +30,7 @@ namespace Avalonia.Skia.RenderTests
var stackPanel = new StackPanel var stackPanel = new StackPanel
{ {
Name = "PART_RootPanel", Name = "PART_RootPanel",
Spacing = 5, Spacing = 4,
[!StackPanel.OrientationProperty] = control[!PipsPager.OrientationProperty], [!StackPanel.OrientationProperty] = control[!PipsPager.OrientationProperty],
HorizontalAlignment = HorizontalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center VerticalAlignment = VerticalAlignment.Center
@ -65,7 +69,6 @@ namespace Avalonia.Skia.RenderTests
[!Button.IsVisibleProperty] = control[!PipsPager.IsNextButtonVisibleProperty] [!Button.IsVisibleProperty] = control[!PipsPager.IsNextButtonVisibleProperty]
}.RegisterInNameScope(scope); }.RegisterInNameScope(scope);
// Simple ListBox Template (ItemsPresenter)
var listBoxTemplate = new FuncControlTemplate<ListBox>((lb, s) => var listBoxTemplate = new FuncControlTemplate<ListBox>((lb, s) =>
new ItemsPresenter new ItemsPresenter
{ {
@ -86,18 +89,16 @@ namespace Avalonia.Skia.RenderTests
}) })
}.RegisterInNameScope(scope); }.RegisterInNameScope(scope);
// Default Item Style
var itemStyle = new Style(x => x.OfType<ListBoxItem>()); var itemStyle = new Style(x => x.OfType<ListBoxItem>());
itemStyle.Setters.Add(new Setter(ListBoxItem.TemplateProperty, new FuncControlTemplate<ListBoxItem>((item, s) => itemStyle.Setters.Add(new Setter(ListBoxItem.TemplateProperty,
new Ellipse { Name="Pip", Width = 10, Height = 10 }.RegisterInNameScope(s)))); new FuncControlTemplate<ListBoxItem>((item, s) =>
new Rectangle { Name = "Pip", Width = 10, Height = 10 }.RegisterInNameScope(s))));
// Default Pip Fill Style
var defaultPipStyle = new Style(x => x.OfType<ListBoxItem>().Template().Name("Pip")); var defaultPipStyle = new Style(x => x.OfType<ListBoxItem>().Template().Name("Pip"));
defaultPipStyle.Setters.Add(new Setter(Ellipse.FillProperty, Brushes.Gray)); defaultPipStyle.Setters.Add(new Setter(Rectangle.FillProperty, Brushes.Gray));
// Selected Item Style
var selectedStyle = new Style(x => x.OfType<ListBoxItem>().Class(":selected").Template().Name("Pip")); var selectedStyle = new Style(x => x.OfType<ListBoxItem>().Class(":selected").Template().Name("Pip"));
selectedStyle.Setters.Add(new Setter(Ellipse.FillProperty, Brushes.Red)); selectedStyle.Setters.Add(new Setter(Rectangle.FillProperty, Brushes.Red));
pipsList.Styles.Add(itemStyle); pipsList.Styles.Add(itemStyle);
pipsList.Styles.Add(defaultPipStyle); pipsList.Styles.Add(defaultPipStyle);
@ -135,7 +136,7 @@ namespace Avalonia.Skia.RenderTests
Dispatcher.UIThread.RunJobs(null, TestContext.Current.CancellationToken); Dispatcher.UIThread.RunJobs(null, TestContext.Current.CancellationToken);
await RenderToFile(target); await RenderToFile(target);
CompareImages(); CompareImages(skipImmediate: true);
} }
[Fact] [Fact]
@ -162,7 +163,7 @@ namespace Avalonia.Skia.RenderTests
Dispatcher.UIThread.RunJobs(null, TestContext.Current.CancellationToken); Dispatcher.UIThread.RunJobs(null, TestContext.Current.CancellationToken);
await RenderToFile(target); await RenderToFile(target);
CompareImages(); CompareImages(skipImmediate: true);
} }
} }
} }

BIN
tests/TestFiles/Skia/Controls/PipsPager/PipsPager_Default.expected.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
tests/TestFiles/Skia/Controls/PipsPager/PipsPager_Preselected_Index.expected.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Loading…
Cancel
Save