Browse Source

Merge branch 'master' into fixes/4303-designwidth-height

pull/4433/head
Steven Kirk 6 years ago
committed by GitHub
parent
commit
89b4903fb9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  2. 68
      samples/ControlCatalog/Pages/ListBoxPage.xaml.cs
  3. 65
      samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
  4. 15
      src/Avalonia.Controls/Repeater/ItemsSourceView.cs
  5. 37
      src/Avalonia.Controls/Utils/SelectedItemsSync.cs
  6. 3
      src/Avalonia.Themes.Default/Accents/BaseDark.xaml
  7. 3
      src/Avalonia.Themes.Default/Accents/BaseLight.xaml
  8. 334
      src/Avalonia.Themes.Default/DatePicker.xaml
  9. 3
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  10. 219
      src/Avalonia.Themes.Default/SplitView.xaml
  11. 283
      src/Avalonia.Themes.Default/TimePicker.xaml
  12. 79
      src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
  13. 5
      src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
  14. 4
      src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
  15. 10
      src/Skia/Avalonia.Skia/TextShaperImpl.cs
  16. 14
      tests/Avalonia.Controls.UnitTests/Utils/SelectedItemsSyncTests.cs

3
samples/ControlCatalog/Pages/ListBoxPage.xaml

@ -11,8 +11,7 @@
Spacing="16">
<StackPanel Orientation="Vertical" Spacing="8">
<ListBox Items="{Binding Items}"
SelectedItem="{Binding SelectedItem}"
SelectedItems="{Binding SelectedItems}"
Selection="{Binding Selection}"
AutoScrollToSelectedItem="True"
SelectionMode="{Binding SelectionMode}"
Width="250"

68
samples/ControlCatalog/Pages/ListBoxPage.xaml.cs

@ -1,10 +1,6 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ReactiveUI;
using ControlCatalog.ViewModels;
namespace ControlCatalog.Pages
{
@ -13,72 +9,12 @@ namespace ControlCatalog.Pages
public ListBoxPage()
{
InitializeComponent();
DataContext = new PageViewModel();
DataContext = new ListBoxPageViewModel();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private class PageViewModel : ReactiveObject
{
private int _counter;
private SelectionMode _selectionMode;
public PageViewModel()
{
Items = new ObservableCollection<string>(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
SelectedItems = new ObservableCollection<string>();
AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem()));
RemoveItemCommand = ReactiveCommand.Create(() =>
{
while (SelectedItems.Count > 0)
{
Items.Remove(SelectedItems[0]);
}
});
SelectRandomItemCommand = ReactiveCommand.Create(() =>
{
var random = new Random();
SelectedItem = Items[random.Next(Items.Count - 1)];
});
}
public ObservableCollection<string> Items { get; }
private string _selectedItem;
public string SelectedItem
{
get { return _selectedItem; }
set { this.RaiseAndSetIfChanged(ref _selectedItem, value); }
}
public ObservableCollection<string> SelectedItems { get; }
public ReactiveCommand<Unit, Unit> AddItemCommand { get; }
public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; }
public ReactiveCommand<Unit, Unit> SelectRandomItemCommand { get; }
public SelectionMode SelectionMode
{
get => _selectionMode;
set
{
SelectedItems.Clear();
this.RaiseAndSetIfChanged(ref _selectionMode, value);
}
}
private string GenerateItem() => $"Item {_counter++.ToString()}";
}
}
}

65
samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using Avalonia.Controls;
using ReactiveUI;
namespace ControlCatalog.ViewModels
{
public class ListBoxPageViewModel : ReactiveObject
{
private int _counter;
private SelectionMode _selectionMode;
public ListBoxPageViewModel()
{
Items = new ObservableCollection<string>(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
Selection = new SelectionModel();
Selection.Select(1);
AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem()));
RemoveItemCommand = ReactiveCommand.Create(() =>
{
while (Selection.SelectedItems.Count > 0)
{
Items.Remove((string)Selection.SelectedItems.First());
}
});
SelectRandomItemCommand = ReactiveCommand.Create(() =>
{
var random = new Random();
using (Selection.Update())
{
Selection.ClearSelection();
Selection.Select(random.Next(Items.Count - 1));
}
});
}
public ObservableCollection<string> Items { get; }
public SelectionModel Selection { get; }
public ReactiveCommand<Unit, Unit> AddItemCommand { get; }
public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; }
public ReactiveCommand<Unit, Unit> SelectRandomItemCommand { get; }
public SelectionMode SelectionMode
{
get => _selectionMode;
set
{
Selection.ClearSelection();
this.RaiseAndSetIfChanged(ref _selectionMode, value);
}
}
private string GenerateItem() => $"Item {_counter++.ToString()}";
}
}

15
src/Avalonia.Controls/Repeater/ItemsSourceView.cs

@ -25,7 +25,6 @@ namespace Avalonia.Controls
{
private readonly IList _inner;
private INotifyCollectionChanged _notifyCollectionChanged;
private int _cachedSize = -1;
/// <summary>
/// Initializes a new instance of the ItemsSourceView class for the specified data source.
@ -54,18 +53,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets the number of items in the collection.
/// </summary>
public int Count
{
get
{
if (_cachedSize == -1)
{
_cachedSize = _inner.Count;
}
return _cachedSize;
}
}
public int Count => _inner.Count;
/// <summary>
/// Gets a value that indicates whether the items source can provide a unique key for each item.
@ -126,7 +114,6 @@ namespace Avalonia.Controls
protected void OnItemsSourceChanged(NotifyCollectionChangedEventArgs args)
{
_cachedSize = _inner.Count;
CollectionChanged?.Invoke(this, args);
}

37
src/Avalonia.Controls/Utils/SelectedItemsSync.cs

@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using Avalonia.Collections;
@ -16,6 +17,7 @@ namespace Avalonia.Controls.Utils
private IList? _items;
private bool _updatingItems;
private bool _updatingModel;
private bool _initializeOnSourceAssignment;
public SelectedItemsSync(ISelectionModel model)
{
@ -63,10 +65,18 @@ namespace Avalonia.Controls.Utils
_updatingModel = true;
_items = items;
using (Model.Update())
if (Model.Source is object)
{
Model.ClearSelection();
Add(items);
using (Model.Update())
{
Model.ClearSelection();
Add(items);
}
}
else if (!_initializeOnSourceAssignment)
{
Model.PropertyChanged += SelectionModelPropertyChanged;
_initializeOnSourceAssignment = true;
}
if (_items is INotifyCollectionChanged incc2)
@ -86,9 +96,11 @@ namespace Avalonia.Controls.Utils
if (_items != null)
{
Model.PropertyChanged -= SelectionModelPropertyChanged;
Model.SelectionChanged -= SelectionModelSelectionChanged;
Model = model;
Model.SelectionChanged += SelectionModelSelectionChanged;
_initializeOnSourceAssignment = false;
try
{
@ -175,6 +187,25 @@ namespace Avalonia.Controls.Utils
}
}
private void SelectionModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (_initializeOnSourceAssignment &&
_items != null &&
e.PropertyName == nameof(SelectionModel.Source))
{
try
{
_updatingModel = true;
Add(_items);
_initializeOnSourceAssignment = false;
}
finally
{
_updatingModel = false;
}
}
}
private void SelectionModelSelectionChanged(object sender, SelectionModelSelectionChangedEventArgs e)
{
if (_updatingModel)

3
src/Avalonia.Themes.Default/Accents/BaseDark.xaml

@ -58,6 +58,9 @@
<SolidColorBrush x:Key="NotificationCardWarningBackgroundBrush" Color="#FDB328" Opacity="0.75"/>
<SolidColorBrush x:Key="NotificationCardErrorBackgroundBrush" Color="#BD202C" Opacity="0.75"/>
<SolidColorBrush x:Key="DatePickerFlyoutPresenterHighlightFill" Color="{DynamicResource ThemeAccentColor}" Opacity="0.4" />
<SolidColorBrush x:Key="TimePickerFlyoutPresenterHighlightFill" Color="{DynamicResource ThemeAccentColor}" Opacity="0.4" />
<SolidColorBrush x:Key="ThemeControlTransparentBrush" Color="Transparent" />
<Thickness x:Key="ThemeBorderThickness">1,1,1,1</Thickness>

3
src/Avalonia.Themes.Default/Accents/BaseLight.xaml

@ -61,6 +61,9 @@
<SolidColorBrush x:Key="NotificationCardWarningBackgroundBrush" Color="#FDB328" Opacity="0.75"/>
<SolidColorBrush x:Key="NotificationCardErrorBackgroundBrush" Color="#BD202C" Opacity="0.75"/>
<SolidColorBrush x:Key="DatePickerFlyoutPresenterHighlightFill" Color="{DynamicResource ThemeAccentColor}" Opacity="0.4" />
<SolidColorBrush x:Key="TimePickerFlyoutPresenterHighlightFill" Color="{DynamicResource ThemeAccentColor}" Opacity="0.4" />
<SolidColorBrush x:Key="ThemeControlTransparentBrush" Color="Transparent" />
<Thickness x:Key="ThemeBorderThickness">1</Thickness>

334
src/Avalonia.Themes.Default/DatePicker.xaml

@ -0,0 +1,334 @@
<!--
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
-->
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Styles.Resources>
<Thickness x:Key="DatePickerTopHeaderMargin">0,0,0,4</Thickness>
<x:Double x:Key="DatePickerFlyoutPresenterHighlightHeight">40</x:Double>
<x:Double x:Key="DatePickerFlyoutPresenterItemHeight">40</x:Double>
<x:Double x:Key="DatePickerFlyoutPresenterAcceptDismissHostGridHeight">41</x:Double>
<x:Double x:Key="DatePickerThemeMinWidth">296</x:Double>
<x:Double x:Key="DatePickerThemeMaxWidth">456</x:Double>
<Thickness x:Key="DatePickerFlyoutPresenterItemPadding">0,3,0,6</Thickness>
<Thickness x:Key="DatePickerFlyoutPresenterMonthPadding">9,3,0,6</Thickness>
<Thickness x:Key="DatePickerHostPadding">0,3,0,6</Thickness>
<Thickness x:Key="DatePickerHostMonthPadding">9,3,0,6</Thickness>
<x:Double x:Key="DatePickerSpacerThemeWidth">1</x:Double>
</Styles.Resources>
<!-- Styles for the items displayed in the selectors -->
<Style Selector="ListBoxItem.DateTimePickerItem">
<Setter Property="Padding" Value="{DynamicResource DatePickerFlyoutPresenterItemPadding}"/>
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
<Style Selector="ListBoxItem.DateTimePickerItem:selected">
<Setter Property="IsHitTestVisible" Value="False"/>
</Style>
<Style Selector="ListBoxItem.DateTimePickerItem:selected /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="Transparent"/>
</Style>
<Style Selector="ListBoxItem.DateTimePickerItem:selected /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="ListBoxItem.DateTimePickerItem.MonthItem">
<Setter Property="Padding" Value="{DynamicResource DatePickerFlyoutPresenterMonthPadding}"/>
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
</Style>
<!-- This is used for both the accept/dismiss & repeatbuttons in the presenter-->
<Style Selector=":is(Button).DateTimeFlyoutButtonStyle">
<Setter Property="Background" Value="{DynamicResource ThemeControlTransparentBrush}" />
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}">
<ContentPresenter x:Name="ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{DynamicResource ThemeControlTransparentBrush}"
BorderThickness="{DynamicResource DateTimeFlyoutButtonBorderThickness}"
Content="{TemplateBinding Content}"
TextBlock.Foreground="{DynamicResource ThemeForegroundBrush}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector=":is(Button).DateTimeFlyoutButtonStyle:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightLowBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlTransparentBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector=":is(Button).DateTimeFlyoutButtonStyle:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlTransparentBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="RepeatButton.UpButton">
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Height" Value="22" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Focusable" Value="False" />
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightLowBrush}" />
<Setter Property="Content">
<Template>
<Viewbox Height="10" Width="10" HorizontalAlignment="Center" VerticalAlignment="Center">
<Path Stroke="{Binding $parent[RepeatButton].Foreground}" StrokeThickness="1" Data="M 0,9 L 9,0 L 18,9"/>
</Viewbox>
</Template>
</Setter>
</Style>
<Style Selector="RepeatButton.DownButton">
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Height" Value="22" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Focusable" Value="False" />
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightLowBrush}" />
<Setter Property="Content">
<Template>
<Viewbox Height="10" Width="10" HorizontalAlignment="Center" VerticalAlignment="Center">
<Path Stroke="{Binding $parent[RepeatButton].Foreground}" StrokeThickness="1" Data="M 0,0 L 9,9 L 18,0"/>
</Viewbox>
</Template>
</Setter>
</Style>
<Style Selector="DatePicker">
<Setter Property="FontSize" Value="{DynamicResource FontSizeNormal}" />
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}" />
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<ControlTemplate>
<Grid Name="LayoutRoot" Margin="{TemplateBinding Padding}" RowDefinitions="Auto,*">
<ContentPresenter Name="HeaderContentPresenter" Grid.Row="0"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Margin="{DynamicResource DatePickerTopHeaderMargin}"
MaxWidth="{DynamicResource DatePickerThemeMaxWidth}"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"/>
<Button Name="FlyoutButton" Grid.Row="1"
Foreground="{TemplateBinding Foreground}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
IsEnabled="{TemplateBinding IsEnabled}"
MinWidth="{DynamicResource DatePickerThemeMinWidth}"
MaxWidth="{DynamicResource DatePickerThemeMaxWidth}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
TemplatedControl.IsTemplateFocusTarget="True">
<Button.Template>
<ControlTemplate>
<ContentPresenter Name="ContentPresenter"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"/>
</ControlTemplate>
</Button.Template>
<Grid Name="ButtonContentGrid" ColumnDefinitions="78*,Auto,132*,Auto,78*">
<TextBlock Name="DayText" Text="day" HorizontalAlignment="Center"
Padding="{DynamicResource DatePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
<TextBlock Name="MonthText" Text="month" TextAlignment="Left"
Padding="{DynamicResource DatePickerHostMonthPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
<TextBlock Name="YearText" Text="year" HorizontalAlignment="Center"
Padding="{DynamicResource DatePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
<Rectangle x:Name="FirstSpacer"
Fill="{DynamicResource ThemeControlMidHighBrush}"
HorizontalAlignment="Center"
Width="1"
Grid.Column="1" />
<Rectangle x:Name="SecondSpacer"
Fill="{DynamicResource ThemeControlMidHighBrush}"
HorizontalAlignment="Center"
Width="1"
Grid.Column="3" />
</Grid>
</Button>
<Popup Name="Popup" WindowManagerAddShadowHint="False"
StaysOpen="False" PlacementTarget="{TemplateBinding}"
PlacementMode="Bottom">
<DatePickerPresenter Name="PickerPresenter" />
</Popup>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="DatePicker /template/ ContentPresenter#HeaderContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="DatePicker:disabled /template/ Rectangle">
<!--<Setter Property="Fill" Value="{DynamicResource DatePickerSpacerFillDisabled}"/>-->
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" />
</Style>
<Style Selector="DatePicker /template/ Button#FlyoutButton:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlHighBrush}"/>
<!--<Setter Property="Background" Value="{DynamicResource DatePickerButtonBackgroundPointerOver}"/>-->
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="DatePicker /template/ Button#FlyoutButton:pressed /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlLowBrush}"/>
<Setter Property="Background">
<SolidColorBrush Color="{DynamicResource ThemeControlMidHighColor}" Opacity="0.6" />
</Setter>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="DatePicker /template/ Button#FlyoutButton:disabled /template/ ContentPresenter">
<!--<Setter Property="BorderBrush" Value="{DynamicResource DatePickerButtonBorderBrushDisabled}"/>
<Setter Property="Background" Value="{DynamicResource DatePickerButtonBackgroundDisabled}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource DatePickerButtonForegroundDisabled}"/>-->
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" />
</Style>
<!-- Changes foreground for watermark text when SelectedDate is null-->
<Style Selector="DatePicker:hasnodate /template/ Button#FlyoutButton TextBlock">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundLowBrush}"/>
</Style>
<!--WinUI: DatePickerFlyoutPresenter-->
<Style Selector="DatePickerPresenter">
<Setter Property="Width" Value="296" />
<Setter Property="MinWidth" Value="296" />
<Setter Property="MaxHeight" Value="398" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{DynamicResource FontSizeNormal}" />
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource DateTimeFlyoutBorderThickness}" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="Background" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{DynamicResource DateTimeFlyoutBorderPadding}"
MaxHeight="398">
<Grid Name="ContentRoot" RowDefinitions="*,Auto">
<Grid Name="PickerContainer">
<!--Column Definitions set in code, ignore here-->
<Panel Name="MonthHost">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden">
<DateTimePickerPanel Name="MonthSelector"
PanelType="Month"
ItemHeight="{DynamicResource DatePickerFlyoutPresenterItemHeight}"
ShouldLoop="True" />
</ScrollViewer>
<RepeatButton Name="MonthUpButton"
Classes="DateTimeFlyoutButtonStyle UpButton"/>
<RepeatButton Name="MonthDownButton"
Classes="DateTimeFlyoutButtonStyle DownButton"/>
</Panel>
<Panel Name="DayHost">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden">
<DateTimePickerPanel Name="DaySelector"
PanelType="Day"
ItemHeight="{DynamicResource DatePickerFlyoutPresenterItemHeight}"
ShouldLoop="True" />
</ScrollViewer>
<RepeatButton Name="DayUpButton"
Classes="DateTimeFlyoutButtonStyle UpButton"/>
<RepeatButton Name="DayDownButton"
Classes="DateTimeFlyoutButtonStyle DownButton"/>
</Panel>
<Panel Name="YearHost">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden">
<DateTimePickerPanel Name="YearSelector"
PanelType="Year"
ItemHeight="{DynamicResource DatePickerFlyoutPresenterItemHeight}"
ShouldLoop="False" />
</ScrollViewer>
<RepeatButton Name="YearUpButton"
Classes="DateTimeFlyoutButtonStyle UpButton"/>
<RepeatButton Name="YearDownButton"
Classes="DateTimeFlyoutButtonStyle DownButton"/>
</Panel>
<Rectangle Name="HighlightRect" IsHitTestVisible="False" ZIndex="-1"
Fill="{DynamicResource DatePickerFlyoutPresenterHighlightFill}"
Grid.Column="0" Grid.ColumnSpan="5" VerticalAlignment="Center"
Height="{DynamicResource DatePickerFlyoutPresenterHighlightHeight}" />
<Rectangle Name="FirstSpacer"
Fill="{DynamicResource ThemeControlMidHighBrush}"
HorizontalAlignment="Center"
Width="{DynamicResource DatePickerSpacerThemeWidth}"
Grid.Column="1" />
<Rectangle Name="SecondSpacer"
Fill="{DynamicResource ThemeControlMidHighBrush}"
HorizontalAlignment="Center"
Width="{DynamicResource DatePickerSpacerThemeWidth}"
Grid.Column="3" />
</Grid>
<Grid Grid.Row="1" Height="{DynamicResource DatePickerFlyoutPresenterAcceptDismissHostGridHeight}"
Name="AcceptDismissGrid" ColumnDefinitions="*,*">
<Rectangle Height="{DynamicResource DatePickerSpacerThemeWidth}" VerticalAlignment="Top"
Fill="{DynamicResource ThemeControlMidHighBrush}"
Grid.ColumnSpan="2"/>
<Button Name="AcceptButton" Grid.Column="0" Classes="DateTimeFlyoutButtonStyle"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Path Stroke="{Binding $parent[Button].Foreground}" StrokeLineCap="Round"
StrokeThickness="0.75" Data="M0.5,8.5 5,13.5 15.5,3" />
</Button>
<Button Name="DismissButton" Grid.Column="1" Classes="DateTimeFlyoutButtonStyle"
FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Path Stroke="{Binding $parent[Button].Foreground}" StrokeLineCap="Round"
StrokeThickness="0.75" Data="M2,2 14,14 M2,14 14 2" />
</Button>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="DatePickerPresenter /template/ Panel RepeatButton">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="DatePickerPresenter /template/ Panel:pointerover RepeatButton">
<Setter Property="IsVisible" Value="True" />
</Style>
</Styles>

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

@ -55,4 +55,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.NotificationCard.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.NativeMenuBar.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ToggleSwitch.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.SplitView.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.DatePicker.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.TimePicker.xaml?assembly=Avalonia.Themes.Default"/>
</Styles>

219
src/Avalonia.Themes.Default/SplitView.xaml

@ -0,0 +1,219 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Styles.Resources>
<x:Double x:Key="SplitViewOpenPaneThemeLength">320</x:Double>
<x:Double x:Key="SplitViewCompactPaneThemeLength">48</x:Double>
<!-- Not used here (directly) since they're strings, but preserving for reference
<x:String x:Key="SplitViewPaneAnimationOpenDuration">00:00:00.2</x:String>
<x:String x:Key="SplitViewPaneAnimationOpenPreDuration">00:00:00.19999</x:String>
<x:String x:Key="SplitViewPaneAnimationCloseDuration">00:00:00.1</x:String>-->
</Styles.Resources>
<Style Selector="SplitView">
<Setter Property="OpenPaneLength" Value="{DynamicResource SplitViewOpenPaneThemeLength}" />
<Setter Property="CompactPaneLength" Value="{DynamicResource SplitViewCompactPaneThemeLength}" />
<Setter Property="PaneBackground" Value="{DynamicResource ThemeControlHighlightLowBrush}" />
</Style>
<!-- Left -->
<Style Selector="SplitView:left">
<Setter Property="Template">
<ControlTemplate>
<Grid Name="Container" Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<!-- why is this throwing a binding error? -->
<ColumnDefinition Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.PaneColumnGridLength}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Panel Name="PART_PaneRoot" Background="{TemplateBinding PaneBackground}"
ClipToBounds="True"
HorizontalAlignment="Left"
ZIndex="100">
<Border Child="{TemplateBinding Pane}"/>
<Rectangle Name="HCPaneBorder" Fill="{DynamicResource SystemControlForegroundTransparentBrush}" Width="1" HorizontalAlignment="Right" />
</Panel>
<Panel Name="ContentRoot">
<Border Child="{TemplateBinding Content}" />
<Rectangle Name="LightDismissLayer"/>
</Panel>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<!-- Overlay -->
<Style Selector="SplitView:overlay:left /template/ Panel#PART_PaneRoot">
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ClosedPaneWidth}" />
<!-- ColumnSpan should be 2 -->
<Setter Property="Grid.ColumnSpan" Value="1"/>
<Setter Property="Grid.Column" Value="0"/>
</Style>
<Style Selector="SplitView:overlay:left /template/ Panel#ContentRoot">
<Setter Property="Grid.Column" Value="1"/>
<Setter Property="Grid.ColumnSpan" Value="2"/>
</Style>
<!-- CompactInline -->
<Style Selector="SplitView:compactinline:left /template/ Panel#PART_PaneRoot">
<Setter Property="Grid.ColumnSpan" Value="1"/>
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ClosedPaneWidth}" />
</Style>
<Style Selector="SplitView:compactinline:left /template/ Panel#ContentRoot">
<Setter Property="Grid.Column" Value="1"/>
<Setter Property="Grid.ColumnSpan" Value="1"/>
</Style>
<!-- CompactOverlay -->
<Style Selector="SplitView:compactoverlay:left /template/ Panel#PART_PaneRoot">
<!-- ColumnSpan should be 2 -->
<Setter Property="Grid.ColumnSpan" Value="1"/>
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ClosedPaneWidth}" />
</Style>
<Style Selector="SplitView:compactoverlay:left /template/ Panel#ContentRoot">
<Setter Property="Grid.Column" Value="1"/>
<Setter Property="Grid.ColumnSpan" Value="1"/>
</Style>
<!-- Inline -->
<Style Selector="SplitView:inline:left /template/ Panel#PART_PaneRoot">
<Setter Property="Grid.ColumnSpan" Value="1"/>
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ClosedPaneWidth}" />
</Style>
<Style Selector="SplitView:inline:left /template/ Panel#ContentRoot">
<Setter Property="Grid.Column" Value="1"/>
<Setter Property="Grid.ColumnSpan" Value="1"/>
</Style>
<!-- Right -->
<Style Selector="SplitView:right">
<Setter Property="Template">
<ControlTemplate>
<Grid Name="Container" Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.PaneColumnGridLength}"/>
</Grid.ColumnDefinitions>
<Panel Name="PART_PaneRoot" Background="{TemplateBinding PaneBackground}"
ClipToBounds="True"
HorizontalAlignment="Right"
ZIndex="100">
<Border Child="{TemplateBinding Pane}"/>
<Rectangle Name="HCPaneBorder"
Fill="{DynamicResource SystemControlForegroundTransparentBrush}"
Width="1" HorizontalAlignment="Left" />
</Panel>
<Panel Name="ContentRoot">
<Border Child="{TemplateBinding Content}" />
<Rectangle Name="LightDismissLayer"/>
</Panel>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<!-- Overlay -->
<Style Selector="SplitView:overlay:right /template/ Panel#PART_PaneRoot">
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ClosedPaneWidth}" />
<Setter Property="Grid.ColumnSpan" Value="2"/>
<Setter Property="Grid.Column" Value="1"/>
</Style>
<Style Selector="SplitView:overlay:right /template/ Panel#ContentRoot">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="Grid.ColumnSpan" Value="2"/>
</Style>
<!-- CompactInline -->
<Style Selector="SplitView:compactinline:right /template/ Panel#PART_PaneRoot">
<Setter Property="Grid.ColumnSpan" Value="1"/>
<Setter Property="Grid.Column" Value="1"/>
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ClosedPaneWidth}" />
</Style>
<Style Selector="SplitView:compactinline:right /template/ Panel#ContentRoot">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="Grid.ColumnSpan" Value="1"/>
</Style>
<!-- CompactOverlay -->
<Style Selector="SplitView:compactoverlay:right /template/ Panel#PART_PaneRoot">
<Setter Property="Grid.ColumnSpan" Value="2"/>
<Setter Property="Grid.Column" Value="1"/>
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ClosedPaneWidth}" />
</Style>
<Style Selector="SplitView:compactoverlay:right /template/ Panel#ContentRoot">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="Grid.ColumnSpan" Value="1"/>
</Style>
<!-- Inline -->
<Style Selector="SplitView:inline:right /template/ Panel#PART_PaneRoot">
<Setter Property="Grid.ColumnSpan" Value="1"/>
<Setter Property="Grid.Column" Value="1"/>
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ClosedPaneWidth}" />
</Style>
<Style Selector="SplitView:inline:right /template/ Panel#ContentRoot">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="Grid.ColumnSpan" Value="1"/>
</Style>
<!-- Open/Close Pane animation -->
<Style Selector="SplitView:open /template/ Panel#PART_PaneRoot">
<Setter Property="Transitions">
<Transitions>
<DoubleTransition Property="Width" Duration="00:00:00.2" Easing="0.1,0.9,0.2,1.0" />
</Transitions>
</Setter>
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=OpenPaneLength}" />
</Style>
<Style Selector="SplitView:open /template/ Rectangle#LightDismissLayer">
<Setter Property="Transitions">
<Transitions>
<DoubleTransition Property="Opacity" Duration="00:00:00.2" Easing="0.1,0.9,0.2,1.0" />
</Transitions>
</Setter>
<Setter Property="Opacity" Value="1.0"/>
</Style>
<Style Selector="SplitView:closed /template/ Panel#PART_PaneRoot">
<Setter Property="Transitions">
<Transitions>
<DoubleTransition Property="Width" Duration="00:00:00.1" Easing="0.1,0.9,0.2,1.0" />
</Transitions>
</Setter>
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ClosedPaneWidth}" />
</Style>
<Style Selector="SplitView:closed /template/ Rectangle#LightDismissLayer">
<Setter Property="Transitions">
<Transitions>
<DoubleTransition Property="Opacity" Duration="00:00:00.2" Easing="0.1,0.9,0.2,1.0" />
</Transitions>
</Setter>
<Setter Property="Opacity" Value="0.0"/>
</Style>
<Style Selector="SplitView /template/ Rectangle#LightDismissLayer">
<Setter Property="IsVisible" Value="False"/>
<Setter Property="Fill" Value="Transparent" />
</Style>
<Style Selector="SplitView:lightdismiss /template/ Rectangle#LightDismissLayer">
<Setter Property="Fill" Value="{DynamicResource SplitViewLightDismissOverlayBackground}" />
</Style>
<Style Selector="SplitView:overlay:open /template/ Rectangle#LightDismissLayer">
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="SplitView:compactoverlay:open /template/ Rectangle#LightDismissLayer">
<Setter Property="IsVisible" Value="True"/>
</Style>
</Styles>

283
src/Avalonia.Themes.Default/TimePicker.xaml

@ -0,0 +1,283 @@
<!--
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
-->
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Styles.Resources>
<x:Double x:Key="TimePickerFlyoutPresenterItemHeight">40</x:Double>
<x:Double x:Key="TimePickerSpacerThemeWidth">1</x:Double>
<Thickness x:Key="TimePickerBorderThemeThickness">1</Thickness>
<Thickness x:Key="TimePickerTopHeaderMargin">0,0,0,4</Thickness>
<x:Double x:Key="TimePickerFlyoutPresenterHighlightHeight">40</x:Double>
<x:Double x:Key="TimePickerFlyoutPresenterAcceptDismissHostGridHeight">41</x:Double>
<x:Double x:Key="TimePickerThemeMinWidth">242</x:Double>
<x:Double x:Key="TimePickerThemeMaxWidth">456</x:Double>
<Thickness x:Key="TimePickerFlyoutPresenterItemPadding">0,3,0,6</Thickness>
<Thickness x:Key="TimePickerHostPadding">0,3,0,6</Thickness>
</Styles.Resources>
<Style Selector="ListBoxItem.DateTimePickerItem.HourItem">
<Setter Property="Padding" Value="{DynamicResource TimePickerFlyoutPresenterItemPadding}" />
</Style>
<Style Selector="ListBoxItem.DateTimePickerItem.MinuteItem">
<Setter Property="Padding" Value="{DynamicResource TimePickerFlyoutPresenterItemPadding}" />
</Style>
<Style Selector="ListBoxItem.DateTimePickerItem.TimePeriodItem">
<Setter Property="Padding" Value="{DynamicResource TimePickerFlyoutPresenterItemPadding}" />
</Style>
<Style Selector="TimePicker">
<Setter Property="FontSize" Value="{DynamicResource FontSizeNormal}" />
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}" />
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource TimePickerBorderThemeThickness}"/>
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<ControlTemplate>
<Grid Name="LayoutRoot" Margin="{TemplateBinding Padding}" RowDefinitions="Auto,*">
<ContentPresenter x:Name="HeaderContentPresenter"
Grid.Row="0"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Margin="{DynamicResource TimePickerTopHeaderMargin}"
MaxWidth="{DynamicResource TimePickerThemeMaxWidth}"
TextBlock.Foreground="{DynamicResource TimePickerHeaderForeground}"
HorizontalAlignment="Stretch"
VerticalAlignment="Top" />
<Button x:Name="FlyoutButton"
Grid.Row="1"
Foreground="{TemplateBinding Foreground}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
IsEnabled="{TemplateBinding IsEnabled}"
MinWidth="{DynamicResource TimePickerThemeMinWidth}"
MaxWidth="{DynamicResource TimePickerThemeMaxWidth}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Top"
VerticalContentAlignment="Stretch">
<Button.Template>
<ControlTemplate>
<ContentPresenter Name="ContentPresenter"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch" />
</ControlTemplate>
</Button.Template>
<Grid Name="FlyoutButtonContentGrid">
<!--Ignore col defs here, set in code-->
<Border x:Name="FirstPickerHost" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="HourTextBlock"
HorizontalAlignment="Center"
Padding="{DynamicResource TimePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}" />
</Border>
<Rectangle Name="FirstColumnDivider"
Fill="{DynamicResource ThemeControlMidHighBrush}"
HorizontalAlignment="Center"
Width="{DynamicResource TimePickerSpacerThemeWidth}"
Grid.Column="1" />
<Border x:Name="SecondPickerHost" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="MinuteTextBlock"
HorizontalAlignment="Center"
Padding="{DynamicResource TimePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
</Border>
<Rectangle Name="SecondColumnDivider"
Fill="{DynamicResource ThemeControlMidHighBrush}"
HorizontalAlignment="Center"
Width="{DynamicResource TimePickerSpacerThemeWidth}"
Grid.Column="3" />
<Border x:Name="ThirdPickerHost" Grid.Column="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="PeriodTextBlock"
HorizontalAlignment="Center"
Padding="{DynamicResource TimePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}" />
</Border>
</Grid>
</Button>
<Popup Name="Popup" WindowManagerAddShadowHint="False"
StaysOpen="False" PlacementTarget="{TemplateBinding}"
PlacementMode="Bottom">
<TimePickerPresenter Name="PickerPresenter" />
</Popup>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="TimePicker:disabled /template/ ContentPresenter#HeaderContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="TimePicker:disabled /template/ Rectangle">
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
</Style>
<Style Selector="TimePicker /template/ Button#FlyoutButton:pointerover /template/ ContentPresenter">
<!--<Setter Property="Background" Value="{DynamicResource TimePickerButtonBackgroundPointerOver}"/>-->
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlHighBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="TimePicker /template/ Button:pressed /template/ ContentPresenter">
<Setter Property="Background">
<SolidColorBrush Color="{DynamicResource ThemeControlMidHighColor}" Opacity="0.6" />
</Setter>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlLowBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="TimePicker /template/ Button:disabled /template/ ContentPresenter">
<!--<Setter Property="Background" Value="{DynamicResource TimePickerButtonBackgroundDisabled}"/>
<Setter Property="BorderBrush" Value="{DynamicResource TimePickerButtonBorderBrushDisabled}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TimePickerButtonForegroundDisabled}"/>-->
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" />
</Style>
<Style Selector="TimePicker:hasnotime /template/ Button#FlyoutButton TextBlock">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundLowBrush}"/>
</Style>
<Style Selector="TimePickerPresenter">
<Setter Property="Width" Value="242" />
<Setter Property="MinWidth" Value="242" />
<Setter Property="MaxHeight" Value="398" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource DateTimeFlyoutBorderThickness}" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="Background"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{DynamicResource DateTimeFlyoutBorderPadding}"
MaxHeight="398">
<Grid Name="ContentPanel" RowDefinitions="*,Auto">
<Grid Name="PickerContainer">
<!--Ignore col defs here, set in code-->
<Panel Name="HourHost" Grid.Column="0">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden">
<DateTimePickerPanel Name="HourSelector"
PanelType="Hour"
ShouldLoop="True"
ItemHeight="{DynamicResource TimePickerFlyoutPresenterItemHeight}"/>
</ScrollViewer>
<RepeatButton Name="HourUpButton"
Classes="DateTimeFlyoutButtonStyle UpButton"/>
<RepeatButton Name="HourDownButton"
Classes="DateTimeFlyoutButtonStyle DownButton"/>
</Panel>
<Panel Name="MinuteHost" Grid.Column="2">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden">
<DateTimePickerPanel Name="MinuteSelector"
PanelType="Minute"
ShouldLoop="True"
ItemHeight="{DynamicResource TimePickerFlyoutPresenterItemHeight}"/>
</ScrollViewer>
<RepeatButton Name="MinuteUpButton"
Classes="DateTimeFlyoutButtonStyle UpButton"/>
<RepeatButton Name="MinuteDownButton"
Classes="DateTimeFlyoutButtonStyle DownButton"/>
</Panel>
<Panel Name="PeriodHost" Grid.Column="4">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Hidden">
<DateTimePickerPanel Name="PeriodSelector"
PanelType="TimePeriod"
ShouldLoop="False"
ItemHeight="{DynamicResource TimePickerFlyoutPresenterItemHeight}"/>
</ScrollViewer>
<RepeatButton Name="PeriodUpButton"
Classes="DateTimeFlyoutButtonStyle UpButton"/>
<RepeatButton Name="PeriodDownButton"
Classes="DateTimeFlyoutButtonStyle DownButton"/>
</Panel>
<Rectangle x:Name="HighlightRect" ZIndex="-1"
Fill="{DynamicResource TimePickerFlyoutPresenterHighlightFill}"
Grid.Column="0"
Grid.ColumnSpan="5"
VerticalAlignment="Center"
Height="{DynamicResource TimePickerFlyoutPresenterHighlightHeight}" />
<Rectangle Name="FirstSpacer"
Fill="{DynamicResource ThemeControlMidHighBrush}"
HorizontalAlignment="Center"
Width="{DynamicResource TimePickerSpacerThemeWidth}"
Grid.Column="1" />
<Rectangle Name="SecondSpacer"
Fill="{DynamicResource ThemeControlMidHighBrush}"
HorizontalAlignment="Center"
Width="{DynamicResource TimePickerSpacerThemeWidth}"
Grid.Column="3" />
</Grid>
<Grid Grid.Row="1" Height="{DynamicResource TimePickerFlyoutPresenterAcceptDismissHostGridHeight}"
Name="AcceptDismissHostGrid" ColumnDefinitions="*,*">
<Rectangle Height="{DynamicResource TimePickerSpacerThemeWidth}"
VerticalAlignment="Top"
Fill="{DynamicResource ThemeControlMidHighBrush}"
Grid.ColumnSpan="2" />
<Button Name="AcceptButton" Grid.Column="0" Classes="DateTimeFlyoutButtonStyle"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Path Stroke="{Binding $parent[Button].Foreground}" StrokeLineCap="Round"
StrokeThickness="0.75" Data="M0.5,8.5 5,13.5 15.5,3" />
</Button>
<Button Name="DismissButton" Grid.Column="1" Classes="DateTimeFlyoutButtonStyle"
FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Path Stroke="{Binding $parent[Button].Foreground}" StrokeLineCap="Round"
StrokeThickness="0.75" Data="M2,2 14,14 M2,14 14 2" />
</Button>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="TimePickerPresenter /template/ Panel RepeatButton">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="TimePickerPresenter /template/ Panel:pointerover RepeatButton">
<Setter Property="IsVisible" Value="True" />
</Style>
</Styles>

79
src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs

@ -31,7 +31,8 @@ namespace Avalonia.Media.TextFormatting
case TextWrapping.WrapWithOverflow:
case TextWrapping.Wrap:
{
textLine = PerformTextWrapping(textRuns, textRange, paragraphWidth, paragraphProperties);
textLine = PerformTextWrapping(textRuns, textRange, paragraphWidth, paragraphProperties,
nextLineBreak);
break;
}
default:
@ -118,7 +119,7 @@ namespace Avalonia.Media.TextFormatting
/// <param name="textRuns">The text run's.</param>
/// <param name="length">The length to split at.</param>
/// <returns>The split text runs.</returns>
internal static SplitTextRunsResult SplitTextRuns(IReadOnlyList<ShapedTextCharacters> textRuns, int length)
internal static SplitTextRunsResult SplitTextRuns(List<ShapedTextCharacters> textRuns, int length)
{
var currentLength = 0;
@ -134,13 +135,13 @@ namespace Avalonia.Media.TextFormatting
var firstCount = currentRun.GlyphRun.Characters.Length >= 1 ? i + 1 : i;
var first = new ShapedTextCharacters[firstCount];
var first = new List<ShapedTextCharacters>(firstCount);
if (firstCount > 1)
{
for (var j = 0; j < i; j++)
{
first[j] = textRuns[j];
first.Add(textRuns[j]);
}
}
@ -148,7 +149,7 @@ namespace Avalonia.Media.TextFormatting
if (currentLength + currentRun.GlyphRun.Characters.Length == length)
{
var second = new ShapedTextCharacters[secondCount];
var second = new List<ShapedTextCharacters>(secondCount);
var offset = currentRun.GlyphRun.Characters.Length > 1 ? 1 : 0;
@ -156,11 +157,11 @@ namespace Avalonia.Media.TextFormatting
{
for (var j = 0; j < secondCount; j++)
{
second[j] = textRuns[i + j + offset];
second.Add(textRuns[i + j + offset]);
}
}
first[i] = currentRun;
first.Add(currentRun);
return new SplitTextRunsResult(first, second);
}
@ -168,22 +169,22 @@ namespace Avalonia.Media.TextFormatting
{
secondCount++;
var second = new ShapedTextCharacters[secondCount];
var second = new List<ShapedTextCharacters>(secondCount);
var split = currentRun.Split(length - currentLength);
first.Add(split.First);
second.Add(split.Second);
if (secondCount > 0)
{
for (var j = 1; j < secondCount; j++)
{
second[j] = textRuns[i + j];
second.Add(textRuns[i + j]);
}
}
var split = currentRun.Split(length - currentLength);
first[i] = split.First;
second[0] = split.Second;
return new SplitTextRunsResult(first, second);
}
}
@ -201,7 +202,7 @@ namespace Avalonia.Media.TextFormatting
/// <returns>
/// The formatted text runs.
/// </returns>
private static IReadOnlyList<ShapedTextCharacters> FetchTextRuns(ITextSource textSource,
private static List<ShapedTextCharacters> FetchTextRuns(ITextSource textSource,
int firstTextSourceIndex, TextLineBreak previousLineBreak, out TextLineBreak nextLineBreak)
{
nextLineBreak = default;
@ -212,8 +213,10 @@ namespace Avalonia.Media.TextFormatting
if (previousLineBreak != null)
{
foreach (var shapedCharacters in previousLineBreak.RemainingCharacters)
for (var index = 0; index < previousLineBreak.RemainingCharacters.Count; index++)
{
var shapedCharacters = previousLineBreak.RemainingCharacters[index];
if (shapedCharacters == null)
{
continue;
@ -225,6 +228,14 @@ namespace Avalonia.Media.TextFormatting
{
var splitResult = SplitTextRuns(textRuns, currentLength + runLineBreak.PositionWrap);
if (++index < previousLineBreak.RemainingCharacters.Count)
{
for (; index < previousLineBreak.RemainingCharacters.Count; index++)
{
splitResult.Second.Add(previousLineBreak.RemainingCharacters[index]);
}
}
nextLineBreak = new TextLineBreak(splitResult.Second);
return splitResult.First;
@ -323,9 +334,10 @@ namespace Avalonia.Media.TextFormatting
/// <param name="textRange">The text range that is covered by the text runs.</param>
/// <param name="paragraphWidth">The paragraph width.</param>
/// <param name="paragraphProperties">The text paragraph properties.</param>
/// <param name="currentLineBreak">The current line break if the line was explicitly broken.</param>
/// <returns>The wrapped text line.</returns>
private static TextLine PerformTextWrapping(IReadOnlyList<ShapedTextCharacters> textRuns, TextRange textRange,
double paragraphWidth, TextParagraphProperties paragraphProperties)
private static TextLine PerformTextWrapping(List<ShapedTextCharacters> textRuns, TextRange textRange,
double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak currentLineBreak)
{
var availableWidth = paragraphWidth;
var currentWidth = 0.0;
@ -388,8 +400,22 @@ namespace Avalonia.Media.TextFormatting
var textLineMetrics = TextLineMetrics.Create(splitResult.First,
new TextRange(textRange.Start, currentLength), paragraphWidth, paragraphProperties);
var lineBreak = splitResult.Second != null && splitResult.Second.Count > 0 ?
new TextLineBreak(splitResult.Second) :
var remainingCharacters = splitResult.Second;
if (currentLineBreak?.RemainingCharacters != null)
{
if (remainingCharacters != null)
{
remainingCharacters.AddRange(currentLineBreak.RemainingCharacters);
}
else
{
remainingCharacters = new List<ShapedTextCharacters>(currentLineBreak.RemainingCharacters);
}
}
var lineBreak = remainingCharacters != null && remainingCharacters.Count > 0 ?
new TextLineBreak(remainingCharacters) :
null;
return new TextLineImpl(splitResult.First, textLineMetrics, lineBreak);
@ -403,7 +429,10 @@ namespace Avalonia.Media.TextFormatting
}
return new TextLineImpl(textRuns,
TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties));
TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties),
currentLineBreak?.RemainingCharacters != null ?
new TextLineBreak(currentLineBreak.RemainingCharacters) :
null);
}
/// <summary>
@ -434,7 +463,7 @@ namespace Avalonia.Media.TextFormatting
internal readonly struct SplitTextRunsResult
{
public SplitTextRunsResult(IReadOnlyList<ShapedTextCharacters> first, IReadOnlyList<ShapedTextCharacters> second)
public SplitTextRunsResult(List<ShapedTextCharacters> first, List<ShapedTextCharacters> second)
{
First = first;
@ -447,7 +476,7 @@ namespace Avalonia.Media.TextFormatting
/// <value>
/// The first text runs.
/// </value>
public IReadOnlyList<ShapedTextCharacters> First { get; }
public List<ShapedTextCharacters> First { get; }
/// <summary>
/// Gets the second text runs.
@ -455,7 +484,7 @@ namespace Avalonia.Media.TextFormatting
/// <value>
/// The second text runs.
/// </value>
public IReadOnlyList<ShapedTextCharacters> Second { get; }
public List<ShapedTextCharacters> Second { get; }
}
private struct TextRunEnumerator

5
src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs

@ -183,7 +183,10 @@ namespace Avalonia.Media.TextFormatting
var glyphRun = TextShaper.Current.ShapeText(new ReadOnlySlice<char>(s_empty, startingIndex, 1),
properties.Typeface, properties.FontRenderingEmSize, properties.CultureInfo);
var textRuns = new[] { new ShapedTextCharacters(glyphRun, _paragraphProperties.DefaultTextRunProperties) };
var textRuns = new List<ShapedTextCharacters>
{
new ShapedTextCharacters(glyphRun, _paragraphProperties.DefaultTextRunProperties)
};
return new TextLineImpl(textRuns,
TextLineMetrics.Create(textRuns, new TextRange(startingIndex, 1), MaxWidth, _paragraphProperties));

4
src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs

@ -6,9 +6,9 @@ namespace Avalonia.Media.TextFormatting
{
internal class TextLineImpl : TextLine
{
private readonly IReadOnlyList<ShapedTextCharacters> _textRuns;
private readonly List<ShapedTextCharacters> _textRuns;
public TextLineImpl(IReadOnlyList<ShapedTextCharacters> textRuns, TextLineMetrics lineMetrics,
public TextLineImpl(List<ShapedTextCharacters> textRuns, TextLineMetrics lineMetrics,
TextLineBreak lineBreak = null, bool hasCollapsed = false)
{
_textRuns = textRuns;

10
src/Skia/Avalonia.Skia/TextShaperImpl.cs

@ -123,10 +123,7 @@ namespace Avalonia.Skia
return;
}
if (offsetBuffer == null)
{
offsetBuffer = new Vector[glyphPositions.Length];
}
offsetBuffer ??= new Vector[glyphPositions.Length];
var offsetX = position.XOffset * textScale;
@ -138,10 +135,7 @@ namespace Avalonia.Skia
private static void SetAdvance(ReadOnlySpan<GlyphPosition> glyphPositions, int index, double textScale,
ref double[] advanceBuffer)
{
if (advanceBuffer == null)
{
advanceBuffer = new double[glyphPositions.Length];
}
advanceBuffer ??= new double[glyphPositions.Length];
// Depends on direction of layout
// advanceBuffer[index] = buffer.GlyphPositions[index].YAdvance * textScale;

14
tests/Avalonia.Controls.UnitTests/Utils/SelectedItemsSyncTests.cs

@ -208,6 +208,20 @@ namespace Avalonia.Controls.UnitTests.Utils
target.SetItems(new[] { "foo", "bar", "baz" }));
}
[Fact]
public void Selected_Items_Can_Be_Set_Before_SelectionModel_Source()
{
var model = new SelectionModel();
var target = new SelectedItemsSync(model);
var items = new AvaloniaList<string> { "foo", "bar", "baz" };
var selectedItems = new AvaloniaList<string> { "bar" };
target.SetItems(selectedItems);
model.Source = items;
Assert.Equal(new IndexPath(1), model.SelectedIndex);
}
private static SelectedItemsSync CreateTarget(
IEnumerable<string> items = null)
{

Loading…
Cancel
Save