Browse Source

Merge branch 'master' into feature/fluent-menu-context-menu

pull/4126/head
Dan Walmsley 6 years ago
parent
commit
f726246a45
  1. 2
      build.sh
  2. 3
      native/Avalonia.Native/inc/avalonia-native.h
  3. 1
      native/Avalonia.Native/src/OSX/AvnString.h
  4. 12
      native/Avalonia.Native/src/OSX/AvnString.mm
  5. 34
      native/Avalonia.Native/src/OSX/clipboard.mm
  6. 6
      samples/ControlCatalog/App.xaml
  7. 53
      samples/ControlCatalog/App.xaml.cs
  8. 9
      samples/ControlCatalog/MainView.xaml
  9. 23
      samples/ControlCatalog/MainView.xaml.cs
  10. 2
      samples/ControlCatalog/MainWindow.xaml
  11. 6
      samples/ControlCatalog/Pages/ButtonPage.xaml
  12. 20
      samples/ControlCatalog/Pages/ButtonPage.xaml.cs
  13. 18
      samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml
  14. 14
      samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs
  15. 2
      samples/ControlCatalog/Pages/SliderPage.xaml
  16. 1
      samples/ControlCatalog/Pages/TreeViewPage.xaml
  17. 11
      samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs
  18. 6
      src/Android/Avalonia.Android/Platform/ClipboardImpl.cs
  19. 16
      src/Avalonia.Animation/Animatable.cs
  20. 15
      src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
  21. 93
      src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs
  22. 9
      src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
  23. 2
      src/Avalonia.Base/Properties/AssemblyInfo.cs
  24. 94
      src/Avalonia.Base/Utilities/MathUtilities.cs
  25. 21
      src/Avalonia.Controls/AutoCompleteBox.cs
  26. 4
      src/Avalonia.Controls/Calendar/Calendar.cs
  27. 134
      src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
  28. 4
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  29. 35
      src/Avalonia.Controls/Grid.cs
  30. 20
      src/Avalonia.Controls/IndexPath.cs
  31. 47
      src/Avalonia.Controls/IndexRange.cs
  32. 14
      src/Avalonia.Controls/Primitives/Track.cs
  33. 76
      src/Avalonia.Controls/SelectionModel.cs
  34. 2
      src/Avalonia.Controls/SelectionModelChangeSet.cs
  35. 22
      src/Avalonia.Controls/SelectionModelChildrenRequestedEventArgs.cs
  36. 27
      src/Avalonia.Controls/SelectionNode.cs
  37. 161
      src/Avalonia.Controls/Slider.cs
  38. 22
      src/Avalonia.Controls/TextBlock.cs
  39. 416
      src/Avalonia.Controls/TickBar.cs
  40. 26
      src/Avalonia.Controls/ToolTip.cs
  41. 18
      src/Avalonia.Controls/TreeView.cs
  42. 3
      src/Avalonia.Controls/Utils/BorderRenderHelper.cs
  43. 8
      src/Avalonia.Controls/Utils/SelectionTreeHelper.cs
  44. 4
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  45. 17
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
  46. 38
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs
  47. 24
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs
  48. 2
      src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml
  49. 6
      src/Avalonia.Input/Platform/IClipboard.cs
  50. 15
      src/Avalonia.Native/AvnString.cs
  51. 32
      src/Avalonia.Native/ClipboardImpl.cs
  52. 4
      src/Avalonia.Themes.Default/CalendarDatePicker.xaml
  53. 2
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  54. 92
      src/Avalonia.Themes.Fluent/Accents/FluentBaseDark.xaml
  55. 93
      src/Avalonia.Themes.Fluent/Accents/FluentBaseLight.xaml
  56. 175
      src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml
  57. 174
      src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml
  58. 1
      src/Avalonia.Themes.Fluent/Accents/FluentDark.xaml
  59. 1
      src/Avalonia.Themes.Fluent/Accents/FluentLight.xaml
  60. 36
      src/Avalonia.Themes.Fluent/Button.xaml
  61. 15
      src/Avalonia.Themes.Fluent/Calendar.xaml
  62. 138
      src/Avalonia.Themes.Fluent/CalendarButton.xaml
  63. 4
      src/Avalonia.Themes.Fluent/CalendarDatePicker.xaml
  64. 164
      src/Avalonia.Themes.Fluent/CalendarDayButton.xaml
  65. 275
      src/Avalonia.Themes.Fluent/CalendarItem.xaml
  66. 2
      src/Avalonia.Themes.Fluent/ComboBox.xaml
  67. 2
      src/Avalonia.Themes.Fluent/FluentTheme.xaml
  68. 100
      src/Avalonia.Themes.Fluent/RepeatButton.xaml
  69. 323
      src/Avalonia.Themes.Fluent/Slider.xaml
  70. 113
      src/Avalonia.Themes.Fluent/ToggleButton.xaml
  71. 95
      src/Avalonia.Themes.Fluent/ToolTip.xaml
  72. 5
      src/Avalonia.Visuals/Media/DrawingContext.cs
  73. 17
      src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
  74. 35
      src/Avalonia.X11/X11Atoms.cs
  75. 135
      src/Avalonia.X11/X11Clipboard.cs
  76. 4
      src/Avalonia.X11/XLib.cs
  77. 12
      src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs
  78. 23
      src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs
  79. 8
      src/Markup/Avalonia.Markup/Data/MultiBinding.cs
  80. 2
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  81. 3
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  82. 76
      src/Windows/Avalonia.Win32/ClipboardImpl.cs
  83. 6
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  84. 2
      src/Windows/Avalonia.Win32/Win32Platform.cs
  85. 6
      src/iOS/Avalonia.iOS/Clipboard.cs
  86. 65
      tests/Avalonia.Animation.UnitTests/AnimatableTests.cs
  87. 2
      tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs
  88. 119
      tests/Avalonia.Base.UnitTests/Utilities/MathUtilitiesTests.cs
  89. 47
      tests/Avalonia.Benchmarks/Data/AccessorTestObject.cs
  90. 44
      tests/Avalonia.Benchmarks/Data/PropertyAccessorBenchmarks.cs
  91. 60
      tests/Avalonia.Benchmarks/Data/PropertyAccessorPluginBenchmarks.cs
  92. 14
      tests/Avalonia.Controls.UnitTests/CalendarDatePickerTests.cs
  93. 82
      tests/Avalonia.Controls.UnitTests/IndexRangeTests.cs
  94. 146
      tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs
  95. 24
      tests/Avalonia.Controls.UnitTests/TabControlTests.cs
  96. 5
      tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
  97. 71
      tests/Avalonia.Controls.UnitTests/ToolTipTests.cs
  98. 548
      tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
  99. 44
      tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs
  100. 2
      tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Property.cs

2
build.sh

@ -67,6 +67,8 @@ else
fi
fi
export PATH=$DOTNET_DIRECTORY:$PATH
echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)"
"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" -- ${BUILD_ARGUMENTS[@]}

3
native/Avalonia.Native/inc/avalonia-native.h

@ -387,6 +387,9 @@ AVNCOM(IAvnClipboard, 0f) : IUnknown
virtual HRESULT SetText (char* type, void* utf8Text) = 0;
virtual HRESULT ObtainFormats(IAvnStringArray**ppv) = 0;
virtual HRESULT GetStrings(char* type, IAvnStringArray**ppv) = 0;
virtual HRESULT SetBytes(char* type, void* utf8Text, int len) = 0;
virtual HRESULT GetBytes(char* type, IAvnString**ppv) = 0;
virtual HRESULT Clear() = 0;
};

1
native/Avalonia.Native/src/OSX/AvnString.h

@ -12,4 +12,5 @@
extern IAvnString* CreateAvnString(NSString* string);
extern IAvnStringArray* CreateAvnStringArray(NSArray<NSString*>* array);
extern IAvnStringArray* CreateAvnStringArray(NSString* string);
extern IAvnString* CreateByteArray(void* data, int len);
#endif /* AvnString_h */

12
native/Avalonia.Native/src/OSX/AvnString.mm

@ -29,6 +29,13 @@ public:
memcpy((void*)_cstring, (void*)cstring, _length);
}
AvnStringImpl(void*ptr, int len)
{
_length = len;
_cstring = (const char*)malloc(_length);
memcpy((void*)_cstring, ptr, len);
}
virtual ~AvnStringImpl()
{
free((void*)_cstring);
@ -114,3 +121,8 @@ IAvnStringArray* CreateAvnStringArray(NSString* string)
{
return new AvnStringArrayImpl(string);
}
IAvnString* CreateByteArray(void* data, int len)
{
return new AvnStringImpl(data, len);
}

34
native/Avalonia.Native/src/OSX/clipboard.mm

@ -82,6 +82,40 @@ public:
return S_OK;
}
virtual HRESULT SetBytes(char* type, void* bytes, int len) override
{
auto typeString = [NSString stringWithUTF8String:(const char*)type];
auto data = [NSData dataWithBytes:bytes length:len];
if(_item == nil)
[_pb setData:data forType:typeString];
else
[_item setData:data forType:typeString];
return S_OK;
}
virtual HRESULT GetBytes(char* type, IAvnString**ppv) override
{
*ppv = nil;
auto typeString = [NSString stringWithUTF8String:(const char*)type];
NSData*data;
@try
{
if(_item)
data = [_item dataForType:typeString];
else
data = [_pb dataForType:typeString];
if(data == nil)
return E_FAIL;
}
@catch(NSException* e)
{
return E_FAIL;
}
*ppv = CreateByteArray((void*)data.bytes, (int)data.length);
return S_OK;
}
virtual HRESULT Clear() override
{

6
samples/ControlCatalog/App.xaml

@ -1,10 +1,8 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.App">
<Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Default.xaml"/>
<Application.Styles>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Default.xaml"/>
<Style Selector="TextBlock.h1">
<Setter Property="FontSize" Value="{DynamicResource FontSizeLarge}"/>
<Setter Property="FontWeight" Value="Medium"/>

53
samples/ControlCatalog/App.xaml.cs

@ -1,14 +1,67 @@
using System;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Styling;
namespace ControlCatalog
{
public class App : Application
{
public static Styles FluentDark = new Styles
{
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseDark.xaml?assembly=Avalonia.Themes.Default")
},
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Fluent.Accents.FluentDark.xaml?assembly=Avalonia.Themes.Fluent")
},
};
public static Styles FluentLight = new Styles
{
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default")
},
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Fluent.Accents.FluentLight.xaml?assembly=Avalonia.Themes.Fluent")
},
};
public static Styles DefaultLight = new Styles
{
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default")
},
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default")
},
};
public static Styles DefaultDark = new Styles
{
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseDark.xaml?assembly=Avalonia.Themes.Default")
},
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default")
},
};
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
Styles.Insert(0, FluentDark);
}
public override void OnFrameworkInitializationCompleted()

9
samples/ControlCatalog/MainView.xaml

@ -29,7 +29,8 @@
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<pages:DataGridPage/>
</TabItem>
<TabItem Header="DatePicker"><pages:DatePickerPage/></TabItem>
<TabItem Header="CalendarDatePicker">
<pages:CalendarDatePickerPage/></TabItem>
<TabItem Header="Drag+Drop"><pages:DragAndDropPage/></TabItem>
<TabItem Header="Expander"><pages:ExpanderPage/></TabItem>
<TabItem Header="Image"
@ -67,8 +68,10 @@
<ComboBoxItem>Full Decorations</ComboBoxItem>
</ComboBox>
<ComboBox x:Name="Themes" SelectedIndex="0">
<ComboBoxItem>Light</ComboBoxItem>
<ComboBoxItem>Dark</ComboBoxItem>
<ComboBoxItem>Fluent - Dark</ComboBoxItem>
<ComboBoxItem>Fluent - Light</ComboBoxItem>
<ComboBoxItem>Simple - Light</ComboBoxItem>
<ComboBoxItem>Simple - Dark</ComboBoxItem>
</ComboBox>
<ComboBox x:Name="TransparencyLevels" SelectedIndex="0">
<ComboBoxItem>None</ComboBoxItem>

23
samples/ControlCatalog/MainView.xaml.cs

@ -32,30 +32,25 @@ namespace ControlCatalog
}
var light = new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default")
};
var dark = new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("resm:Avalonia.Themes.Default.Accents.BaseDark.xaml?assembly=Avalonia.Themes.Default")
};
var themes = this.Find<ComboBox>("Themes");
themes.SelectionChanged += (sender, e) =>
{
switch (themes.SelectedIndex)
{
case 0:
Styles[0] = light;
Application.Current.Styles[0] = App.FluentDark;
break;
case 1:
Styles[0] = dark;
Application.Current.Styles[0] = App.FluentLight;
break;
case 2:
Application.Current.Styles[0] = App.DefaultLight;
break;
case 3:
Application.Current.Styles[0] = App.DefaultDark;
break;
}
};
Styles.Add(light);
};
var decorations = this.Find<ComboBox>("Decorations");
decorations.SelectionChanged += (sender, e) =>

2
samples/ControlCatalog/MainWindow.xaml

@ -7,7 +7,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:ControlCatalog.ViewModels"
xmlns:v="clr-namespace:ControlCatalog.Views"
x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}" Background="Transparent">
x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}" Background="{DynamicResource SystemControlPageBackgroundAltHighBrush}">
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="File">

6
samples/ControlCatalog/Pages/ButtonPage.xaml

@ -24,7 +24,11 @@
</Style>
</Button.Styles>
</Button>
</StackPanel>
<RepeatButton Name="RepeatButton">
<TextBlock Name="RepeatButtonTextBlock" Text="Repeat Button: 0" />
</RepeatButton>
<ToggleButton Content="Toggle Button"/>
</StackPanel>
<StackPanel Orientation="Vertical" Spacing="8" Width="150">
<Button BorderThickness="0">No Border</Button>

20
samples/ControlCatalog/Pages/ButtonPage.xaml.cs

@ -5,5 +5,25 @@ namespace ControlCatalog.Pages
{
public class ButtonPage : UserControl
{
private int repeatButtonClickCount = 0;
public ButtonPage()
{
InitializeComponent();
this.FindControl<RepeatButton>("RepeatButton").Click += OnRepeatButtonClick;
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public void OnRepeatButtonClick(object sender, object args)
{
repeatButtonClickCount++;
var textBlock = this.FindControl<TextBlock>("RepeatButtonTextBlock");
textBlock.Text = $"Repeat Button: {repeatButtonClickCount}";
}
}
}

18
samples/ControlCatalog/Pages/DatePickerPage.xaml → samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml

@ -1,8 +1,8 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.DatePickerPage">
x:Class="ControlCatalog.Pages.CalendarDatePickerPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">DatePicker</TextBlock>
<TextBlock Classes="h1">CalendarDatePicker</TextBlock>
<TextBlock Classes="h2">A control for selecting dates with a calendar drop-down</TextBlock>
<StackPanel Orientation="Horizontal"
@ -12,34 +12,34 @@
<StackPanel Orientation="Vertical"
Width="200">
<TextBlock Text="SelectedDateFormat: Short"/>
<DatePicker Name="DatePicker1"
<CalendarDatePicker Name="DatePicker1"
SelectedDateFormat="Short"
Margin="0,0,0,8"/>
<TextBlock Text="SelectedDateFormat: Long"/>
<DatePicker Name="DatePicker2"
<CalendarDatePicker Name="DatePicker2"
SelectedDateFormat="Long"
Margin="0,0,0,8"/>
<TextBlock Text="SelectedDateFormat: Custom"/>
<DatePicker Name="DatePicker3"
<CalendarDatePicker Name="DatePicker3"
SelectedDateFormat="Custom"
CustomDateFormatString="ddd, MMM d"
Margin="0,0,0,8"/>
<TextBlock Text="Blackout Dates"/>
<DatePicker Name="DatePicker4"
<CalendarDatePicker Name="DatePicker4"
Margin="0,0,0,8"/>
<DatePicker Margin="0,0,0,8"
<CalendarDatePicker Margin="0,0,0,8"
Watermark="Watermark"/>
<DatePicker Margin="0,0,0,8"
<CalendarDatePicker Margin="0,0,0,8"
Name="DatePicker5"
Watermark="Floating Watermark"
UseFloatingWatermark="True"/>
<TextBlock Text="Disabled"/>
<DatePicker IsEnabled="False"/>
<CalendarDatePicker IsEnabled="False"/>
</StackPanel>
</StackPanel>

14
samples/ControlCatalog/Pages/DatePickerPage.xaml.cs → samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs

@ -4,17 +4,17 @@ using System;
namespace ControlCatalog.Pages
{
public class DatePickerPage : UserControl
public class CalendarDatePickerPage : UserControl
{
public DatePickerPage()
public CalendarDatePickerPage()
{
InitializeComponent();
var dp1 = this.FindControl<DatePicker>("DatePicker1");
var dp2 = this.FindControl<DatePicker>("DatePicker2");
var dp3 = this.FindControl<DatePicker>("DatePicker3");
var dp4 = this.FindControl<DatePicker>("DatePicker4");
var dp5 = this.FindControl<DatePicker>("DatePicker5");
var dp1 = this.FindControl<CalendarDatePicker>("DatePicker1");
var dp2 = this.FindControl<CalendarDatePicker>("DatePicker2");
var dp3 = this.FindControl<CalendarDatePicker>("DatePicker3");
var dp4 = this.FindControl<CalendarDatePicker>("DatePicker4");
var dp5 = this.FindControl<CalendarDatePicker>("DatePicker5");
dp1.SelectedDate = DateTime.Today;
dp2.SelectedDate = DateTime.Today.AddDays(10);

2
samples/ControlCatalog/Pages/SliderPage.xaml

@ -9,12 +9,14 @@
<Slider Value="0"
Minimum="0"
Maximum="100"
TickFrequency="10"
Width="300"/>
<Slider Value="0"
Minimum="0"
Maximum="100"
Orientation="Vertical"
IsSnapToTickEnabled="True"
TickPlacement="Outside"
TickFrequency="10"
Height="300"/>
</StackPanel>

1
samples/ControlCatalog/Pages/TreeViewPage.xaml

@ -20,6 +20,7 @@
<Button Command="{Binding AddItemCommand}">Add</Button>
<Button Command="{Binding RemoveItemCommand}">Remove</Button>
<Button Command="{Binding SelectRandomItemCommand}">Select Random</Button>
<ComboBox SelectedIndex="{Binding SelectionMode, Mode=TwoWay}">
<ComboBoxItem>Single</ComboBoxItem>

11
samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs

@ -23,12 +23,14 @@ namespace ControlCatalog.ViewModels
AddItemCommand = ReactiveCommand.Create(AddItem);
RemoveItemCommand = ReactiveCommand.Create(RemoveItem);
SelectRandomItemCommand = ReactiveCommand.Create(SelectRandomItem);
}
public ObservableCollection<Node> 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
{
@ -74,6 +76,15 @@ namespace ControlCatalog.ViewModels
}
}
private void SelectRandomItem()
{
var random = new Random();
var depth = random.Next(4);
var indexes = Enumerable.Range(0, 4).Select(x => random.Next(10));
var path = new IndexPath(indexes);
Selection.SelectedIndex = path;
}
private void SelectionChanged(object sender, SelectionModelSelectionChangedEventArgs e)
{
var selected = string.Join(",", e.SelectedIndices);

6
src/Android/Avalonia.Android/Platform/ClipboardImpl.cs

@ -43,5 +43,11 @@ namespace Avalonia.Android.Platform
return Task.FromResult<object>(null);
}
public Task SetDataObjectAsync(IDataObject data) => throw new PlatformNotSupportedException();
public Task<string[]> GetFormatsAsync() => throw new PlatformNotSupportedException();
public Task<object> GetDataAsync(string format) => throw new PlatformNotSupportedException();
}
}

16
src/Avalonia.Animation/Animatable.cs

@ -93,17 +93,17 @@ namespace Avalonia.Animation
var oldTransitions = change.OldValue.GetValueOrDefault<Transitions>();
var newTransitions = change.NewValue.GetValueOrDefault<Transitions>();
if (oldTransitions is object)
{
oldTransitions.CollectionChanged -= TransitionsCollectionChanged;
RemoveTransitions(oldTransitions);
}
if (newTransitions is object)
{
newTransitions.CollectionChanged += TransitionsCollectionChanged;
AddTransitions(newTransitions);
}
if (oldTransitions is object)
{
oldTransitions.CollectionChanged -= TransitionsCollectionChanged;
RemoveTransitions(oldTransitions);
}
}
else if (_transitionsEnabled &&
Transitions is object &&
@ -111,8 +111,10 @@ namespace Avalonia.Animation
!change.Property.IsDirect &&
change.Priority > BindingPriority.Animation)
{
foreach (var transition in Transitions)
for (var i = Transitions.Count -1; i >= 0; --i)
{
var transition = Transitions[i];
if (transition.Property == change.Property)
{
var state = _transitionState[transition];

15
src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs

@ -1,7 +1,5 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Reflection;
using Avalonia.Utilities;
@ -14,7 +12,7 @@ namespace Avalonia.Data.Core.Plugins
public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin
{
/// <inheritdoc/>
public bool Match(object obj, string propertyName) => true;
public bool Match(object obj, string propertyName) => GetPropertyWithName(obj.GetType(), propertyName) != null;
/// <summary>
/// Starts monitoring the value of a property on an object.
@ -31,7 +29,8 @@ namespace Avalonia.Data.Core.Plugins
Contract.Requires<ArgumentNullException>(propertyName != null);
reference.TryGetTarget(out object instance);
var p = instance.GetType().GetRuntimeProperties().FirstOrDefault(x => x.Name == propertyName);
var p = GetPropertyWithName(instance.GetType(), propertyName);
if (p != null)
{
@ -45,6 +44,14 @@ namespace Avalonia.Data.Core.Plugins
}
}
private static PropertyInfo GetPropertyWithName(Type type, string propertyName)
{
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Static | BindingFlags.Instance;
return type.GetProperty(propertyName, bindingFlags);
}
private class Accessor : PropertyAccessorBase, IWeakSubscriber<PropertyChangedEventArgs>
{
private readonly WeakReference<object> _reference;

93
src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs

@ -1,13 +1,16 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace Avalonia.Data.Core.Plugins
{
class MethodAccessorPlugin : IPropertyAccessorPlugin
public class MethodAccessorPlugin : IPropertyAccessorPlugin
{
public bool Match(object obj, string methodName)
=> obj.GetType().GetRuntimeMethods().Any(x => x.Name == methodName);
private readonly Dictionary<(Type, string), MethodInfo> _methodLookup =
new Dictionary<(Type, string), MethodInfo>();
public bool Match(object obj, string methodName) => GetFirstMethodWithName(obj.GetType(), methodName) != null;
public IPropertyAccessor Start(WeakReference<object> reference, string methodName)
{
@ -15,17 +18,22 @@ namespace Avalonia.Data.Core.Plugins
Contract.Requires<ArgumentNullException>(methodName != null);
reference.TryGetTarget(out object instance);
var method = instance.GetType().GetRuntimeMethods().FirstOrDefault(x => x.Name == methodName);
var method = GetFirstMethodWithName(instance.GetType(), methodName);
if (method != null)
{
if (method.GetParameters().Length + (method.ReturnType == typeof(void) ? 0 : 1) > 8)
var parameters = method.GetParameters();
if (parameters.Length + (method.ReturnType == typeof(void) ? 0 : 1) > 8)
{
var exception = new ArgumentException("Cannot create a binding accessor for a method with more than 8 parameters or more than 7 parameters if it has a non-void return type.", nameof(methodName));
var exception = new ArgumentException(
"Cannot create a binding accessor for a method with more than 8 parameters or more than 7 parameters if it has a non-void return type.",
nameof(methodName));
return new PropertyError(new BindingNotification(exception, BindingErrorType.Error));
}
return new Accessor(reference, method);
return new Accessor(reference, method, parameters);
}
else
{
@ -35,31 +43,72 @@ namespace Avalonia.Data.Core.Plugins
}
}
private MethodInfo GetFirstMethodWithName(Type type, string methodName)
{
var key = (type, methodName);
if (!_methodLookup.TryGetValue(key, out MethodInfo methodInfo))
{
methodInfo = TryFindAndCacheMethod(type, methodName);
}
return methodInfo;
}
private MethodInfo TryFindAndCacheMethod(Type type, string methodName)
{
MethodInfo found = null;
const BindingFlags bindingFlags =
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
var methods = type.GetMethods(bindingFlags);
foreach (MethodInfo methodInfo in methods)
{
if (methodInfo.Name == methodName)
{
found = methodInfo;
break;
}
}
_methodLookup.Add((type, methodName), found);
return found;
}
private sealed class Accessor : PropertyAccessorBase
{
public Accessor(WeakReference<object> reference, MethodInfo method)
public Accessor(WeakReference<object> reference, MethodInfo method, ParameterInfo[] parameters)
{
Contract.Requires<ArgumentNullException>(reference != null);
Contract.Requires<ArgumentNullException>(method != null);
var paramTypes = method.GetParameters().Select(param => param.ParameterType).ToArray();
var returnType = method.ReturnType;
if (returnType == typeof(void))
bool hasReturn = returnType != typeof(void);
var signatureTypeCount = (hasReturn ? 1 : 0) + parameters.Length;
var paramTypes = new Type[signatureTypeCount];
for (var i = 0; i < parameters.Length; i++)
{
if (paramTypes.Length == 0)
{
PropertyType = typeof(Action);
}
else
{
PropertyType = Type.GetType($"System.Action`{paramTypes.Length}").MakeGenericType(paramTypes);
}
ParameterInfo parameter = parameters[i];
paramTypes[i] = parameter.ParameterType;
}
if (hasReturn)
{
paramTypes[paramTypes.Length - 1] = returnType;
PropertyType = Expression.GetFuncType(paramTypes);
}
else
{
var genericTypeParameters = paramTypes.Concat(new[] { returnType }).ToArray();
PropertyType = Type.GetType($"System.Func`{genericTypeParameters.Length}").MakeGenericType(genericTypeParameters);
PropertyType = Expression.GetActionType(paramTypes);
}
if (method.IsStatic)

9
src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs

@ -62,8 +62,13 @@ namespace Avalonia.Data.Core
if (accessor == null)
{
throw new NotSupportedException(
$"Could not find a matching property accessor for {PropertyName}.");
reference.TryGetTarget(out object instance);
var message = $"Could not find a matching property accessor for '{PropertyName}' on '{instance}'";
var exception = new MissingMemberException(message);
accessor = new PropertyError(new BindingNotification(exception, BindingErrorType.Error));
}
_accessor = accessor;

2
src/Avalonia.Base/Properties/AssemblyInfo.cs

@ -7,4 +7,4 @@ using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Data.Converters")]
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

94
src/Avalonia.Base/Utilities/MathUtilities.cs

@ -8,6 +8,11 @@ namespace Avalonia.Utilities
/// </summary>
public static class MathUtilities
{
// smallest such that 1.0+DoubleEpsilon != 1.0
private const double DoubleEpsilon = 2.2204460492503131e-016;
private const float FloatEpsilon = 1.192092896e-07F;
/// <summary>
/// AreClose - Returns whether or not two doubles are "close". That is, whether or
/// not they are within epsilon of each other.
@ -18,11 +23,26 @@ namespace Avalonia.Utilities
{
//in case they are Infinities (then epsilon check does not work)
if (value1 == value2) return true;
double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * double.Epsilon;
double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DoubleEpsilon;
double delta = value1 - value2;
return (-eps < delta) && (eps > delta);
}
/// <summary>
/// AreClose - Returns whether or not two floats are "close". That is, whether or
/// not they are within epsilon of each other.
/// </summary>
/// <param name="value1"> The first float to compare. </param>
/// <param name="value2"> The second float to compare. </param>
public static bool AreClose(float value1, float value2)
{
//in case they are Infinities (then epsilon check does not work)
if (value1 == value2) return true;
float eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0f) * FloatEpsilon;
float delta = value1 - value2;
return (-eps < delta) && (eps > delta);
}
/// <summary>
/// LessThan - Returns whether or not the first double is less than the second double.
/// That is, whether or not the first is strictly less than *and* not within epsilon of
@ -35,6 +55,18 @@ namespace Avalonia.Utilities
return (value1 < value2) && !AreClose(value1, value2);
}
/// <summary>
/// LessThan - Returns whether or not the first float is less than the second float.
/// That is, whether or not the first is strictly less than *and* not within epsilon of
/// the other number.
/// </summary>
/// <param name="value1"> The first single float to compare. </param>
/// <param name="value2"> The second single float to compare. </param>
public static bool LessThan(float value1, float value2)
{
return (value1 < value2) && !AreClose(value1, value2);
}
/// <summary>
/// GreaterThan - Returns whether or not the first double is greater than the second double.
/// That is, whether or not the first is strictly greater than *and* not within epsilon of
@ -47,6 +79,18 @@ namespace Avalonia.Utilities
return (value1 > value2) && !AreClose(value1, value2);
}
/// <summary>
/// GreaterThan - Returns whether or not the first float is greater than the second float.
/// That is, whether or not the first is strictly greater than *and* not within epsilon of
/// the other number.
/// </summary>
/// <param name="value1"> The first float to compare. </param>
/// <param name="value2"> The second float to compare. </param>
public static bool GreaterThan(float value1, float value2)
{
return (value1 > value2) && !AreClose(value1, value2);
}
/// <summary>
/// LessThanOrClose - Returns whether or not the first double is less than or close to
/// the second double. That is, whether or not the first is strictly less than or within
@ -59,6 +103,18 @@ namespace Avalonia.Utilities
return (value1 < value2) || AreClose(value1, value2);
}
/// <summary>
/// LessThanOrClose - Returns whether or not the first float is less than or close to
/// the second float. That is, whether or not the first is strictly less than or within
/// epsilon of the other number.
/// </summary>
/// <param name="value1"> The first float to compare. </param>
/// <param name="value2"> The second float to compare. </param>
public static bool LessThanOrClose(float value1, float value2)
{
return (value1 < value2) || AreClose(value1, value2);
}
/// <summary>
/// GreaterThanOrClose - Returns whether or not the first double is greater than or close to
/// the second double. That is, whether or not the first is strictly greater than or within
@ -71,6 +127,18 @@ namespace Avalonia.Utilities
return (value1 > value2) || AreClose(value1, value2);
}
/// <summary>
/// GreaterThanOrClose - Returns whether or not the first float is greater than or close to
/// the second float. That is, whether or not the first is strictly greater than or within
/// epsilon of the other number.
/// </summary>
/// <param name="value1"> The first float to compare. </param>
/// <param name="value2"> The second float to compare. </param>
public static bool GreaterThanOrClose(float value1, float value2)
{
return (value1 > value2) || AreClose(value1, value2);
}
/// <summary>
/// IsOne - Returns whether or not the double is "close" to 1. Same as AreClose(double, 1),
/// but this is faster.
@ -78,7 +146,17 @@ namespace Avalonia.Utilities
/// <param name="value"> The double to compare to 1. </param>
public static bool IsOne(double value)
{
return Math.Abs(value - 1.0) < 10.0 * double.Epsilon;
return Math.Abs(value - 1.0) < 10.0 * DoubleEpsilon;
}
/// <summary>
/// IsOne - Returns whether or not the float is "close" to 1. Same as AreClose(float, 1),
/// but this is faster.
/// </summary>
/// <param name="value"> The float to compare to 1. </param>
public static bool IsOne(float value)
{
return Math.Abs(value - 1.0f) < 10.0f * FloatEpsilon;
}
/// <summary>
@ -88,7 +166,17 @@ namespace Avalonia.Utilities
/// <param name="value"> The double to compare to 0. </param>
public static bool IsZero(double value)
{
return Math.Abs(value) < 10.0 * double.Epsilon;
return Math.Abs(value) < 10.0 * DoubleEpsilon;
}
/// <summary>
/// IsZero - Returns whether or not the float is "close" to 0. Same as AreClose(float, 0),
/// but this is faster.
/// </summary>
/// <param name="value"> The float to compare to 0. </param>
public static bool IsZero(float value)
{
return Math.Abs(value) < 10.0f * FloatEpsilon;
}
/// <summary>

21
src/Avalonia.Controls/AutoCompleteBox.cs

@ -468,10 +468,11 @@ namespace Avalonia.Controls
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.Text" />
/// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, string> TextProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, string>(
nameof(Text),
TextBlock.TextProperty.AddOwnerWithDataValidation<AutoCompleteBox>(
o => o.Text,
(o, v) => o.Text = v);
(o, v) => o.Text = v,
defaultBindingMode: BindingMode.TwoWay,
enableDataValidation: true);
/// <summary>
/// Identifies the
@ -1244,6 +1245,20 @@ namespace Avalonia.Controls
base.OnApplyTemplate(e);
}
/// <summary>
/// Called to update the validation state for properties for which data validation is
/// enabled.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The new binding value for the property.</param>
protected override void UpdateDataValidation<T>(AvaloniaProperty<T> property, BindingValue<T> value)
{
if (property == TextProperty)
{
DataValidationErrors.SetError(this, value.Error);
}
}
/// <summary>
/// Provides handling for the

4
src/Avalonia.Controls/Calendar/Calendar.cs

@ -998,10 +998,10 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets a value indicating whether DatePicker should change its
/// Gets or sets a value indicating whether CalendarDatePicker should change its
/// DisplayDate because of a SelectedDate change on its Calendar.
/// </summary>
internal bool DatePickerDisplayDateFlag { get; set; }
internal bool CalendarDatePickerDisplayDateFlag { get; set; }
internal CalendarDayButton FindDayButtonFromDay(DateTime day)
{

134
src/Avalonia.Controls/Calendar/DatePicker.cs → src/Avalonia.Controls/Calendar/CalendarDatePicker.cs

@ -16,29 +16,29 @@ namespace Avalonia.Controls
{
/// <summary>
/// Provides data for the
/// <see cref="E:Avalonia.Controls.DatePicker.DateValidationError" />
/// <see cref="E:Avalonia.Controls.CalendarDatePicker.DateValidationError" />
/// event.
/// </summary>
public class DatePickerDateValidationErrorEventArgs : EventArgs
public class CalendarDatePickerDateValidationErrorEventArgs : EventArgs
{
private bool _throwException;
/// <summary>
/// Initializes a new instance of the
/// <see cref="T:Avalonia.Controls.DatePickerDateValidationErrorEventArgs" />
/// <see cref="T:Avalonia.Controls.CalendarDatePickerDateValidationErrorEventArgs" />
/// class.
/// </summary>
/// <param name="exception">
/// The initial exception from the
/// <see cref="E:Avalonia.Controls.DatePicker.DateValidationError" />
/// <see cref="E:Avalonia.Controls.CalendarDatePicker.DateValidationError" />
/// event.
/// </param>
/// <param name="text">
/// The text that caused the
/// <see cref="E:Avalonia.Controls.DatePicker.DateValidationError" />
/// <see cref="E:Avalonia.Controls.CalendarDatePicker.DateValidationError" />
/// event.
/// </param>
public DatePickerDateValidationErrorEventArgs(Exception exception, string text)
public CalendarDatePickerDateValidationErrorEventArgs(Exception exception, string text)
{
this.Text = text;
this.Exception = exception;
@ -46,7 +46,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets the initial exception associated with the
/// <see cref="E:Avalonia.Controls.DatePicker.DateValidationError" />
/// <see cref="E:Avalonia.Controls.CalendarDatePicker.DateValidationError" />
/// event.
/// </summary>
/// <value>
@ -56,7 +56,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets the text that caused the
/// <see cref="E:Avalonia.Controls.DatePicker.DateValidationError" />
/// <see cref="E:Avalonia.Controls.CalendarDatePicker.DateValidationError" />
/// event.
/// </summary>
/// <value>
@ -66,7 +66,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets a value indicating whether
/// <see cref="P:Avalonia.Controls.DatePickerDateValidationErrorEventArgs.Exception" />
/// <see cref="P:Avalonia.Controls.CalendarDatePickerDateValidationErrorEventArgs.Exception" />
/// should be thrown.
/// </summary>
/// <value>
@ -74,7 +74,7 @@ namespace Avalonia.Controls
/// </value>
/// <exception cref="T:System.ArgumentException">
/// If set to true and
/// <see cref="P:Avalonia.Controls.DatePickerDateValidationErrorEventArgs.Exception" />
/// <see cref="P:Avalonia.Controls.CalendarDatePickerDateValidationErrorEventArgs.Exception" />
/// is null.
/// </exception>
public bool ThrowException
@ -93,9 +93,9 @@ namespace Avalonia.Controls
/// <summary>
/// Specifies date formats for a
/// <see cref="T:Avalonia.Controls.DatePicker" />.
/// <see cref="T:Avalonia.Controls.CalendarDatePicker" />.
/// </summary>
public enum DatePickerFormat
public enum CalendarDatePickerFormat
{
/// <summary>
/// Specifies that the date should be displayed using unabbreviated days
@ -115,7 +115,7 @@ namespace Avalonia.Controls
Custom = 2
}
public class DatePicker : TemplatedControl
public class CalendarDatePicker : TemplatedControl
{
private const string ElementTextBox = "PART_TextBox";
private const string ElementButton = "PART_Button";
@ -154,59 +154,59 @@ namespace Avalonia.Controls
/// </value>
public CalendarBlackoutDatesCollection BlackoutDates { get; private set; }
public static readonly DirectProperty<DatePicker, DateTime> DisplayDateProperty =
AvaloniaProperty.RegisterDirect<DatePicker, DateTime>(
public static readonly DirectProperty<CalendarDatePicker, DateTime> DisplayDateProperty =
AvaloniaProperty.RegisterDirect<CalendarDatePicker, DateTime>(
nameof(DisplayDate),
o => o.DisplayDate,
(o, v) => o.DisplayDate = v);
public static readonly DirectProperty<DatePicker, DateTime?> DisplayDateStartProperty =
AvaloniaProperty.RegisterDirect<DatePicker, DateTime?>(
public static readonly DirectProperty<CalendarDatePicker, DateTime?> DisplayDateStartProperty =
AvaloniaProperty.RegisterDirect<CalendarDatePicker, DateTime?>(
nameof(DisplayDateStart),
o => o.DisplayDateStart,
(o, v) => o.DisplayDateStart = v);
public static readonly DirectProperty<DatePicker, DateTime?> DisplayDateEndProperty =
AvaloniaProperty.RegisterDirect<DatePicker, DateTime?>(
public static readonly DirectProperty<CalendarDatePicker, DateTime?> DisplayDateEndProperty =
AvaloniaProperty.RegisterDirect<CalendarDatePicker, DateTime?>(
nameof(DisplayDateEnd),
o => o.DisplayDateEnd,
(o, v) => o.DisplayDateEnd = v);
public static readonly StyledProperty<DayOfWeek> FirstDayOfWeekProperty =
AvaloniaProperty.Register<DatePicker, DayOfWeek>(nameof(FirstDayOfWeek));
AvaloniaProperty.Register<CalendarDatePicker, DayOfWeek>(nameof(FirstDayOfWeek));
public static readonly DirectProperty<DatePicker, bool> IsDropDownOpenProperty =
AvaloniaProperty.RegisterDirect<DatePicker, bool>(
public static readonly DirectProperty<CalendarDatePicker, bool> IsDropDownOpenProperty =
AvaloniaProperty.RegisterDirect<CalendarDatePicker, bool>(
nameof(IsDropDownOpen),
o => o.IsDropDownOpen,
(o, v) => o.IsDropDownOpen = v);
public static readonly StyledProperty<bool> IsTodayHighlightedProperty =
AvaloniaProperty.Register<DatePicker, bool>(nameof(IsTodayHighlighted));
public static readonly DirectProperty<DatePicker, DateTime?> SelectedDateProperty =
AvaloniaProperty.RegisterDirect<DatePicker, DateTime?>(
AvaloniaProperty.Register<CalendarDatePicker, bool>(nameof(IsTodayHighlighted));
public static readonly DirectProperty<CalendarDatePicker, DateTime?> SelectedDateProperty =
AvaloniaProperty.RegisterDirect<CalendarDatePicker, DateTime?>(
nameof(SelectedDate),
o => o.SelectedDate,
(o, v) => o.SelectedDate = v);
public static readonly StyledProperty<DatePickerFormat> SelectedDateFormatProperty =
AvaloniaProperty.Register<DatePicker, DatePickerFormat>(
public static readonly StyledProperty<CalendarDatePickerFormat> SelectedDateFormatProperty =
AvaloniaProperty.Register<CalendarDatePicker, CalendarDatePickerFormat>(
nameof(SelectedDateFormat),
defaultValue: DatePickerFormat.Short,
defaultValue: CalendarDatePickerFormat.Short,
validate: IsValidSelectedDateFormat);
public static readonly StyledProperty<string> CustomDateFormatStringProperty =
AvaloniaProperty.Register<DatePicker, string>(
AvaloniaProperty.Register<CalendarDatePicker, string>(
nameof(CustomDateFormatString),
defaultValue: "d",
validate: IsValidDateFormatString);
public static readonly DirectProperty<DatePicker, string> TextProperty =
AvaloniaProperty.RegisterDirect<DatePicker, string>(
public static readonly DirectProperty<CalendarDatePicker, string> TextProperty =
AvaloniaProperty.RegisterDirect<CalendarDatePicker, string>(
nameof(Text),
o => o.Text,
(o, v) => o.Text = v);
public static readonly StyledProperty<string> WatermarkProperty =
TextBox.WatermarkProperty.AddOwner<DatePicker>();
TextBox.WatermarkProperty.AddOwner<CalendarDatePicker>();
public static readonly StyledProperty<bool> UseFloatingWatermarkProperty =
TextBox.UseFloatingWatermarkProperty.AddOwner<DatePicker>();
TextBox.UseFloatingWatermarkProperty.AddOwner<CalendarDatePicker>();
/// <summary>
@ -218,9 +218,9 @@ namespace Avalonia.Controls
/// </value>
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// The specified date is not in the range defined by
/// <see cref="P:Avalonia.Controls.DatePicker.DisplayDateStart" />
/// <see cref="P:Avalonia.Controls.CalendarDatePicker.DisplayDateStart" />
/// and
/// <see cref="P:Avalonia.Controls.DatePicker.DisplayDateEnd" />.
/// <see cref="P:Avalonia.Controls.CalendarDatePicker.DisplayDateEnd" />.
/// </exception>
public DateTime DisplayDate
{
@ -320,7 +320,7 @@ namespace Avalonia.Controls
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// An specified format is not valid.
/// </exception>
public DatePickerFormat SelectedDateFormat
public CalendarDatePickerFormat SelectedDateFormat
{
get { return GetValue(SelectedDateFormatProperty); }
set { SetValue(SelectedDateFormatProperty, value); }
@ -380,33 +380,33 @@ namespace Avalonia.Controls
/// Occurs when <see cref="P:Avalonia.Controls.DatePicker.Text" />
/// is assigned a value that cannot be interpreted as a date.
/// </summary>
public event EventHandler<DatePickerDateValidationErrorEventArgs> DateValidationError;
public event EventHandler<CalendarDatePickerDateValidationErrorEventArgs> DateValidationError;
/// <summary>
/// Occurs when the
/// <see cref="P:Avalonia.Controls.DatePicker.SelectedDate" />
/// <see cref="P:Avalonia.Controls.CalendarDatePicker.SelectedDate" />
/// property is changed.
/// </summary>
public event EventHandler<SelectionChangedEventArgs> SelectedDateChanged;
static DatePicker()
static CalendarDatePicker()
{
FocusableProperty.OverrideDefaultValue<DatePicker>(true);
DisplayDateProperty.Changed.AddClassHandler<DatePicker>((x,e) => x.OnDisplayDateChanged(e));
DisplayDateStartProperty.Changed.AddClassHandler<DatePicker>((x,e) => x.OnDisplayDateStartChanged(e));
DisplayDateEndProperty.Changed.AddClassHandler<DatePicker>((x,e) => x.OnDisplayDateEndChanged(e));
IsDropDownOpenProperty.Changed.AddClassHandler<DatePicker>((x,e) => x.OnIsDropDownOpenChanged(e));
SelectedDateProperty.Changed.AddClassHandler<DatePicker>((x,e) => x.OnSelectedDateChanged(e));
SelectedDateFormatProperty.Changed.AddClassHandler<DatePicker>((x,e) => x.OnSelectedDateFormatChanged(e));
CustomDateFormatStringProperty.Changed.AddClassHandler<DatePicker>((x,e) => x.OnCustomDateFormatStringChanged(e));
TextProperty.Changed.AddClassHandler<DatePicker>((x,e) => x.OnTextChanged(e));
FocusableProperty.OverrideDefaultValue<CalendarDatePicker>(true);
DisplayDateProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnDisplayDateChanged(e));
DisplayDateStartProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnDisplayDateStartChanged(e));
DisplayDateEndProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnDisplayDateEndChanged(e));
IsDropDownOpenProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnIsDropDownOpenChanged(e));
SelectedDateProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnSelectedDateChanged(e));
SelectedDateFormatProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnSelectedDateFormatChanged(e));
CustomDateFormatStringProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnCustomDateFormatStringChanged(e));
TextProperty.Changed.AddClassHandler<CalendarDatePicker>((x,e) => x.OnTextChanged(e));
}
/// <summary>
/// Initializes a new instance of the
/// <see cref="T:Avalonia.Controls.DatePicker" /> class.
/// </summary>
public DatePicker()
public CalendarDatePicker()
{
FirstDayOfWeek = DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek;
_defaultText = string.Empty;
@ -662,12 +662,12 @@ namespace Avalonia.Controls
// change is coming from the Calendar UI itself, so, we
// shouldn't change the DisplayDate since it will automatically
// be changed by the Calendar
if ((day.Month != DisplayDate.Month || day.Year != DisplayDate.Year) && (_calendar == null || !_calendar.DatePickerDisplayDateFlag))
if ((day.Month != DisplayDate.Month || day.Year != DisplayDate.Year) && (_calendar == null || !_calendar.CalendarDatePickerDisplayDateFlag))
{
DisplayDate = day;
}
if(_calendar != null)
_calendar.DatePickerDisplayDateFlag = false;
_calendar.CalendarDatePickerDisplayDateFlag = false;
}
else
{
@ -707,7 +707,7 @@ namespace Avalonia.Controls
}
private void OnCustomDateFormatStringChanged(AvaloniaPropertyChangedEventArgs e)
{
if(SelectedDateFormat == DatePickerFormat.Custom)
if(SelectedDateFormat == CalendarDatePickerFormat.Custom)
{
OnDateFormatChanged();
}
@ -752,15 +752,15 @@ namespace Avalonia.Controls
/// <summary>
/// Raises the
/// <see cref="E:Avalonia.Controls.DatePicker.DateValidationError" />
/// <see cref="E:Avalonia.Controls.CalendarDatePicker.DateValidationError" />
/// event.
/// </summary>
/// <param name="e">
/// A
/// <see cref="T:Avalonia.Controls.DatePickerDateValidationErrorEventArgs" />
/// <see cref="T:Avalonia.Controls.CalendarDatePickerDateValidationErrorEventArgs" />
/// that contains the event data.
/// </param>
protected virtual void OnDateValidationError(DatePickerDateValidationErrorEventArgs e)
protected virtual void OnDateValidationError(CalendarDatePickerDateValidationErrorEventArgs e)
{
DateValidationError?.Invoke(this, e);
}
@ -959,7 +959,7 @@ namespace Avalonia.Controls
}
else
{
var dateValidationError = new DatePickerDateValidationErrorEventArgs(new ArgumentOutOfRangeException(nameof(text), "SelectedDate value is not valid."), text);
var dateValidationError = new CalendarDatePickerDateValidationErrorEventArgs(new ArgumentOutOfRangeException(nameof(text), "SelectedDate value is not valid."), text);
OnDateValidationError(dateValidationError);
if (dateValidationError.ThrowException)
@ -970,7 +970,7 @@ namespace Avalonia.Controls
}
catch (FormatException ex)
{
DatePickerDateValidationErrorEventArgs textParseError = new DatePickerDateValidationErrorEventArgs(ex, text);
CalendarDatePickerDateValidationErrorEventArgs textParseError = new CalendarDatePickerDateValidationErrorEventArgs(ex, text);
OnDateValidationError(textParseError);
if (textParseError.ThrowException)
@ -986,11 +986,11 @@ namespace Avalonia.Controls
switch (SelectedDateFormat)
{
case DatePickerFormat.Short:
case CalendarDatePickerFormat.Short:
return string.Format(CultureInfo.CurrentCulture, d.ToString(dtfi.ShortDatePattern, dtfi));
case DatePickerFormat.Long:
case CalendarDatePickerFormat.Long:
return string.Format(CultureInfo.CurrentCulture, d.ToString(dtfi.LongDatePattern, dtfi));
case DatePickerFormat.Custom:
case CalendarDatePickerFormat.Custom:
return string.Format(CultureInfo.CurrentCulture, d.ToString(CustomDateFormatString, dtfi));
}
return null;
@ -1118,12 +1118,12 @@ namespace Avalonia.Controls
switch (SelectedDateFormat)
{
case DatePickerFormat.Long:
case CalendarDatePickerFormat.Long:
{
watermarkText = string.Format(CultureInfo.CurrentCulture, watermarkFormat, dtfi.LongDatePattern.ToString());
break;
}
case DatePickerFormat.Short:
case CalendarDatePickerFormat.Short:
default:
{
watermarkText = string.Format(CultureInfo.CurrentCulture, watermarkFormat, dtfi.ShortDatePattern.ToString());
@ -1139,11 +1139,11 @@ namespace Avalonia.Controls
}
}
private static bool IsValidSelectedDateFormat(DatePickerFormat value)
private static bool IsValidSelectedDateFormat(CalendarDatePickerFormat value)
{
return value == DatePickerFormat.Long
|| value == DatePickerFormat.Short
|| value == DatePickerFormat.Custom;
return value == CalendarDatePickerFormat.Long
|| value == CalendarDatePickerFormat.Short
|| value == CalendarDatePickerFormat.Custom;
}
private static bool IsValidDateFormatString(string formatString)
{

4
src/Avalonia.Controls/Calendar/CalendarItem.cs

@ -909,7 +909,7 @@ namespace Avalonia.Controls.Primitives
case CalendarSelectionMode.SingleDate:
{
DateTime selectedDate = (DateTime)b.DataContext;
Owner.DatePickerDisplayDateFlag = true;
Owner.CalendarDatePickerDisplayDateFlag = true;
if (Owner.SelectedDates.Count == 0)
{
Owner.SelectedDates.Add(selectedDate);
@ -981,7 +981,7 @@ namespace Avalonia.Controls.Primitives
}
case CalendarSelectionMode.SingleDate:
{
Owner.DatePickerDisplayDateFlag = true;
Owner.CalendarDatePickerDisplayDateFlag = true;
if (Owner.SelectedDates.Count == 0)
{
Owner.SelectedDates.Add(selectedDate);

35
src/Avalonia.Controls/Grid.cs

@ -1228,7 +1228,7 @@ namespace Avalonia.Controls
Debug.Assert(1 < count && 0 <= start && (start + count) <= definitions.Count);
// avoid processing when asked to distribute "0"
if (!_IsZero(requestedSize))
if (!MathUtilities.IsZero(requestedSize))
{
DefinitionBase[] tempDefinitions = TempDefinitions; // temp array used to remember definitions for sorting
int end = start + count;
@ -1306,7 +1306,7 @@ namespace Avalonia.Controls
}
// sanity check: requested size must all be distributed
Debug.Assert(_IsZero(sizeToDistribute));
Debug.Assert(MathUtilities.IsZero(sizeToDistribute));
}
else if (requestedSize <= rangeMaxSize)
{
@ -1346,7 +1346,7 @@ namespace Avalonia.Controls
}
// sanity check: requested size must all be distributed
Debug.Assert(_IsZero(sizeToDistribute));
Debug.Assert(MathUtilities.IsZero(sizeToDistribute));
}
else
{
@ -1358,7 +1358,7 @@ namespace Avalonia.Controls
double equalSize = requestedSize / count;
if (equalSize < maxMaxSize
&& !_AreClose(equalSize, maxMaxSize))
&& !MathUtilities.AreClose(equalSize, maxMaxSize))
{
// equi-size is less than maximum of maxSizes.
// in this case distribute so that smaller definitions grow faster than
@ -2151,7 +2151,7 @@ namespace Avalonia.Controls
// and precision of floating-point computation. (However, the resulting
// display is subject to anti-aliasing problems. TANSTAAFL.)
if (!_AreClose(roundedTakenSize, finalSize))
if (!MathUtilities.AreClose(roundedTakenSize, finalSize))
{
// Compute deltas
for (int i = 0; i < definitions.Count; ++i)
@ -2168,7 +2168,7 @@ namespace Avalonia.Controls
if (roundedTakenSize > finalSize)
{
int i = definitions.Count - 1;
while ((adjustedSize > finalSize && !_AreClose(adjustedSize, finalSize)) && i >= 0)
while ((adjustedSize > finalSize && !MathUtilities.AreClose(adjustedSize, finalSize)) && i >= 0)
{
DefinitionBase definition = definitions[definitionIndices[i]];
double final = definition.SizeCache - dpiIncrement;
@ -2184,7 +2184,7 @@ namespace Avalonia.Controls
else if (roundedTakenSize < finalSize)
{
int i = 0;
while ((adjustedSize < finalSize && !_AreClose(adjustedSize, finalSize)) && i < definitions.Count)
while ((adjustedSize < finalSize && !MathUtilities.AreClose(adjustedSize, finalSize)) && i < definitions.Count)
{
DefinitionBase definition = definitions[definitionIndices[i]];
double final = definition.SizeCache + dpiIncrement;
@ -2595,27 +2595,6 @@ namespace Avalonia.Controls
set { SetFlags(value, Flags.HasGroup3CellsInAutoRows); }
}
/// <summary>
/// fp version of <c>d == 0</c>.
/// </summary>
/// <param name="d">Value to check.</param>
/// <returns><c>true</c> if d == 0.</returns>
private static bool _IsZero(double d)
{
return (Math.Abs(d) < double.Epsilon);
}
/// <summary>
/// fp version of <c>d1 == d2</c>
/// </summary>
/// <param name="d1">First value to compare</param>
/// <param name="d2">Second value to compare</param>
/// <returns><c>true</c> if d1 == d2</returns>
private static bool _AreClose(double d1, double d2)
{
return (Math.Abs(d1 - d2) < double.Epsilon);
}
/// <summary>
/// Returns reference to extended data bag.
/// </summary>

20
src/Avalonia.Controls/IndexPath.cs

@ -123,6 +123,26 @@ namespace Avalonia.Controls
}
}
public bool IsAncestorOf(in IndexPath other)
{
if (other.GetSize() <= GetSize())
{
return false;
}
var size = GetSize();
for (int i = 0; i < size; i++)
{
if (GetAt(i) != other.GetAt(i))
{
return false;
}
}
return true;
}
public override string ToString()
{
if (_path != null)

47
src/Avalonia.Controls/IndexRange.cs

@ -132,6 +132,53 @@ namespace Avalonia.Controls
return result;
}
public static int Intersect(
IList<IndexRange> ranges,
IndexRange range,
IList<IndexRange>? removed = null)
{
var result = 0;
for (var i = 0; i < ranges.Count && range != s_invalid; ++i)
{
var existing = ranges[i];
if (existing.End < range.Begin || existing.Begin > range.End)
{
removed?.Add(existing);
ranges.RemoveAt(i--);
result += existing.Count;
}
else
{
if (existing.Begin < range.Begin)
{
var except = new IndexRange(existing.Begin, range.Begin - 1);
removed?.Add(except);
ranges[i] = existing = new IndexRange(range.Begin, existing.End);
result += except.Count;
}
if (existing.End > range.End)
{
var except = new IndexRange(range.End + 1, existing.End);
removed?.Add(except);
ranges[i] = new IndexRange(existing.Begin, range.End);
result += except.Count;
}
}
}
MergeRanges(ranges);
if (removed is object)
{
MergeRanges(removed);
}
return result;
}
public static int Remove(
IList<IndexRange> ranges,
IndexRange range,

14
src/Avalonia.Controls/Primitives/Track.cs

@ -41,13 +41,16 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<bool> IsDirectionReversedProperty =
AvaloniaProperty.Register<Track, bool>(nameof(IsDirectionReversed));
public static readonly StyledProperty<bool> IgnoreThumbDragProperty =
AvaloniaProperty.Register<Track, bool>(nameof(IsThumbDragHandled));
private double _minimum;
private double _maximum = 100.0;
private double _value;
static Track()
{
ThumbProperty.Changed.AddClassHandler<Track>((x,e) => x.ThumbChanged(e));
ThumbProperty.Changed.AddClassHandler<Track>((x, e) => x.ThumbChanged(e));
IncreaseButtonProperty.Changed.AddClassHandler<Track>((x, e) => x.ButtonChanged(e));
DecreaseButtonProperty.Changed.AddClassHandler<Track>((x, e) => x.ButtonChanged(e));
AffectsArrange<Track>(MinimumProperty, MaximumProperty, ValueProperty, OrientationProperty);
@ -113,6 +116,12 @@ namespace Avalonia.Controls.Primitives
set { SetValue(IsDirectionReversedProperty, value); }
}
public bool IsThumbDragHandled
{
get { return GetValue(IgnoreThumbDragProperty); }
set { SetValue(IgnoreThumbDragProperty, value); }
}
private double ThumbCenterOffset { get; set; }
private double Density { get; set; }
@ -422,6 +431,9 @@ namespace Avalonia.Controls.Primitives
private void ThumbDragged(object sender, VectorEventArgs e)
{
if (IsThumbDragHandled)
return;
Value = MathUtilities.Clamp(
Value + ValueFromDistance(e.Vector.X, e.Vector.Y),
Minimum,

76
src/Avalonia.Controls/SelectionModel.cs

@ -46,17 +46,25 @@ namespace Avalonia.Controls
if (_rootNode.Source != null)
{
if (_rootNode.Source != null)
// Temporarily prevent auto-select when switching source.
var restoreAutoSelect = _autoSelect;
_autoSelect = false;
try
{
using (var operation = new Operation(this))
{
ClearSelection(resetAnchor: true);
}
}
finally
{
_autoSelect = restoreAutoSelect;
}
}
_rootNode.Source = value;
ApplyAutoSelect();
ApplyAutoSelect(true);
RaisePropertyChanged("Source");
@ -114,7 +122,7 @@ namespace Avalonia.Controls
if (_autoSelect != value)
{
_autoSelect = value;
ApplyAutoSelect();
ApplyAutoSelect(true);
}
}
}
@ -133,7 +141,7 @@ namespace Avalonia.Controls
while (current?.AnchorIndex >= 0)
{
path.Add(current.AnchorIndex);
current = current.GetAt(current.AnchorIndex, false);
current = current.GetAt(current.AnchorIndex, false, default);
}
anchor = new IndexPath(path);
@ -188,7 +196,6 @@ namespace Avalonia.Controls
using var operation = new Operation(this);
ClearSelection(resetAnchor: true);
SelectWithPathImpl(value, select: true);
ApplyAutoSelect();
}
}
}
@ -384,21 +391,18 @@ namespace Avalonia.Controls
{
using var operation = new Operation(this);
SelectImpl(index, select: false);
ApplyAutoSelect();
}
public void Deselect(int groupIndex, int itemIndex)
{
using var operation = new Operation(this);
SelectWithGroupImpl(groupIndex, itemIndex, select: false);
ApplyAutoSelect();
}
public void DeselectAt(IndexPath index)
{
using var operation = new Operation(this);
SelectWithPathImpl(index, select: false);
ApplyAutoSelect();
}
public bool IsSelected(int index) => _rootNode.IsSelected(index);
@ -416,7 +420,7 @@ namespace Avalonia.Controls
for (int i = 0; i < path.GetSize() - 1; i++)
{
var childIndex = path.GetAt(i);
node = node.GetAt(childIndex, realizeChild: false);
node = node.GetAt(childIndex, false, default);
if (node == null)
{
@ -451,7 +455,7 @@ namespace Avalonia.Controls
}
var isSelected = (bool?)false;
var childNode = _rootNode.GetAt(groupIndex, realizeChild: false);
var childNode = _rootNode.GetAt(groupIndex, false, default);
if (childNode != null)
{
@ -470,7 +474,7 @@ namespace Avalonia.Controls
for (int i = 0; i < path.GetSize() - 1; i++)
{
var childIndex = path.GetAt(i);
node = node.GetAt(childIndex, realizeChild: false);
node = node.GetAt(childIndex, false, default);
if (node == null)
{
@ -565,7 +569,6 @@ namespace Avalonia.Controls
{
using var operation = new Operation(this);
ClearSelection(resetAnchor: true);
ApplyAutoSelect();
}
public IDisposable Update() => new Operation(this);
@ -592,10 +595,13 @@ namespace Avalonia.Controls
}
OnSelectionChanged(e);
ApplyAutoSelect();
ApplyAutoSelect(true);
}
internal IObservable<object?>? ResolvePath(object data, IndexPath dataIndexPath)
internal IObservable<object?>? ResolvePath(
object data,
IndexPath dataIndexPath,
IndexPath finalIndexPath)
{
IObservable<object?>? resolved = null;
@ -604,18 +610,22 @@ namespace Avalonia.Controls
{
if (_childrenRequestedEventArgs == null)
{
_childrenRequestedEventArgs = new SelectionModelChildrenRequestedEventArgs(data, dataIndexPath, false);
_childrenRequestedEventArgs = new SelectionModelChildrenRequestedEventArgs(
data,
dataIndexPath,
finalIndexPath,
false);
}
else
{
_childrenRequestedEventArgs.Initialize(data, dataIndexPath, false);
_childrenRequestedEventArgs.Initialize(data, dataIndexPath, finalIndexPath, false);
}
ChildrenRequested(this, _childrenRequestedEventArgs);
resolved = _childrenRequestedEventArgs.Children;
// Clear out the values in the args so that it cannot be used after the event handler call.
_childrenRequestedEventArgs.Initialize(null, default, true);
_childrenRequestedEventArgs.Initialize(null, default, default, true);
}
return resolved;
@ -632,6 +642,8 @@ namespace Avalonia.Controls
{
AnchorIndex = default;
}
OnSelectionChanged();
}
private void OnSelectionChanged(SelectionModelSelectionChangedEventArgs? e = null)
@ -667,6 +679,8 @@ namespace Avalonia.Controls
{
AnchorIndex = new IndexPath(index);
}
OnSelectionChanged();
}
private void SelectWithGroupImpl(int groupIndex, int itemIndex, bool select)
@ -676,13 +690,15 @@ namespace Avalonia.Controls
ClearSelection(resetAnchor: true);
}
var childNode = _rootNode.GetAt(groupIndex, realizeChild: true);
var childNode = _rootNode.GetAt(groupIndex, true, new IndexPath(groupIndex, itemIndex));
var selected = childNode!.Select(itemIndex, select);
if (selected)
{
AnchorIndex = new IndexPath(groupIndex, itemIndex);
}
OnSelectionChanged();
}
private void SelectWithPathImpl(IndexPath index, bool select)
@ -711,6 +727,8 @@ namespace Avalonia.Controls
{
AnchorIndex = index;
}
OnSelectionChanged();
}
private void SelectRangeFromAnchorImpl(int index, bool select)
@ -724,6 +742,7 @@ namespace Avalonia.Controls
}
_rootNode.SelectRange(new IndexRange(anchorIndex, index), select);
OnSelectionChanged();
}
private void SelectRangeFromAnchorWithGroupImpl(int endGroupIndex, int endItemIndex, bool select)
@ -752,11 +771,13 @@ namespace Avalonia.Controls
for (int groupIdx = startGroupIndex; groupIdx <= endGroupIndex; groupIdx++)
{
var groupNode = _rootNode.GetAt(groupIdx, realizeChild: true)!;
var groupNode = _rootNode.GetAt(groupIdx, true, new IndexPath(endGroupIndex, endItemIndex))!;
int startIndex = groupIdx == startGroupIndex ? startItemIndex : 0;
int endIndex = groupIdx == endGroupIndex ? endItemIndex : groupNode.DataCount - 1;
groupNode.SelectRange(new IndexRange(startIndex, endIndex), select);
}
OnSelectionChanged();
}
private void SelectRangeImpl(IndexPath start, IndexPath end, bool select)
@ -784,6 +805,8 @@ namespace Avalonia.Controls
info.ParentNode!.Select(info.Path.GetAt(info.Path.GetSize() - 1), select);
}
});
OnSelectionChanged();
}
private void BeginOperation()
@ -806,6 +829,8 @@ namespace Avalonia.Controls
if (--_operationCount == 0)
{
ApplyAutoSelect(false);
var changes = new List<SelectionNodeOperation>();
_rootNode.EndOperation(changes);
@ -827,7 +852,7 @@ namespace Avalonia.Controls
}
}
private void ApplyAutoSelect()
private void ApplyAutoSelect(bool createOperation)
{
if (AutoSelect)
{
@ -835,8 +860,15 @@ namespace Avalonia.Controls
if (SelectedIndex == default && _rootNode.ItemsSourceView?.Count > 0)
{
using var operation = new Operation(this);
SelectImpl(0, true);
if (createOperation)
{
using var operation = new Operation(this);
SelectImpl(0, true);
}
else
{
SelectImpl(0, true);
}
}
}
}

2
src/Avalonia.Controls/SelectionModelChangeSet.cs

@ -135,7 +135,7 @@ namespace Avalonia.Controls
if (index >= currentIndex && index < currentIndex + currentCount)
{
int targetIndex = GetIndexAt(getRanges(info), index - currentIndex);
item = info.Items?.GetAt(targetIndex);
item = info.Items?.Count > targetIndex ? info.Items?.GetAt(targetIndex) : null;
break;
}

22
src/Avalonia.Controls/SelectionModelChildrenRequestedEventArgs.cs

@ -16,15 +16,17 @@ namespace Avalonia.Controls
{
private object? _source;
private IndexPath _sourceIndexPath;
private IndexPath _finalIndexPath;
private bool _throwOnAccess;
internal SelectionModelChildrenRequestedEventArgs(
object source,
IndexPath sourceIndexPath,
IndexPath finalIndexPath,
bool throwOnAccess)
{
source = source ?? throw new ArgumentNullException(nameof(source));
Initialize(source, sourceIndexPath, throwOnAccess);
Initialize(source, sourceIndexPath, finalIndexPath, throwOnAccess);
}
/// <summary>
@ -65,9 +67,26 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Gets the index of the final object which is being attempted to be retrieved.
/// </summary>
public IndexPath FinalIndex
{
get
{
if (_throwOnAccess)
{
throw new ObjectDisposedException(nameof(SelectionModelChildrenRequestedEventArgs));
}
return _finalIndexPath;
}
}
internal void Initialize(
object? source,
IndexPath sourceIndexPath,
IndexPath finalIndexPath,
bool throwOnAccess)
{
if (!throwOnAccess && source == null)
@ -77,6 +96,7 @@ namespace Avalonia.Controls
_source = source;
_sourceIndexPath = sourceIndexPath;
_finalIndexPath = finalIndexPath;
_throwOnAccess = throwOnAccess;
}
}

27
src/Avalonia.Controls/SelectionNode.cs

@ -101,6 +101,7 @@ namespace Avalonia.Controls
ItemsSourceView = newDataSource;
TrimInvalidSelections();
PopulateSelectedItemsFromSelectedIndices();
HookupCollectionChangedHandler();
OnSelectionChanged();
@ -108,6 +109,26 @@ namespace Avalonia.Controls
}
}
private void TrimInvalidSelections()
{
if (_selected == null || ItemsSourceView == null)
{
return;
}
var validRange = ItemsSourceView.Count > 0 ? new IndexRange(0, ItemsSourceView.Count - 1) : new IndexRange(-1, -1);
var removed = new List<IndexRange>();
var removedCount = IndexRange.Intersect(_selected, validRange, removed);
if (removedCount > 0)
{
using var operation = _manager.Update();
SelectedCount -= removedCount;
OnSelectionChanged();
_operation!.Deselected(removed);
}
}
public ItemsSourceView? ItemsSourceView { get; private set; }
public int DataCount => ItemsSourceView?.Count ?? 0;
public int ChildrenNodeCount => _childrenNodes.Count;
@ -141,7 +162,7 @@ namespace Avalonia.Controls
// create a bunch of leaf node instances - instead i use the same instance m_leafNode to avoid
// an explosion of node objects. However, I'm still creating the m_childrenNodes
// collection unfortunately.
public SelectionNode? GetAt(int index, bool realizeChild)
public SelectionNode? GetAt(int index, bool realizeChild, IndexPath finalIndexPath)
{
SelectionNode? child = null;
@ -171,7 +192,7 @@ namespace Avalonia.Controls
if (childData != null)
{
var childDataIndexPath = IndexPath.CloneWithChildIndex(index);
resolver = _manager.ResolvePath(childData, childDataIndexPath);
resolver = _manager.ResolvePath(childData, childDataIndexPath, finalIndexPath);
}
if (resolver != null)
@ -843,7 +864,7 @@ namespace Avalonia.Controls
int notSelectedCount = 0;
for (int i = 0; i < ChildrenNodeCount; i++)
{
var child = GetAt(i, realizeChild: false);
var child = GetAt(i, false, default);
if (child != null)
{

161
src/Avalonia.Controls/Slider.cs

@ -1,12 +1,40 @@
using System;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Utilities;
namespace Avalonia.Controls
{
/// <summary>
/// Enum which describes how to position the ticks in a <see cref="Slider"/>.
/// </summary>
public enum TickPlacement
{
/// <summary>
/// No tick marks will appear.
/// </summary>
None,
/// <summary>
/// Tick marks will appear above the track for a horizontal <see cref="Slider"/>, or to the left of the track for a vertical <see cref="Slider"/>.
/// </summary>
TopLeft,
/// <summary>
/// Tick marks will appear below the track for a horizontal <see cref="Slider"/>, or to the right of the track for a vertical <see cref="Slider"/>.
/// </summary>
BottomRight,
/// <summary>
/// Tick marks appear on both sides of either a horizontal or vertical <see cref="Slider"/>.
/// </summary>
Outside
}
/// <summary>
/// A control that lets the user select from a range of values by moving a Thumb control along a Track.
/// </summary>
@ -30,19 +58,31 @@ namespace Avalonia.Controls
public static readonly StyledProperty<double> TickFrequencyProperty =
AvaloniaProperty.Register<Slider, double>(nameof(TickFrequency), 0.0);
/// <summary>
/// Defines the <see cref="TickPlacement"/> property.
/// </summary>
public static readonly StyledProperty<TickPlacement> TickPlacementProperty =
AvaloniaProperty.Register<TickBar, TickPlacement>(nameof(TickPlacement), 0d);
// Slider required parts
private bool _isDragging = false;
private Track _track;
private Button _decreaseButton;
private Button _increaseButton;
private IDisposable _decreaseButtonPressDispose;
private IDisposable _decreaseButtonReleaseDispose;
private IDisposable _increaseButtonSubscription;
private IDisposable _increaseButtonReleaseDispose;
private IDisposable _pointerMovedDispose;
/// <summary>
/// Initializes static members of the <see cref="Slider"/> class.
/// </summary>
static Slider()
{
PressedMixin.Attach<Slider>();
OrientationProperty.OverrideDefaultValue(typeof(Slider), Orientation.Horizontal);
Thumb.DragStartedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble);
Thumb.DragDeltaEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragDelta(e), RoutingStrategies.Bubble);
Thumb.DragCompletedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragCompleted(e), RoutingStrategies.Bubble);
}
@ -81,57 +121,89 @@ namespace Avalonia.Controls
set { SetValue(TickFrequencyProperty, value); }
}
/// <summary>
/// Gets or sets a value that indicates where to draw
/// tick marks in relation to the track.
/// </summary>
public TickPlacement TickPlacement
{
get { return GetValue(TickPlacementProperty); }
set { SetValue(TickPlacementProperty, value); }
}
/// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
if (_decreaseButton != null)
{
_decreaseButton.Click -= DecreaseClick;
}
if (_increaseButton != null)
{
_increaseButton.Click -= IncreaseClick;
}
base.OnApplyTemplate(e);
_decreaseButtonPressDispose?.Dispose();
_decreaseButtonReleaseDispose?.Dispose();
_increaseButtonSubscription?.Dispose();
_increaseButtonReleaseDispose?.Dispose();
_pointerMovedDispose?.Dispose();
_decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
_track = e.NameScope.Find<Track>("PART_Track");
_increaseButton = e.NameScope.Find<Button>("PART_IncreaseButton");
if (_track != null)
{
_track.IsThumbDragHandled = true;
}
if (_decreaseButton != null)
{
_decreaseButton.Click += DecreaseClick;
_decreaseButtonPressDispose = _decreaseButton.AddDisposableHandler(PointerPressedEvent, TrackPressed, RoutingStrategies.Tunnel);
_decreaseButtonReleaseDispose = _decreaseButton.AddDisposableHandler(PointerReleasedEvent, TrackReleased, RoutingStrategies.Tunnel);
}
if (_increaseButton != null)
{
_increaseButton.Click += IncreaseClick;
_increaseButtonSubscription = _increaseButton.AddDisposableHandler(PointerPressedEvent, TrackPressed, RoutingStrategies.Tunnel);
_increaseButtonReleaseDispose = _increaseButton.AddDisposableHandler(PointerReleasedEvent, TrackReleased, RoutingStrategies.Tunnel);
}
_pointerMovedDispose = this.AddDisposableHandler(PointerMovedEvent, TrackMoved, RoutingStrategies.Tunnel);
}
private void DecreaseClick(object sender, RoutedEventArgs e)
private void TrackMoved(object sender, PointerEventArgs e)
{
ChangeValueBy(-LargeChange);
if (_isDragging)
{
MoveToPoint(e.GetCurrentPoint(_track));
}
}
private void IncreaseClick(object sender, RoutedEventArgs e)
private void TrackReleased(object sender, PointerReleasedEventArgs e)
{
ChangeValueBy(LargeChange);
_isDragging = false;
}
private void ChangeValueBy(double by)
private void TrackPressed(object sender, PointerPressedEventArgs e)
{
if (IsSnapToTickEnabled)
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
by = by < 0 ? Math.Min(-TickFrequency, by) : Math.Max(TickFrequency, by);
MoveToPoint(e.GetCurrentPoint(_track));
_isDragging = true;
}
}
var value = Value;
var next = SnapToTick(Math.Max(Math.Min(value + by, Maximum), Minimum));
if (next != value)
{
Value = next;
}
private void MoveToPoint(PointerPoint x)
{
var orient = Orientation == Orientation.Horizontal;
var pointDen = orient ? _track.Bounds.Width : _track.Bounds.Height;
// Just add epsilon to avoid NaN in case 0/0
pointDen += double.Epsilon;
var pointNum = orient ? x.Position.X : x.Position.Y;
var logicalPos = MathUtilities.Clamp(pointNum / pointDen, 0.0d, 1.0d);
var invert = orient ? 0 : 1;
var calcVal = Math.Abs(invert - logicalPos);
var range = Maximum - Minimum;
var finalValue = calcVal * range;
Value = IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue;
}
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
@ -150,19 +222,7 @@ namespace Avalonia.Controls
/// <param name="e"></param>
protected virtual void OnThumbDragStarted(VectorEventArgs e)
{
}
/// <summary>
/// Called when user dragging the <see cref="Thumb"/>.
/// </summary>
/// <param name="e"></param>
protected virtual void OnThumbDragDelta(VectorEventArgs e)
{
Thumb thumb = e.Source as Thumb;
if (thumb != null && _track?.Thumb == thumb)
{
MoveToNextTick(_track.Value);
}
_isDragging = true;
}
/// <summary>
@ -171,15 +231,7 @@ namespace Avalonia.Controls
/// <param name="e"></param>
protected virtual void OnThumbDragCompleted(VectorEventArgs e)
{
}
/// <summary>
/// Searches for the closest tick and sets Value to that tick.
/// </summary>
/// <param name="value">Value that want to snap to closest Tick.</param>
private void MoveToNextTick(double value)
{
Value = SnapToTick(Math.Max(Minimum, Math.Min(Maximum, value)));
_isDragging = false;
}
/// <summary>
@ -188,14 +240,17 @@ namespace Avalonia.Controls
/// <param name="value">Value that want to snap to closest Tick.</param>
private double SnapToTick(double value)
{
if (IsSnapToTickEnabled && TickFrequency > 0.0)
var previous = Minimum;
var next = Maximum;
if (TickFrequency > 0.0)
{
double previous = Minimum + (Math.Round(((value - Minimum) / TickFrequency)) * TickFrequency);
double next = Math.Min(Maximum, previous + TickFrequency);
value = value > (previous + next) * 0.5 ? next : previous;
previous = Minimum + (Math.Round((value - Minimum) / TickFrequency) * TickFrequency);
next = Math.Min(Maximum, previous + TickFrequency);
}
return value;
// Choose the closest value between previous and next. If tie, snap to 'next'.
return MathUtilities.GreaterThanOrClose(value, (previous + next) * 0.5) ? next : previous;
}
private void UpdatePseudoClasses(Orientation o)

22
src/Avalonia.Controls/TextBlock.cs

@ -70,6 +70,14 @@ namespace Avalonia.Controls
Brushes.Black,
inherits: true);
/// <summary>
/// Defines the <see cref="MaxLines"/> property.
/// </summary>
public static readonly StyledProperty<int> MaxLinesProperty =
AvaloniaProperty.Register<TextBlock, int>(
nameof(MaxLines),
validate: IsValidMaxLines);
/// <summary>
/// Defines the <see cref="Text"/> property.
/// </summary>
@ -222,6 +230,15 @@ namespace Avalonia.Controls
set { SetValue(ForegroundProperty, value); }
}
/// <summary>
/// Gets or sets the maximum number of text lines.
/// </summary>
public int MaxLines
{
get => GetValue(MaxLinesProperty);
set => SetValue(MaxLinesProperty, value);
}
/// <summary>
/// Gets or sets the control's text wrapping mode.
/// </summary>
@ -404,7 +421,8 @@ namespace Avalonia.Controls
TextTrimming,
TextDecorations,
constraint.Width,
constraint.Height);
constraint.Height,
MaxLines);
}
/// <summary>
@ -451,5 +469,7 @@ namespace Avalonia.Controls
InvalidateMeasure();
}
private static bool IsValidMaxLines(int maxLines) => maxLines >= 0;
}
}

416
src/Avalonia.Controls/TickBar.cs

@ -0,0 +1,416 @@
using System;
using System.Collections.Generic;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Utilities;
namespace Avalonia.Controls
{
/// <summary>
/// Enum which describes how to position the TickBar.
/// </summary>
public enum TickBarPlacement
{
/// <summary>
/// Position this tick at the left of target element.
/// </summary>
Left,
/// <summary>
/// Position this tick at the top of target element.
/// </summary>
Top,
/// <summary>
/// Position this tick at the right of target element.
/// </summary>
Right,
/// <summary>
/// Position this tick at the bottom of target element.
/// </summary>
Bottom,
}
/// <summary>
/// An element that is used for drawing <see cref="Slider"/>'s Ticks.
/// </summary>
public class TickBar : Control
{
static TickBar()
{
AffectsRender<TickBar>(ReservedSpaceProperty,
MaximumProperty,
MinimumProperty,
OrientationProperty,
TickFrequencyProperty);
}
public TickBar() : base()
{
}
/// <summary>
/// Defines the <see cref="Fill"/> property.
/// </summary>
public static readonly StyledProperty<IBrush> FillProperty =
AvaloniaProperty.Register<TickBar, IBrush>(nameof(Fill));
/// <summary>
/// Brush used to fill the TickBar's Ticks.
/// </summary>
public IBrush Fill
{
get { return GetValue(FillProperty); }
set { SetValue(FillProperty, value); }
}
/// <summary>
/// Defines the <see cref="Minimum"/> property.
/// </summary>
public static readonly StyledProperty<double> MinimumProperty =
AvaloniaProperty.Register<TickBar, double>(nameof(Minimum), 0d);
/// <summary>
/// Logical position where the Minimum Tick will be drawn
/// </summary>
public double Minimum
{
get { return GetValue(MinimumProperty); }
set
{
SetValue(MinimumProperty, value);
}
}
/// <summary>
/// Defines the <see cref="Maximum"/> property.
/// </summary>
public static readonly StyledProperty<double> MaximumProperty =
AvaloniaProperty.Register<TickBar, double>(nameof(Maximum), 0d);
/// <summary>
/// Logical position where the Maximum Tick will be drawn
/// </summary>
public double Maximum
{
get { return GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
/// <summary>
/// Defines the <see cref="TickFrequency"/> property.
/// </summary>
public static readonly StyledProperty<double> TickFrequencyProperty =
AvaloniaProperty.Register<TickBar, double>(nameof(TickFrequency), 0d);
/// <summary>
/// TickFrequency property defines how the tick will be drawn.
/// </summary>
public double TickFrequency
{
get { return GetValue(TickFrequencyProperty); }
set { SetValue(TickFrequencyProperty, value); }
}
/// <summary>
/// Defines the <see cref="Orientation"/> property.
/// </summary>
public static readonly StyledProperty<Orientation> OrientationProperty =
AvaloniaProperty.Register<TickBar, Orientation>(nameof(Orientation));
/// <summary>
/// TickBar parent's orientation.
/// </summary>
public Orientation Orientation
{
get { return GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
/// <summary>
/// Defines the <see cref="Ticks"/> property.
/// </summary>
public static readonly StyledProperty<List<double>> TicksProperty =
AvaloniaProperty.Register<TickBar, List<double>>(nameof(Ticks));
/// <summary>
/// The Ticks property contains collection of value of type Double which
/// are the logical positions use to draw the ticks.
/// The property value is a <see cref="DoubleCollection" />.
/// </summary>
public List<double> Ticks
{
get { return GetValue(TicksProperty); }
set { SetValue(TicksProperty, value); }
}
/// <summary>
/// Defines the <see cref="IsDirectionReversed"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsDirectionReversedProperty =
AvaloniaProperty.Register<TickBar, bool>(nameof(IsDirectionReversed), false);
/// <summary>
/// The IsDirectionReversed property defines the direction of value incrementation.
/// By default, if Tick's orientation is Horizontal, ticks will be drawn from left to right.
/// (And, bottom to top for Vertical orientation).
/// If IsDirectionReversed is 'true' the direction of the drawing will be in opposite direction.
/// </summary>
public bool IsDirectionReversed
{
get { return GetValue(IsDirectionReversedProperty); }
set { SetValue(IsDirectionReversedProperty, value); }
}
/// <summary>
/// Defines the <see cref="Placement"/> property.
/// </summary>
public static readonly StyledProperty<TickBarPlacement> PlacementProperty =
AvaloniaProperty.Register<TickBar, TickBarPlacement>(nameof(Placement), 0d);
/// <summary>
/// Placement property specified how the Tick will be placed.
/// This property affects the way ticks are drawn.
/// This property has type of <see cref="TickBarPlacement" />.
/// </summary>
public TickBarPlacement Placement
{
get { return GetValue(PlacementProperty); }
set { SetValue(PlacementProperty, value); }
}
/// <summary>
/// Defines the <see cref="ReservedSpace"/> property.
/// </summary>
public static readonly StyledProperty<Rect> ReservedSpaceProperty =
AvaloniaProperty.Register<TickBar, Rect>(nameof(ReservedSpace));
/// <summary>
/// TickBar will use ReservedSpaceProperty for left and right spacing (for horizontal orientation) or
/// tob and bottom spacing (for vertical orienation).
/// The space on both sides of TickBar is half of specified ReservedSpace.
/// This property has type of <see cref="Rect" />.
/// </summary>
public Rect ReservedSpace
{
get { return GetValue(ReservedSpaceProperty); }
set { SetValue(ReservedSpaceProperty, value); }
}
/// <summary>
/// Draw ticks.
/// Ticks can be draw in 8 diffrent ways depends on Placment property and IsDirectionReversed property.
///
/// This function also draw selection-tick(s) if IsSelectionRangeEnabled is 'true' and
/// SelectionStart and SelectionEnd are valid.
///
/// The primary ticks (for Mininum and Maximum value) height will be 100% of TickBar's render size (use Width or Height
/// depends on Placement property).
///
/// The secondary ticks (all other ticks, including selection-tics) height will be 75% of TickBar's render size.
///
/// Brush that use to fill ticks is specified by Shape.Fill property.
///
/// Pen that use to draw ticks is specified by Shape.Pen property.
/// </summary>
public override void Render(DrawingContext dc)
{
var size = new Size(Bounds.Width, Bounds.Height);
var range = Maximum - Minimum;
var tickLen = 0.0d; // Height for Primary Tick (for Mininum and Maximum value)
var tickLen2 = 0.0d; // Height for Secondary Tick
var logicalToPhysical = 1.0;
var progression = 1.0d;
var startPoint = new Point();
var endPoint = new Point();
var rSpace = Orientation == Orientation.Horizontal ? ReservedSpace.Width : ReservedSpace.Height;
// Take Thumb size in to account
double halfReservedSpace = rSpace * 0.5;
switch (Placement)
{
case TickBarPlacement.Top:
if (MathUtilities.GreaterThanOrClose(rSpace, size.Width))
{
return;
}
size = new Size(size.Width - rSpace, size.Height);
tickLen = -size.Height;
startPoint = new Point(halfReservedSpace, size.Height);
endPoint = new Point(halfReservedSpace + size.Width, size.Height);
logicalToPhysical = size.Width / range;
progression = 1;
break;
case TickBarPlacement.Bottom:
if (MathUtilities.GreaterThanOrClose(rSpace, size.Width))
{
return;
}
size = new Size(size.Width - rSpace, size.Height);
tickLen = size.Height;
startPoint = new Point(halfReservedSpace, 0d);
endPoint = new Point(halfReservedSpace + size.Width, 0d);
logicalToPhysical = size.Width / range;
progression = 1;
break;
case TickBarPlacement.Left:
if (MathUtilities.GreaterThanOrClose(rSpace, size.Height))
{
return;
}
size = new Size(size.Width, size.Height - rSpace);
tickLen = -size.Width;
startPoint = new Point(size.Width, size.Height + halfReservedSpace);
endPoint = new Point(size.Width, halfReservedSpace);
logicalToPhysical = size.Height / range * -1;
progression = -1;
break;
case TickBarPlacement.Right:
if (MathUtilities.GreaterThanOrClose(rSpace, size.Height))
{
return;
}
size = new Size(size.Width, size.Height - rSpace);
tickLen = size.Width;
startPoint = new Point(0d, size.Height + halfReservedSpace);
endPoint = new Point(0d, halfReservedSpace);
logicalToPhysical = size.Height / range * -1;
progression = -1;
break;
};
tickLen2 = tickLen * 0.75;
// Invert direciton of the ticks
if (IsDirectionReversed)
{
progression *= -progression;
logicalToPhysical *= -1;
// swap startPoint & endPoint
var pt = startPoint;
startPoint = endPoint;
endPoint = pt;
}
var pen = new Pen(Fill, 1.0d);
// Is it Vertical?
if (Placement == TickBarPlacement.Left || Placement == TickBarPlacement.Right)
{
// Reduce tick interval if it is more than would be visible on the screen
double interval = TickFrequency;
if (interval > 0.0)
{
double minInterval = (Maximum - Minimum) / size.Height;
if (interval < minInterval)
{
interval = minInterval;
}
}
// Draw Min & Max tick
dc.DrawLine(pen, startPoint, new Point(startPoint.X + tickLen, startPoint.Y));
dc.DrawLine(pen, new Point(startPoint.X, endPoint.Y),
new Point(startPoint.X + tickLen, endPoint.Y));
// This property is rarely set so let's try to avoid the GetValue
// caching of the mutable default value
var ticks = Ticks ?? null;
// Draw ticks using specified Ticks collection
if (ticks?.Count > 0)
{
for (int i = 0; i < ticks.Count; i++)
{
if (MathUtilities.LessThanOrClose(ticks[i], Minimum) || MathUtilities.GreaterThanOrClose(ticks[i], Maximum))
{
continue;
}
double adjustedTick = ticks[i] - Minimum;
double y = adjustedTick * logicalToPhysical + startPoint.Y;
dc.DrawLine(pen,
new Point(startPoint.X, y),
new Point(startPoint.X + tickLen2, y));
}
}
// Draw ticks using specified TickFrequency
else if (interval > 0.0)
{
for (double i = interval; i < range; i += interval)
{
double y = i * logicalToPhysical + startPoint.Y;
dc.DrawLine(pen,
new Point(startPoint.X, y),
new Point(startPoint.X + tickLen2, y));
}
}
}
else // Placement == Top || Placement == Bottom
{
// Reduce tick interval if it is more than would be visible on the screen
double interval = TickFrequency;
if (interval > 0.0)
{
double minInterval = (Maximum - Minimum) / size.Width;
if (interval < minInterval)
{
interval = minInterval;
}
}
// Draw Min & Max tick
dc.DrawLine(pen, startPoint, new Point(startPoint.X, startPoint.Y + tickLen));
dc.DrawLine(pen, new Point(endPoint.X, startPoint.Y),
new Point(endPoint.X, startPoint.Y + tickLen));
// This property is rarely set so let's try to avoid the GetValue
// caching of the mutable default value
var ticks = Ticks ?? null;
// Draw ticks using specified Ticks collection
if (ticks?.Count > 0)
{
for (int i = 0; i < ticks.Count; i++)
{
if (MathUtilities.LessThanOrClose(ticks[i], Minimum) || MathUtilities.GreaterThanOrClose(ticks[i], Maximum))
{
continue;
}
double adjustedTick = ticks[i] - Minimum;
double x = adjustedTick * logicalToPhysical + startPoint.X;
dc.DrawLine(pen,
new Point(x, startPoint.Y),
new Point(x, startPoint.Y + tickLen2));
}
}
// Draw ticks using specified TickFrequency
else if (interval > 0.0)
{
for (double i = interval; i < range; i += interval)
{
double x = i * logicalToPhysical + startPoint.X;
dc.DrawLine(pen,
new Point(x, startPoint.Y),
new Point(x, startPoint.Y + tickLen2));
}
}
}
}
}
}

26
src/Avalonia.Controls/ToolTip.cs

@ -204,13 +204,15 @@ namespace Avalonia.Controls
private static void IsOpenChanged(AvaloniaPropertyChangedEventArgs e)
{
var control = (Control)e.Sender;
var newValue = (bool)e.NewValue;
ToolTip toolTip;
if ((bool)e.NewValue)
if (newValue)
{
var tip = GetTip(control);
if (tip == null) return;
var toolTip = control.GetValue(ToolTipProperty);
toolTip = control.GetValue(ToolTipProperty);
if (toolTip == null || (tip != toolTip && tip != toolTip.Content))
{
toolTip?.Close();
@ -223,9 +225,11 @@ namespace Avalonia.Controls
}
else
{
var toolTip = control.GetValue(ToolTipProperty);
toolTip = control.GetValue(ToolTipProperty);
toolTip?.Close();
}
toolTip?.UpdatePseudoClasses(newValue);
}
private void Open(Control control)
@ -238,6 +242,9 @@ namespace Avalonia.Controls
_popup.ConfigurePosition(control, GetPlacement(control),
new Point(GetHorizontalOffset(control), GetVerticalOffset(control)));
WindowManagerAddShadowHintChanged(_popup, false);
_popup.Show();
}
@ -250,5 +257,18 @@ namespace Avalonia.Controls
_popup = null;
}
}
private void WindowManagerAddShadowHintChanged(IPopupHost host, bool hint)
{
if (host is PopupRoot pr)
{
pr.PlatformImpl.SetWindowManagerAddShadowHint(hint);
}
}
private void UpdatePseudoClasses(bool newValue)
{
PseudoClasses.Set(":open", newValue);
}
}
}

18
src/Avalonia.Controls/TreeView.cs

@ -119,9 +119,10 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the selected item.
/// </summary>
/// <summary>
/// Gets or sets the selected item.
/// </summary>
/// <remarks>
/// Note that setting this property only currently works if the item is expanded to be visible.
/// To select non-expanded nodes use `Selection.SelectedIndex`.
/// </remarks>
public object SelectedItem
{
get => Selection.SelectedItem;
@ -346,7 +347,7 @@ namespace Avalonia.Controls
if (container != null)
{
container.BringIntoView();
DispatcherTimer.RunOnce(container.BringIntoView, TimeSpan.Zero);
}
}
}
@ -395,10 +396,17 @@ namespace Avalonia.Controls
private void OnSelectionModelChildrenRequested(object sender, SelectionModelChildrenRequestedEventArgs e)
{
var container = ItemContainerGenerator.Index.ContainerFromItem(e.Source) as ItemsControl;
var container = ItemContainerGenerator.Index.ContainerFromItem(e.Source) as TreeViewItem;
if (container is object)
{
if (e.SourceIndex.IsAncestorOf(e.FinalIndex))
{
container.IsExpanded = true;
container.ApplyTemplate();
container.Presenter?.ApplyTemplate();
}
e.Children = Observable.CombineLatest(
container.GetObservable(TreeViewItem.IsExpandedProperty),
container.GetObservable(ItemsProperty),

3
src/Avalonia.Controls/Utils/BorderRenderHelper.cs

@ -1,6 +1,7 @@
using System;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Utilities;
namespace Avalonia.Controls.Utils
{
@ -119,7 +120,7 @@ namespace Avalonia.Controls.Utils
}
var rect = new Rect(_size);
if (Math.Abs(borderThickness) > double.Epsilon)
if (!MathUtilities.IsZero(borderThickness))
rect = rect.Deflate(borderThickness * 0.5);
var rrect = new RoundedRect(rect, _cornerRadius.TopLeft, _cornerRadius.TopRight,
_cornerRadius.BottomRight, _cornerRadius.BottomLeft);

8
src/Avalonia.Controls/Utils/SelectionTreeHelper.cs

@ -28,7 +28,7 @@ namespace Avalonia.Controls.Utils
if (depth < path.GetSize() - 1)
{
node = node.GetAt(childIndex, realizeChildren)!;
node = node.GetAt(childIndex, realizeChildren, path)!;
}
}
}
@ -50,7 +50,7 @@ namespace Avalonia.Controls.Utils
int count = realizeChildren ? nextNode.Node.DataCount : nextNode.Node.ChildrenNodeCount;
for (int i = count - 1; i >= 0; i--)
{
var child = nextNode.Node.GetAt(i, realizeChildren);
var child = nextNode.Node.GetAt(i, realizeChildren, nextNode.Path);
var childPath = nextNode.Path.CloneWithChildIndex(i);
if (child != null)
{
@ -90,7 +90,7 @@ namespace Avalonia.Controls.Utils
for (int i = endIndex; i >= startIndex; i--)
{
var child = node.GetAt(i, realizeChild: true);
var child = node.GetAt(i, true, end);
if (child != null)
{
var childPath = currentPath.CloneWithChildIndex(i);
@ -112,7 +112,7 @@ namespace Avalonia.Controls.Utils
int endIndex = depth < end.GetSize() && isEndPath ? end.GetAt(depth) : info.Node.DataCount - 1;
for (int i = endIndex; i >= startIndex; i--)
{
var child = info.Node.GetAt(i, realizeChild: true);
var child = info.Node.GetAt(i, true, end);
if (child != null)
{
var childPath = info.Path.CloneWithChildIndex(i);

4
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -160,6 +160,10 @@ namespace Avalonia.DesignerSupport.Remote
public Task SetTextAsync(string text) => Task.CompletedTask;
public Task ClearAsync() => Task.CompletedTask;
public Task SetDataObjectAsync(IDataObject data) => Task.CompletedTask;
public Task<string[]> GetFormatsAsync() => Task.FromResult(new string[0]);
public Task<object> GetDataAsync(string format) => Task.FromResult((object)null);
}
class CursorFactoryStub : IStandardCursorFactory

17
src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs

@ -2,6 +2,7 @@
using Avalonia.Controls;
using Avalonia.Diagnostics.Models;
using Avalonia.Input;
using Avalonia.Threading;
namespace Avalonia.Diagnostics.ViewModels
{
@ -49,7 +50,21 @@ namespace Avalonia.Diagnostics.ViewModels
value is TreePageViewModel newTree &&
oldTree?.SelectedNode?.Visual is IControl control)
{
newTree.SelectControl(control);
// HACK: We want to select the currently selected control in the new tree, but
// to select nested nodes in TreeView, currently the TreeView has to be able to
// expand the parent nodes. Because at this point the TreeView isn't visible,
// this will fail unless we schedule the selection to run after layout.
DispatcherTimer.RunOnce(
() =>
{
try
{
newTree.SelectControl(control);
}
catch { }
},
TimeSpan.FromMilliseconds(0),
DispatcherPriority.ApplicationIdle);
}
RaiseAndSetIfChanged(ref _content, value);

38
src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs

@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Reactive;
using System.Reactive.Linq;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Avalonia.Styling;
using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.ViewModels
@ -82,5 +82,41 @@ namespace Avalonia.Diagnostics.ViewModels
get;
private set;
}
public IndexPath Index
{
get
{
var indices = new List<int>();
var child = this;
var parent = Parent;
while (parent is object)
{
indices.Add(IndexOf(parent.Children, child));
child = child.Parent;
parent = parent.Parent;
}
indices.Add(0);
indices.Reverse();
return new IndexPath(indices);
}
}
private static int IndexOf(IReadOnlyList<TreeNode> collection, TreeNode item)
{
var count = collection.Count;
for (var i = 0; i < count; ++i)
{
if (collection[i] == item)
{
return i;
}
}
throw new AvaloniaInternalException("TreeNode was not present in parent Children collection.");
}
}
}

24
src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs

@ -6,28 +6,40 @@ namespace Avalonia.Diagnostics.ViewModels
{
internal class TreePageViewModel : ViewModelBase, IDisposable
{
private TreeNode _selected;
private TreeNode _selectedNode;
private ControlDetailsViewModel _details;
private string _propertyFilter;
public TreePageViewModel(TreeNode[] nodes)
{
Nodes = nodes;
}
Selection = new SelectionModel
{
SingleSelect = true,
Source = Nodes
};
Selection.SelectionChanged += (s, e) =>
{
SelectedNode = (TreeNode)Selection.SelectedItem;
};
}
public TreeNode[] Nodes { get; protected set; }
public SelectionModel Selection { get; }
public TreeNode SelectedNode
{
get => _selected;
set
get => _selectedNode;
private set
{
if (Details != null)
{
_propertyFilter = Details.PropertyFilter;
}
if (RaiseAndSetIfChanged(ref _selected, value))
if (RaiseAndSetIfChanged(ref _selectedNode, value))
{
Details = value != null ?
new ControlDetailsViewModel(value.Visual, _propertyFilter) :
@ -83,8 +95,8 @@ namespace Avalonia.Diagnostics.ViewModels
if (node != null)
{
SelectedNode = node;
ExpandNode(node.Parent);
Selection.SelectedIndex = node.Index;
}
}

2
src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml

@ -6,7 +6,7 @@
<TreeView Name="tree"
BorderThickness="0"
Items="{Binding Nodes}"
SelectedItem="{Binding SelectedNode, Mode=TwoWay}">
Selection="{Binding Selection}">
<TreeView.DataTemplates>
<TreeDataTemplate DataType="vm:TreeNode"
ItemsSource="{Binding Children}">

6
src/Avalonia.Input/Platform/IClipboard.cs

@ -9,5 +9,11 @@ namespace Avalonia.Input.Platform
Task SetTextAsync(string text);
Task ClearAsync();
Task SetDataObjectAsync(IDataObject data);
Task<string[]> GetFormatsAsync();
Task<object> GetDataAsync(string format);
}
}

15
src/Avalonia.Native/AvnString.cs

@ -5,6 +5,7 @@ namespace Avalonia.Native.Interop
unsafe partial class IAvnString
{
private string _managed;
private byte[] _bytes;
public string String
{
@ -22,6 +23,20 @@ namespace Avalonia.Native.Interop
}
}
public byte[] Bytes
{
get
{
if (_bytes == null)
{
_bytes = new byte[Length()];
Marshal.Copy(Pointer(), _bytes, 0, _bytes.Length);
}
return _bytes;
}
}
public override string ToString() => String;
}

32
src/Avalonia.Native/ClipboardImpl.cs

@ -82,6 +82,38 @@ namespace Avalonia.Native
using (var strings = _native.GetStrings(NSFilenamesPboardType))
return strings.ToStringArray();
}
public unsafe Task SetDataObjectAsync(IDataObject data)
{
_native.Clear();
foreach (var fmt in data.GetDataFormats())
{
var o = data.Get(fmt);
if(o is string s)
using (var b = new Utf8Buffer(s))
_native.SetText(fmt, b.DangerousGetHandle());
else if(o is byte[] bytes)
fixed (byte* pbytes = bytes)
_native.SetBytes(fmt, new IntPtr(pbytes), bytes.Length);
}
return Task.CompletedTask;
}
public Task<string[]> GetFormatsAsync()
{
using (var n = _native.ObtainFormats())
return Task.FromResult(n.ToStringArray());
}
public async Task<object> GetDataAsync(string format)
{
if (format == DataFormats.Text)
return await GetTextAsync();
if (format == DataFormats.FileNames)
return GetFileNames();
using (var n = _native.GetBytes(format))
return n.Bytes;
}
}
class ClipboardDataObject : IDataObject, IDisposable

4
src/Avalonia.Themes.Fluent/DatePicker.xaml → src/Avalonia.Themes.Default/CalendarDatePicker.xaml

@ -8,7 +8,7 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style Selector="DatePicker">
<Style Selector="CalendarDatePicker">
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
@ -119,7 +119,7 @@
</Setter>
</Style>
<Style Selector="DatePicker:focus /template/ TextBox#PART_TextBox">
<Style Selector="CalendarDatePicker:focus /template/ TextBox#PART_TextBox">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}"/>
</Style>

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

@ -45,7 +45,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.CalendarDayButton.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.CalendarItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Calendar.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.DatePicker.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.CalendarDatePicker.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ButtonSpinner.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.NumericUpDown.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.AutoCompleteBox.xaml?assembly=Avalonia.Themes.Default"/>

92
src/Avalonia.Themes.Fluent/Accents/FluentBaseDark.xaml

@ -1,4 +1,6 @@
<Style xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style.Resources>
<Color x:Key="SystemAccentColor">#FF0078D7</Color>
<Color x:Key="SystemAltHighColor">#FF000000</Color>
@ -31,6 +33,10 @@
<Color x:Key="SystemRevealListLowColor">#FF1D1D1D</Color>
<Color x:Key="SystemRevealListMediumColor">#FF333333</Color>
<!--<AcrylicBrush x:Key="SystemControlAcrylicWindowBrush" BackgroundSource="HostBackdrop" TintColor="{ThemeResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{ThemeResource SystemChromeMediumColor}" />-->
<!--<RevealBackgroundBrush x:Key="SystemControlTransparentRevealBackgroundBrush" TargetTheme="Dark" Color="Transparent" FallbackColor="Transparent" />-->
<SolidColorBrush x:Key="SystemControlTransparentRevealBackgroundBrush" Color="Transparent" />
<!--<RevealBorderBrush x:Key="SystemControlTransparentRevealBorderBrush" TargetTheme="Dark" Color="Transparent" FallbackColor="Transparent" />-->
<SolidColorBrush x:Key="SystemControlTransparentRevealBorderBrush" Color="Transparent" />
<!-- Override system shape defaults -->
<CornerRadius x:Key="ControlCornerRadius">2,2,2,2</CornerRadius>
@ -86,6 +92,57 @@
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<!-- Resources for RepeatButton.xaml -->
<StaticResource x:Key="RepeatButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="RepeatButtonBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="RepeatButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="RepeatButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="RepeatButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="RepeatButtonBorderBrush" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushPointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<!-- Resources for Windows.UI.Xaml.Controls.Primitives.ToggleButton -->
<StaticResource x:Key="ToggleButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundChecked" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedPressed" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminate" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminatePointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminatePressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminateDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonForegroundChecked" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedPointerOver" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedPressed" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminate" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminatePointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminatePressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminateDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrush" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushPointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushChecked" ResourceKey="SystemControlHighlightAltTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedPointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminate" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminatePointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminatePressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminateDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<!-- BaseResources for ComboBox.xaml -->
<StaticResource x:Key="ComboBoxItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ComboBoxItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
@ -312,5 +369,38 @@
<StaticResource x:Key="RadioButtonCheckGlyphStrokePointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="RadioButtonCheckGlyphStrokePressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="RadioButtonCheckGlyphStrokeDisabled" ResourceKey="SystemControlTransparentBrush" />
<!-- BaseResources for Slider.xaml -->
<StaticResource x:Key="SliderContainerBackground" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundPointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderThumbBackground" ResourceKey="SystemControlForegroundAccentBrush" />
<StaticResource x:Key="SliderThumbBackgroundPointerOver" ResourceKey="SystemControlHighlightChromeAltLowBrush" />
<StaticResource x:Key="SliderThumbBackgroundPressed" ResourceKey="SystemControlHighlightChromeHighBrush" />
<StaticResource x:Key="SliderThumbBackgroundDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderTrackFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTrackFillPointerOver" ResourceKey="SystemControlForegroundBaseMediumBrush" />
<StaticResource x:Key="SliderTrackFillPressed" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTrackFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderTrackValueFill" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillPressed" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderHeaderForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="SliderHeaderForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="SliderTickBarFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTickBarFillDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="SliderInlineTickBarFill" ResourceKey="SystemControlBackgroundAltHighBrush" />
<!-- Resources for ToolTip.xaml -->
<x:Double x:Key="ToolTipContentThemeFontSize">12</x:Double>
<Thickness x:Key="ToolTipBorderThemeThickness">1</Thickness>
<StaticResource x:Key="ToolTipForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToolTipBackground" ResourceKey="SystemControlBackgroundChromeMediumLowBrush" />
<StaticResource x:Key="ToolTipBorderBrush" ResourceKey="SystemControlForegroundChromeHighBrush" />
<SolidColorBrush x:Key="ToolTipBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToolTipBorderThemeBrush" Color="#FF808080" />
<SolidColorBrush x:Key="ToolTipForegroundThemeBrush" Color="#FF666666" />
</Style.Resources>
</Style>

93
src/Avalonia.Themes.Fluent/Accents/FluentBaseLight.xaml

@ -1,4 +1,6 @@
<Style xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style.Resources>
<Color x:Key="SystemAccentColor">#FF0078D7</Color>
<Color x:Key="SystemAltHighColor">#FFFFFFFF</Color>
@ -31,6 +33,10 @@
<Color x:Key="SystemRevealListLowColor">#FFE6E6E6</Color>
<Color x:Key="SystemRevealListMediumColor">#FFCCCCCC</Color>
<!--<AcrylicBrush x:Key="SystemControlAcrylicWindowBrush" BackgroundSource="HostBackdrop" TintColor="{ThemeResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{ThemeResource SystemChromeMediumColor}" />-->
<!--<RevealBackgroundBrush x:Key="SystemControlTransparentRevealBackgroundBrush" TargetTheme="Dark" Color="Transparent" FallbackColor="Transparent" />-->
<SolidColorBrush x:Key="SystemControlTransparentRevealBackgroundBrush" Color="Transparent" />
<!--<RevealBorderBrush x:Key="SystemControlTransparentRevealBorderBrush" TargetTheme="Dark" Color="Transparent" FallbackColor="Transparent" />-->
<SolidColorBrush x:Key="SystemControlTransparentRevealBorderBrush" Color="Transparent" />
<!-- Override system shape defaults -->
<CornerRadius x:Key="ControlCornerRadius">2,2,2,2</CornerRadius>
@ -87,6 +93,58 @@
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<!-- Resources for RepeatButton.xaml -->
<StaticResource x:Key="RepeatButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="RepeatButtonBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="RepeatButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="RepeatButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="RepeatButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="RepeatButtonBorderBrush" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushPointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<!-- Resources for ToggleButton.xaml -->
<StaticResource x:Key="ToggleButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundChecked" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedPressed" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminate" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminatePointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminatePressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminateDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonForegroundChecked" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedPointerOver" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedPressed" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminate" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminatePointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminatePressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminateDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrush" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushPointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushChecked" ResourceKey="SystemControlHighlightAltTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedPointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminate" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminatePointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminatePressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminateDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<!-- BaseResources for ComboBox.xaml -->
<StaticResource x:Key="ComboBoxItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ComboBoxItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
@ -313,5 +371,38 @@
<StaticResource x:Key="RadioButtonCheckGlyphStrokePointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="RadioButtonCheckGlyphStrokePressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="RadioButtonCheckGlyphStrokeDisabled" ResourceKey="SystemControlTransparentBrush" />
<!-- BaseResources for Slider.xaml -->
<StaticResource x:Key="SliderContainerBackground" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundPointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderThumbBackground" ResourceKey="SystemControlForegroundAccentBrush" />
<StaticResource x:Key="SliderThumbBackgroundPointerOver" ResourceKey="SystemControlHighlightChromeAltLowBrush" />
<StaticResource x:Key="SliderThumbBackgroundPressed" ResourceKey="SystemControlHighlightChromeHighBrush" />
<StaticResource x:Key="SliderThumbBackgroundDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderTrackFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTrackFillPointerOver" ResourceKey="SystemControlForegroundBaseMediumBrush" />
<StaticResource x:Key="SliderTrackFillPressed" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTrackFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderTrackValueFill" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillPressed" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderHeaderForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="SliderHeaderForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="SliderTickBarFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTickBarFillDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="SliderInlineTickBarFill" ResourceKey="SystemControlBackgroundAltHighBrush" />
<!-- Resources for ToolTip.xaml -->
<x:Double x:Key="ToolTipContentThemeFontSize">12</x:Double>
<Thickness x:Key="ToolTipBorderThemeThickness">1</Thickness>
<StaticResource x:Key="ToolTipForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToolTipBackground" ResourceKey="SystemControlBackgroundChromeMediumLowBrush" />
<StaticResource x:Key="ToolTipBorderBrush" ResourceKey="SystemControlForegroundChromeHighBrush" />
<SolidColorBrush x:Key="ToolTipBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToolTipBorderThemeBrush" Color="#FF808080" />
<SolidColorBrush x:Key="ToolTipForegroundThemeBrush" Color="#FF666666" />
</Style.Resources>
</Style>

175
src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml

@ -1,6 +1,6 @@
<Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style.Resources>
<!-- Resources for Button.xaml -->
<StaticResource x:Key="AccentButtonBackground" ResourceKey="SystemControlBackgroundAccentBrush" />
@ -39,6 +39,87 @@
<SolidColorBrush x:Key="ButtonPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ButtonPressedForegroundThemeBrush" Color="#FF000000" />
<!-- Resources for RepeatButton.xaml -->
<Thickness x:Key="RepeatButtonBorderThemeThickness">1</Thickness>
<StaticResource x:Key="RepeatButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<SolidColorBrush x:Key="RepeatButtonBackgroundPointerOver" Color="{StaticResource SystemBaseHighColor}" Opacity="0.1" />
<StaticResource x:Key="RepeatButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="RepeatButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="RepeatButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="RepeatButtonBorderBrush" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushPointerOver" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<SolidColorBrush x:Key="RepeatButtonBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="RepeatButtonDisabledBackgroundThemeBrush" Color="Transparent" />
<SolidColorBrush x:Key="RepeatButtonDisabledBorderThemeBrush" Color="#66FFFFFF" />
<SolidColorBrush x:Key="RepeatButtonDisabledForegroundThemeBrush" Color="#66FFFFFF" />
<SolidColorBrush x:Key="RepeatButtonForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="RepeatButtonPointerOverBackgroundThemeBrush" Color="#21FFFFFF" />
<SolidColorBrush x:Key="RepeatButtonPointerOverForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="RepeatButtonPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="RepeatButtonPressedForegroundThemeBrush" Color="#FF000000" />
<!-- Resources for ToggleButton.xaml -->
<Thickness x:Key="ToggleButtonBorderThemeThickness">1</Thickness>
<StaticResource x:Key="ToggleButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<SolidColorBrush x:Key="ToggleButtonBackgroundPointerOver" Color="{StaticResource SystemBaseHighColor}" Opacity="0.1" />
<StaticResource x:Key="ToggleButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundChecked" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedPointerOver" ResourceKey="SystemAccentColorDark1" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedPressed" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminate" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminatePointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminatePressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminateDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonForegroundChecked" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedPointerOver" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedPressed" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminate" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminatePointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminatePressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminateDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrush" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushPointerOver" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushChecked" ResourceKey="SystemControlHighlightAltTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedPointerOver" ResourceKey="SystemControlHighlightAltTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminate" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminatePointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminatePressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminateDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<SolidColorBrush x:Key="ToggleButtonBackgroundThemeBrush" Color="Transparent" />
<SolidColorBrush x:Key="ToggleButtonBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToggleButtonCheckedBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToggleButtonCheckedBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToggleButtonCheckedDisabledBackgroundThemeBrush" Color="#66FFFFFF" />
<SolidColorBrush x:Key="ToggleButtonCheckedDisabledForegroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ToggleButtonCheckedForegroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ToggleButtonCheckedPointerOverBackgroundThemeBrush" Color="#99FFFFFF" />
<SolidColorBrush x:Key="ToggleButtonCheckedPointerOverBorderThemeBrush" Color="#99FFFFFF" />
<SolidColorBrush x:Key="ToggleButtonCheckedPressedBackgroundThemeBrush" Color="Transparent" />
<SolidColorBrush x:Key="ToggleButtonCheckedPressedBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToggleButtonCheckedPressedForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToggleButtonDisabledBorderThemeBrush" Color="#66FFFFFF" />
<SolidColorBrush x:Key="ToggleButtonDisabledForegroundThemeBrush" Color="#66FFFFFF" />
<SolidColorBrush x:Key="ToggleButtonForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToggleButtonPointerOverBackgroundThemeBrush" Color="#21FFFFFF" />
<SolidColorBrush x:Key="ToggleButtonPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToggleButtonPressedForegroundThemeBrush" Color="#FF000000" />
<!-- Resources for ComboBox.xaml -->
<x:Double x:Key="ComboBoxArrowThemeFontSize">21</x:Double>
<x:Double x:Key="ComboBoxThemeMinWidth">64</x:Double>
@ -327,6 +408,33 @@
<SolidColorBrush x:Key="CheckBoxPressedBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="CheckBoxPressedForegroundThemeBrush" Color="#FF000000" />
<!-- Resources for Calendar.xaml, CalendarButton.xaml, CalendarDayButton.xaml, CalendarItem.xaml -->
<StaticResource x:Key="CalendarViewFocusBorderBrush" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="CalendarViewSelectedHoverBorderBrush" ResourceKey="SystemControlHighlightListAccentMediumBrush" />
<StaticResource x:Key="CalendarViewSelectedPressedBorderBrush" ResourceKey="SystemControlHighlightListAccentHighBrush" />
<StaticResource x:Key="CalendarViewSelectedBorderBrush" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="CalendarViewHoverBorderBrush" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="CalendarViewPressedBorderBrush" ResourceKey="SystemControlHighlightBaseMediumBrush" />
<StaticResource x:Key="CalendarViewTodayForeground" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="CalendarViewBlackoutForeground" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="CalendarViewSelectedForeground" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="CalendarViewPressedForeground" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="CalendarViewOutOfScopeForeground" ResourceKey="SystemControlHyperlinkBaseHighBrush" />
<StaticResource x:Key="CalendarViewCalendarItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="CalendarViewOutOfScopeBackground" ResourceKey="SystemControlDisabledChromeMediumLowBrush" />
<StaticResource x:Key="CalendarViewCalendarItemBackground" ResourceKey="SystemControlBackgroundAltHighBrush" />
<StaticResource x:Key="CalendarViewForeground" ResourceKey="SystemControlHyperlinkBaseMediumHighBrush" />
<StaticResource x:Key="CalendarViewBackground" ResourceKey="SystemControlBackgroundAltHighBrush" />
<StaticResource x:Key="CalendarViewBorderBrush" ResourceKey="SystemControlForegroundChromeMediumBrush" />
<StaticResource x:Key="CalendarViewWeekDayForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonBackground" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonForegroundPointerOver" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonForegroundPressed" ResourceKey="SystemControlForegroundBaseMediumBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="CalendarViewCalendarItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
<StaticResource x:Key="CalendarViewCalendarItemRevealBorderBrush" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonBorderBrushPointerOver" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonBorderBrush" ResourceKey="SystemControlTransparentBrush" />
<!-- Resources for RadioButton.xaml -->
<x:Double x:Key="RadioButtonBorderThemeThickness">1</x:Double>
<StaticResource x:Key="RadioButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
@ -380,5 +488,66 @@
<SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" />
<!-- Resources for Slider.xaml -->
<x:Double x:Key="SliderOutsideTickBarThemeHeight">4</x:Double>
<x:Double x:Key="SliderTrackThemeHeight">2</x:Double>
<Thickness x:Key="SliderBorderThemeThickness">0</Thickness>
<Thickness x:Key="SliderHeaderThemeMargin">0,0,0,4</Thickness>
<FontWeight x:Key="SliderHeaderThemeFontWeight">Normal</FontWeight>
<StaticResource x:Key="SliderContainerBackground" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundPointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderThumbBackground" ResourceKey="SystemControlForegroundAccentBrush" />
<StaticResource x:Key="SliderThumbBackgroundPointerOver" ResourceKey="SystemAccentColorLight1" />
<StaticResource x:Key="SliderThumbBackgroundPressed" ResourceKey="SystemAccentColorDark1" />
<StaticResource x:Key="SliderThumbBackgroundDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderTrackFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTrackFillPointerOver" ResourceKey="SystemControlForegroundBaseMediumBrush" />
<StaticResource x:Key="SliderTrackFillPressed" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTrackFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderTrackValueFill" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillPressed" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderHeaderForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="SliderHeaderForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="SliderTickBarFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTickBarFillDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="SliderInlineTickBarFill" ResourceKey="SystemControlBackgroundAltHighBrush" />
<SolidColorBrush x:Key="SliderBorderThemeBrush" Color="Transparent" />
<SolidColorBrush x:Key="SliderDisabledBorderThemeBrush" Color="Transparent" />
<SolidColorBrush x:Key="SliderThumbBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="SliderThumbBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="SliderThumbDisabledBackgroundThemeBrush" Color="#FF7E7E7E" />
<SolidColorBrush x:Key="SliderThumbPointerOverBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="SliderThumbPointerOverBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="SliderThumbPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="SliderThumbPressedBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="SliderTickMarkInlineBackgroundThemeBrush" Color="Black" />
<SolidColorBrush x:Key="SliderTickMarkInlineDisabledForegroundThemeBrush" Color="Black" />
<SolidColorBrush x:Key="SliderTickmarkOutsideBackgroundThemeBrush" Color="#80FFFFFF" />
<SolidColorBrush x:Key="SliderTickMarkOutsideDisabledForegroundThemeBrush" Color="#80FFFFFF" />
<SolidColorBrush x:Key="SliderTrackBackgroundThemeBrush" Color="#29FFFFFF" />
<SolidColorBrush x:Key="SliderTrackDecreaseBackgroundThemeBrush" Color="#FF5B2EC5" />
<SolidColorBrush x:Key="SliderTrackDecreaseDisabledBackgroundThemeBrush" Color="#1FFFFFFF" />
<SolidColorBrush x:Key="SliderTrackDecreasePointerOverBackgroundThemeBrush" Color="#FF724BCD" />
<SolidColorBrush x:Key="SliderTrackDecreasePressedBackgroundThemeBrush" Color="#FF8152EF" />
<SolidColorBrush x:Key="SliderTrackDisabledBackgroundThemeBrush" Color="#29FFFFFF" />
<SolidColorBrush x:Key="SliderTrackPointerOverBackgroundThemeBrush" Color="#46FFFFFF" />
<SolidColorBrush x:Key="SliderTrackPressedBackgroundThemeBrush" Color="#59FFFFFF" />
<SolidColorBrush x:Key="SliderHeaderForegroundThemeBrush" Color="#FFFFFFFF" />
<!-- Resources for ToolTip.xaml -->
<x:Double x:Key="ToolTipContentThemeFontSize">12</x:Double>
<Thickness x:Key="ToolTipBorderThemeThickness">1</Thickness>
<StaticResource x:Key="ToolTipForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToolTipBackground" ResourceKey="SystemControlBackgroundChromeMediumLowBrush" />
<StaticResource x:Key="ToolTipBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
<SolidColorBrush x:Key="ToolTipBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToolTipBorderThemeBrush" Color="#FF808080" />
<SolidColorBrush x:Key="ToolTipForegroundThemeBrush" Color="#FF666666" />
<Thickness x:Key="ToolTipBorderThemePadding">8,5,8,7</Thickness>
</Style.Resources>
</Style>

174
src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml

@ -1,6 +1,6 @@
<Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style.Resources>
<!-- Resources for Button.xaml -->
<StaticResource x:Key="AccentButtonBackground" ResourceKey="SystemControlBackgroundAccentBrush" />
@ -39,6 +39,86 @@
<SolidColorBrush x:Key="ButtonPressedBackgroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
<!-- Resources for RepeatButton.xaml -->
<Thickness x:Key="RepeatButtonBorderThemeThickness">1</Thickness>
<StaticResource x:Key="RepeatButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<SolidColorBrush x:Key="RepeatButtonBackgroundPointerOver" Color="{StaticResource SystemBaseHighColor}" Opacity="0.1" />
<StaticResource x:Key="RepeatButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="RepeatButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="RepeatButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="RepeatButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="RepeatButtonBorderBrush" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushPointerOver" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="RepeatButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<SolidColorBrush x:Key="RepeatButtonBorderThemeBrush" Color="#33000000" />
<SolidColorBrush x:Key="RepeatButtonDisabledBackgroundThemeBrush" Color="#66CACACA" />
<SolidColorBrush x:Key="RepeatButtonDisabledBorderThemeBrush" Color="#1A000000" />
<SolidColorBrush x:Key="RepeatButtonDisabledForegroundThemeBrush" Color="#66000000" />
<SolidColorBrush x:Key="RepeatButtonForegroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="RepeatButtonPointerOverBackgroundThemeBrush" Color="#D1CDCDCD" />
<SolidColorBrush x:Key="RepeatButtonPointerOverForegroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="RepeatButtonPressedBackgroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="RepeatButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
<!-- Resources for ToggleButton.xaml -->
<Thickness x:Key="ToggleButtonBorderThemeThickness">1</Thickness>
<StaticResource x:Key="ToggleButtonBackground" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<SolidColorBrush x:Key="ToggleButtonBackgroundPointerOver" Color="{StaticResource SystemBaseHighColor}" Opacity="0.1" />
<StaticResource x:Key="ToggleButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundChecked" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedPointerOver" ResourceKey="SystemAccentColorLight1" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedPressed" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundCheckedDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminate" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminatePointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminatePressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBackgroundIndeterminateDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ToggleButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonForegroundChecked" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedPointerOver" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedPressed" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="ToggleButtonForegroundCheckedDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminate" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminatePointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminatePressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="ToggleButtonForegroundIndeterminateDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrush" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushPointerOver" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushChecked" ResourceKey="SystemControlHighlightAltTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedPointerOver" ResourceKey="SystemControlHighlightAltTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushCheckedDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminate" ResourceKey="SystemControlForegroundTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminatePointerOver" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminatePressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ToggleButtonBorderBrushIndeterminateDisabled" ResourceKey="SystemControlDisabledTransparentBrush" />
<SolidColorBrush x:Key="ToggleButtonBackgroundThemeBrush" Color="Transparent" />
<SolidColorBrush x:Key="ToggleButtonBorderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ToggleButtonCheckedBackgroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ToggleButtonCheckedBorderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ToggleButtonCheckedDisabledBackgroundThemeBrush" Color="#66000000" />
<SolidColorBrush x:Key="ToggleButtonCheckedDisabledForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToggleButtonCheckedForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToggleButtonCheckedPointerOverBackgroundThemeBrush" Color="#99000000" />
<SolidColorBrush x:Key="ToggleButtonCheckedPointerOverBorderThemeBrush" Color="#99000000" />
<SolidColorBrush x:Key="ToggleButtonCheckedPressedBackgroundThemeBrush" Color="Transparent" />
<SolidColorBrush x:Key="ToggleButtonCheckedPressedBorderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ToggleButtonCheckedPressedForegroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ToggleButtonDisabledBorderThemeBrush" Color="#66000000" />
<SolidColorBrush x:Key="ToggleButtonDisabledForegroundThemeBrush" Color="#66000000" />
<SolidColorBrush x:Key="ToggleButtonForegroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ToggleButtonPointerOverBackgroundThemeBrush" Color="#21000000" />
<SolidColorBrush x:Key="ToggleButtonPressedBackgroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ToggleButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
<!-- Resources for ComboBox.xaml -->
<x:Double x:Key="ComboBoxArrowThemeFontSize">21</x:Double>
<x:Double x:Key="ComboBoxThemeMinWidth">64</x:Double>
@ -327,6 +407,33 @@
<SolidColorBrush x:Key="CheckBoxPressedBorderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="CheckBoxPressedForegroundThemeBrush" Color="#FFFFFFFF" />
<!-- Resources for Calendar.xaml, CalendarButton.xaml, CalendarDayButton.xaml, CalendarItem.xaml -->
<StaticResource x:Key="CalendarViewFocusBorderBrush" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="CalendarViewSelectedHoverBorderBrush" ResourceKey="SystemControlHighlightListAccentMediumBrush" />
<StaticResource x:Key="CalendarViewSelectedPressedBorderBrush" ResourceKey="SystemControlHighlightListAccentHighBrush" />
<StaticResource x:Key="CalendarViewSelectedBorderBrush" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="CalendarViewHoverBorderBrush" ResourceKey="SystemControlHighlightBaseMediumLowBrush" />
<StaticResource x:Key="CalendarViewPressedBorderBrush" ResourceKey="SystemControlHighlightBaseMediumBrush" />
<StaticResource x:Key="CalendarViewTodayForeground" ResourceKey="SystemControlHighlightAltChromeWhiteBrush" />
<StaticResource x:Key="CalendarViewBlackoutForeground" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="CalendarViewSelectedForeground" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="CalendarViewPressedForeground" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="CalendarViewOutOfScopeForeground" ResourceKey="SystemControlHyperlinkBaseHighBrush" />
<StaticResource x:Key="CalendarViewCalendarItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="CalendarViewOutOfScopeBackground" ResourceKey="SystemControlDisabledChromeMediumLowBrush" />
<StaticResource x:Key="CalendarViewCalendarItemBackground" ResourceKey="SystemControlBackgroundAltHighBrush" />
<StaticResource x:Key="CalendarViewForeground" ResourceKey="SystemControlHyperlinkBaseMediumHighBrush" />
<StaticResource x:Key="CalendarViewBackground" ResourceKey="SystemControlBackgroundAltHighBrush" />
<StaticResource x:Key="CalendarViewBorderBrush" ResourceKey="SystemControlForegroundChromeMediumBrush" />
<StaticResource x:Key="CalendarViewWeekDayForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonBackground" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonForegroundPointerOver" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonForegroundPressed" ResourceKey="SystemControlForegroundBaseMediumBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="CalendarViewCalendarItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
<StaticResource x:Key="CalendarViewCalendarItemRevealBorderBrush" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonBorderBrushPointerOver" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="CalendarViewNavigationButtonBorderBrush" ResourceKey="SystemControlTransparentBrush" />
<!-- Resources for RadioButton.xaml -->
<x:Double x:Key="RadioButtonBorderThemeThickness">1</x:Double>
<StaticResource x:Key="RadioButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
@ -380,5 +487,66 @@
<SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" />
<!-- Resources for Slider.xaml -->
<x:Double x:Key="SliderOutsideTickBarThemeHeight">4</x:Double>
<x:Double x:Key="SliderTrackThemeHeight">2</x:Double>
<Thickness x:Key="SliderBorderThemeThickness">0</Thickness>
<Thickness x:Key="SliderHeaderThemeMargin">0,0,0,4</Thickness>
<FontWeight x:Key="SliderHeaderThemeFontWeight">Normal</FontWeight>
<StaticResource x:Key="SliderContainerBackground" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundPointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundPressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderContainerBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="SliderThumbBackground" ResourceKey="SystemControlForegroundAccentBrush" />
<StaticResource x:Key="SliderThumbBackgroundPointerOver" ResourceKey="SystemAccentColorLight1" />
<StaticResource x:Key="SliderThumbBackgroundPressed" ResourceKey="SystemAccentColorDark1" />
<StaticResource x:Key="SliderThumbBackgroundDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderTrackFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTrackFillPointerOver" ResourceKey="SystemControlForegroundBaseMediumBrush" />
<StaticResource x:Key="SliderTrackFillPressed" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTrackFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderTrackValueFill" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillPointerOver" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillPressed" ResourceKey="SystemControlHighlightAccentBrush" />
<StaticResource x:Key="SliderTrackValueFillDisabled" ResourceKey="SystemControlDisabledChromeDisabledHighBrush" />
<StaticResource x:Key="SliderHeaderForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="SliderHeaderForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="SliderTickBarFill" ResourceKey="SystemControlForegroundBaseMediumLowBrush" />
<StaticResource x:Key="SliderTickBarFillDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="SliderInlineTickBarFill" ResourceKey="SystemControlBackgroundAltHighBrush" />
<SolidColorBrush x:Key="SliderBorderThemeBrush" Color="Transparent" />
<SolidColorBrush x:Key="SliderDisabledBorderThemeBrush" Color="Transparent" />
<SolidColorBrush x:Key="SliderThumbBackgroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="SliderThumbBorderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="SliderThumbDisabledBackgroundThemeBrush" Color="#FF929292" />
<SolidColorBrush x:Key="SliderThumbPointerOverBackgroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="SliderThumbPointerOverBorderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="SliderThumbPressedBackgroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="SliderThumbPressedBorderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="SliderTickMarkInlineBackgroundThemeBrush" Color="White" />
<SolidColorBrush x:Key="SliderTickMarkInlineDisabledForegroundThemeBrush" Color="White" />
<SolidColorBrush x:Key="SliderTickmarkOutsideBackgroundThemeBrush" Color="#80000000" />
<SolidColorBrush x:Key="SliderTickMarkOutsideDisabledForegroundThemeBrush" Color="#80000000" />
<SolidColorBrush x:Key="SliderTrackBackgroundThemeBrush" Color="#1A000000" />
<SolidColorBrush x:Key="SliderTrackDecreaseBackgroundThemeBrush" Color="#FF4617B4" />
<SolidColorBrush x:Key="SliderTrackDecreaseDisabledBackgroundThemeBrush" Color="#1C000000" />
<SolidColorBrush x:Key="SliderTrackDecreasePointerOverBackgroundThemeBrush" Color="#FF5F37BE" />
<SolidColorBrush x:Key="SliderTrackDecreasePressedBackgroundThemeBrush" Color="#FF7241E4" />
<SolidColorBrush x:Key="SliderTrackDisabledBackgroundThemeBrush" Color="#1A000000" />
<SolidColorBrush x:Key="SliderTrackPointerOverBackgroundThemeBrush" Color="#26000000" />
<SolidColorBrush x:Key="SliderTrackPressedBackgroundThemeBrush" Color="#33000000" />
<SolidColorBrush x:Key="SliderHeaderForegroundThemeBrush" Color="#FF000000" />
<!-- Resources for ToolTip.xaml -->
<x:Double x:Key="ToolTipContentThemeFontSize">12</x:Double>
<Thickness x:Key="ToolTipBorderThemeThickness">1</Thickness>
<StaticResource x:Key="ToolTipForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ToolTipBackground" ResourceKey="SystemControlBackgroundChromeMediumLowBrush" />
<StaticResource x:Key="ToolTipBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
<SolidColorBrush x:Key="ToolTipBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ToolTipBorderThemeBrush" Color="#FF808080" />
<SolidColorBrush x:Key="ToolTipForegroundThemeBrush" Color="#FF666666" />
<Thickness x:Key="ToolTipBorderThemePadding">8,5,8,7</Thickness>
</Style.Resources>
</Style>

1
src/Avalonia.Themes.Fluent/Accents/FluentDark.xaml

@ -5,4 +5,5 @@
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Accents.Base.xaml?assembly=Avalonia.Themes.Fluent" />
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Accents.FluentBaseDark.xaml?assembly=Avalonia.Themes.Fluent" />
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Accents.FluentControlResourcesDark.xaml?assembly=Avalonia.Themes.Fluent" />
<StyleInclude Source="resm:Avalonia.Themes.Fluent.FluentTheme.xaml?assembly=Avalonia.Themes.Fluent" />
</Styles>

1
src/Avalonia.Themes.Fluent/Accents/FluentLight.xaml

@ -5,4 +5,5 @@
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Accents.Base.xaml?assembly=Avalonia.Themes.Fluent" />
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Accents.FluentBaseLight.xaml?assembly=Avalonia.Themes.Fluent" />
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Accents.FluentControlResourcesLight.xaml?assembly=Avalonia.Themes.Fluent" />
<StyleInclude Source="resm:Avalonia.Themes.Fluent.FluentTheme.xaml?assembly=Avalonia.Themes.Fluent" />
</Styles>

36
src/Avalonia.Themes.Fluent/Button.xaml

@ -24,21 +24,19 @@
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<!--<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />-->
<Setter Property="FocusVisualMargin" Value="-3" />-->
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter
x:Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CornerRadius="{DynamicResource ControlCornerRadius}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
</ContentPresenter>
<ContentPresenter x:Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CornerRadius="{DynamicResource ControlCornerRadius}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</ControlTemplate>
</Setter>
</Style>
@ -46,19 +44,19 @@
<!-- PointerOverState -->
<Style Selector="Button:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
</Style>
<Style Selector="Button:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
</Style>
<Style Selector="Button:disabled">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
</Style>
@ -70,19 +68,19 @@
<Style Selector="Button.accent:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPointerOver}"/>
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource AccentButtonForegroundPointerOver}" />
</Style>
<Style Selector="Button.accent:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPressed}"/>
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource AccentButtonForegroundPressed}" />
</Style>
<Style Selector="Button.accent:disabled">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushDisabled}"/>
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource AccentButtonForegroundDisabled}" />
</Style>
</Styles>

15
src/Avalonia.Themes.Fluent/Calendar.xaml

@ -5,13 +5,14 @@
// All other rights reserved.
-->
<Styles xmlns="https://github.com/avaloniaui">
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="Calendar">
<!--<Setter Property="Focusable" Value="False" />-->
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}" />
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}" />
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" />
<Setter Property="HeaderBackground" Value="{DynamicResource ThemeAccentBrush2}" />
<Setter Property="Foreground" Value="{DynamicResource CalendarViewForeground}" />
<Setter Property="Background" Value="{DynamicResource CalendarViewBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<ControlTemplate>
<StackPanel Name="Root"
@ -28,4 +29,4 @@
</ControlTemplate>
</Setter>
</Style>
</Styles>
</Styles>

138
src/Avalonia.Themes.Fluent/CalendarButton.xaml

@ -7,75 +7,115 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="CalendarButton">
<Setter Property="Foreground" Value="{DynamicResource ThemeBorderHighBrush}" />
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}" />
<Setter Property="FontSize" Value="{DynamicResource FontSizeSmall}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="MinWidth" Value="37" />
<Setter Property="MinHeight" Value="38" />
<Setter Property="Focusable" Value="False"/>
<Setter Property="ClickMode" Value="Release"/>
<Setter Property="MinWidth" Value="40"/>
<Setter Property="MinHeight" Value="40"/>
<Setter Property="Margin" Value="1"/>
<Setter Property="Padding" Value="0,0,0,4"/>
<!--These are actually set on the CalendarView in WinUI-->
<Setter Property="Foreground" Value="{DynamicResource CalendarViewCalendarItemForeground}"/>
<Setter Property="Background" Value="{DynamicResource CalendarViewCalendarItemRevealBackground}"/>
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewCalendarItemRevealBorderBrush}"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="ClipToBounds" Value="False"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<ControlTemplate>
<Grid>
<Panel>
<!-- To mimic WinUI SystemFocusVisual, Focus visual is drawn outside the bounds of the item -->
<Border Name="Root" Background="{TemplateBinding Background}"
BorderThickness="0" ClipToBounds="True">
<Rectangle Name="SelectedBackground"
Opacity="0.75"
Fill="{TemplateBinding Background}"/>
<ContentControl Name="Content"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
FontSize="{TemplateBinding FontSize}"
Margin="{TemplateBinding Padding}"/>
<Rectangle Name="Background"
Opacity="0.5"
Fill="{TemplateBinding Background}"/>
</Border>
<!--Focusable="False"-->
<ContentControl Name="Content"
Foreground="{TemplateBinding Foreground}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
FontSize="{TemplateBinding FontSize}"
Margin="1,0,1,1"/>
<!-- Drawn Border should render on top of background to preserve the 1px
margin between items-->
<Border Name="Border"
BorderThickness="2"
BorderBrush="{TemplateBinding BorderBrush}"/>
<Rectangle Name="FocusVisual"
StrokeThickness="1"
Stroke="{DynamicResource HighlightBrush}"
IsHitTestVisible="False"/>
</Grid>
<!--Removed for now...WinUI doesn't have selection follow focus, and only uses
focus visual w/ keyboard focus
<Border Name="FocusVisual" BorderThickness="2"
BorderBrush="{DynamicResource SystemControlHighlightBaseHighBrush}"
IsHitTestVisible="False"
Margin="-2" CornerRadius="{DynamicResource ControlCornerRadius}"/>-->
</Panel>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="CalendarButton /template/ Rectangle#Background">
<!--<Style Selector="CalendarButton /template/ Border#FocusVisual">
<Setter Property="IsVisible" Value="False"/>
</Style>-->
<Style Selector="CalendarButton:pointerover /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewHoverBorderBrush}"/>
</Style>
<Style Selector="CalendarButton:pointerover /template/ Rectangle#Background">
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="CalendarButton:pressed /template/ Rectangle#Background">
<Setter Property="IsVisible" Value="True"/>
<Style Selector="CalendarButton:pressed /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewPressedBorderBrush}"/>
</Style>
<Style Selector="CalendarButton /template/ Rectangle#SelectedBackground">
<Setter Property="IsVisible" Value="False"/>
<!-- Adjusted :selected to look like :today from DayItem -->
<Style Selector="CalendarButton:selected /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource SystemAccentBrush}"/>
</Style>
<Style Selector="CalendarButton:selected /template/ Rectangle#SelectedBackground">
<Setter Property="IsVisible" Value="True"/>
<Style Selector="CalendarButton:selected /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewSelectedBorderBrush}"/>
</Style>
<Style Selector="CalendarButton:selected:pointerover /template/ Border#Root">
<Setter Property="Background">
<SolidColorBrush Color="{DynamicResource SystemAccentColor}"/>
</Setter>
</Style>
<Style Selector="CalendarButton:selected:pointerover /template/ Border#Border">
<Setter Property="BorderBrush">
<SolidColorBrush Color="{DynamicResource SystemAccentColorDark1}"/>
</Setter>
</Style>
<Style Selector="CalendarButton:selected:pressed /template/ Border#Root">
<Setter Property="Background">
<SolidColorBrush Color="{DynamicResource SystemAccentColor}"/>
</Setter>
</Style>
<Style Selector="CalendarButton:pressed /template/ Border#Border">
<Setter Property="BorderBrush">
<SolidColorBrush Color="{DynamicResource SystemAccentColorDark2}"/>
</Setter>
</Style>
<Style Selector="CalendarButton:selected /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource CalendarViewTodayForeground}"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
<Style Selector="CalendarButton /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<!-- WinUI calls this OutOfFocus -->
<Style Selector="CalendarButton:inactive /template/ Border#Root">
<!-- These are probably set in code, but consistent -->
<Setter Property="Background" Value="{DynamicResource CalendarViewOutOfScopeBackground}"/>
</Style>
<Style Selector="CalendarButton:inactive /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundLowBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource CalendarViewOutOfScopeForeground}"/>
</Style>
<Style Selector="CalendarButton /template/ Rectangle#FocusVisual">
<Setter Property="IsVisible" Value="False"/>
<Style Selector="CalendarButton:blackout /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource CalendarViewBlackoutForeground}"/>
</Style>
<Style Selector="CalendarButton:btnfocused /template/ Rectangle#FocusVisual">
<Setter Property="IsVisible" Value="True"/>
<!--<Style Selector="CalendarButton:dayfocused /template/ Border#FocusVisual">
<Setter Property="IsVisible" Value="True"/>
</Style>-->
<Style Selector="CalendarDayButton:disabled /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource CalendarViewWeekDayForegroundDisabled}"/>
</Style>
</Styles>

4
src/Avalonia.Themes.Default/DatePicker.xaml → src/Avalonia.Themes.Fluent/CalendarDatePicker.xaml

@ -8,7 +8,7 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style Selector="DatePicker">
<Style Selector="CalendarDatePicker">
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
@ -119,7 +119,7 @@
</Setter>
</Style>
<Style Selector="DatePicker:focus /template/ TextBox#PART_TextBox">
<Style Selector="CalendarDatePicker:focus /template/ TextBox#PART_TextBox">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}"/>
</Style>

164
src/Avalonia.Themes.Fluent/CalendarDayButton.xaml

@ -7,110 +7,110 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="CalendarDayButton">
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}" />
<Setter Property="FontSize" Value="{DynamicResource FontSizeSmall}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="MinWidth" Value="5" />
<Setter Property="MinHeight" Value="5" />
<Setter Property="Focusable" Value="False"/>
<Setter Property="ClickMode" Value="Release"/>
<Setter Property="MinWidth" Value="40"/>
<Setter Property="MinHeight" Value="40"/>
<Setter Property="Margin" Value="1"/>
<Setter Property="Padding" Value="0,0,0,4"/>
<!--These are actually set on the CalendarView in WinUI-->
<Setter Property="Foreground" Value="{DynamicResource CalendarViewCalendarItemForeground}"/>
<Setter Property="Background" Value="{DynamicResource CalendarViewCalendarItemRevealBackground}"/>
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewCalendarItemRevealBorderBrush}"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="ClipToBounds" Value="False"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<ControlTemplate>
<Panel Background="Transparent">
<Rectangle Name="TodayBackground"
Fill="{DynamicResource HighlightBrush}"/>
<Rectangle Name="SelectedBackground"
Opacity="0.75"
Fill="{TemplateBinding Background}"/>
<Rectangle Name="Background"
Opacity="0.5"
Fill="{TemplateBinding Background}"/>
<ContentControl Name="Content"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
FontSize="{TemplateBinding FontSize}"
Margin="5,1,5,1"/>
<Path Name="BlackoutVisual"
Margin="3"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
RenderTransformOrigin="0.5,0.5"
Fill="{DynamicResource ThemeForegroundBrush}"
Stretch="Fill"
Data="M8.1772461,11.029181 L10.433105,11.029181 L11.700684,12.801641 L12.973633,11.029181 L15.191895,11.029181 L12.844727,13.999395 L15.21875,17.060919 L12.962891,17.060919 L11.673828,15.256231 L10.352539,17.060919 L8.1396484,17.060919 L10.519043,14.042364 z" />
<Rectangle Name="FocusVisual"
StrokeThickness="1"
Stroke="{DynamicResource HighlightBrush}"
IsHitTestVisible="False"/>
<Panel>
<!-- To mimic WinUI SystemFocusVisual, Focus visual is drawn outside the bounds of the item -->
<Border Name="Root" Background="{TemplateBinding Background}"
BorderThickness="0" ClipToBounds="True">
<ContentControl Name="Content"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
FontSize="{TemplateBinding FontSize}"
Margin="{TemplateBinding Padding}"/>
</Border>
<!-- Drawn Border should render on top of background to preserve the 1px
margin between items-->
<Border Name="Border"
BorderThickness="2"
BorderBrush="{TemplateBinding BorderBrush}"/>
<!--Removed for now...WinUI doesn't have selection follow focus, and only uses
focus visual w/ keyboard focus
<Border Name="FocusVisual" BorderThickness="2"
BorderBrush="{DynamicResource SystemControlHighlightBaseHighBrush}"
IsHitTestVisible="False"
Margin="-2" CornerRadius="2"/>-->
</Panel>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="CalendarDayButton /template/ Rectangle#Background">
<!--<Style Selector="CalendarDayButton /template/ Border#FocusVisual">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="CalendarDayButton:pointerover /template/ Rectangle#Background">
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="CalendarDayButton:pressed /template/ Rectangle#Background">
<Setter Property="IsVisible" Value="True"/>
</Style>
</Style>-->
<Style Selector="CalendarDayButton /template/ Rectangle#SelectedBackground">
<Setter Property="IsVisible" Value="False"/>
<Style Selector="CalendarDayButton:pointerover /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewHoverBorderBrush}"/>
</Style>
<Style Selector="CalendarDayButton:selected /template/ Rectangle#SelectedBackground">
<Setter Property="IsVisible" Value="True"/>
<Style Selector="CalendarDayButton:pressed /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewPressedBorderBrush}"/>
</Style>
<Style Selector="CalendarDayButton /template/ ContentControl#Content">
<Setter Property="Opacity" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Style Selector="CalendarDayButton:selected /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewSelectedBorderBrush}"/>
</Style>
<Style Selector="CalendarDayButton:disabled /template/ Rectangle#Background">
<Setter Property="IsVisible" Value="False"/>
<Style Selector="CalendarDayButton:selected:pointerover /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewSelectedHoverBorderBrush}"/>
</Style>
<Style Selector="CalendarDayButton:disabled /template/ ContentControl#Content">
<Setter Property="Opacity" Value="0.3"/>
<Style Selector="CalendarDayButton:selected:pressed /template/ Border#Border">
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewSelectedPressedBorderBrush}"/>
</Style>
<Style Selector="CalendarDayButton /template/ Rectangle#FocusVisual">
<Setter Property="IsVisible" Value="False"/>
<Style Selector="CalendarDayButton:today /template/ Border#Root">
<!-- These are probably set in code, but consistent -->
<Setter Property="Background">
<SolidColorBrush Color="{DynamicResource SystemAccentColor}"/>
</Setter>
</Style>
<Style Selector="CalendarDayButton:dayfocused /template/ Rectangle#FocusVisual">
<Setter Property="IsVisible" Value="True"/>
<Style Selector="CalendarDayButton:today:pointerover /template/ Border#Border">
<Setter Property="BorderBrush">
<SolidColorBrush Color="{DynamicResource SystemAccentColorDark1}"/>
</Setter>
</Style>
<Style Selector="CalendarDayButton /template/ Rectangle#TodayBackground">
<Setter Property="IsVisible" Value="False"/>
<Style Selector="CalendarDayButton:today:pressed /template/ Border#Border">
<Setter Property="BorderBrush">
<SolidColorBrush Color="{DynamicResource SystemAccentColorDark2}"/>
</Setter>
</Style>
<Style Selector="CalendarDayButton:today /template/ Rectangle#TodayBackground">
<Setter Property="IsVisible" Value="True"/>
<Style Selector="CalendarDayButton:today /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource CalendarViewTodayForeground}"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
<Style Selector="CalendarDayButton:inactive /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundLowBrush}"/>
<!-- WinUI calls this OutOfFocus -->
<Style Selector="CalendarDayButton:inactive /template/ Border#Root">
<Setter Property="Background" Value="{DynamicResource CalendarViewOutOfScopeBackground}"/>
</Style>
<Style Selector="CalendarDayButton:today /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource ThemeControlLowBrush}"/>
<Style Selector="CalendarDayButton:inactive /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource CalendarViewOutOfScopeForeground}"/>
</Style>
<Style Selector="CalendarDayButton /template/ Path#BlackoutVisual">
<Setter Property="Opacity" Value="0"/>
<Style Selector="CalendarDayButton:blackout /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource CalendarViewBlackoutForeground}"/>
</Style>
<Style Selector="CalendarDayButton:blackout /template/ Path#BlackoutVisual">
<Setter Property="Opacity" Value="0.3"/>
</Style>
<!--<Style Selector="CalendarDayButton:dayfocused /template/ Border#FocusVisual">
<Setter Property="IsVisible" Value="True"/>
</Style>-->
<Style Selector="CalendarDayButton:disabled /template/ ContentControl#Content">
<Setter Property="Foreground" Value="{DynamicResource CalendarViewWeekDayForegroundDisabled}"/>
</Style>
</Styles>

275
src/Avalonia.Themes.Fluent/CalendarItem.xaml

@ -8,176 +8,127 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="CalendarItem">
<Setter Property="Template">
<ControlTemplate>
<Panel>
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
Margin="0,2,0,2"
CornerRadius="1">
<Border CornerRadius="1"
BorderBrush="{DynamicResource ThemeBackgroundBrush}"
BorderThickness="2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.Styles>
<Style Selector="Button.CalendarHeader">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
<Style Selector="Button.CalendarHeader:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button.CalendarNavigation">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="28"/>
</Style>
<Style Selector="Button.CalendarNavigation > Path">
<Setter Property="Fill" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="Button.CalendarNavigation:pointerover > Path">
<Setter Property="Fill" Value="{DynamicResource HighlightBrush}"/>
</Style>
<Style Selector="Button#HeaderButton:pointerover">
<Setter Property="Foreground" Value="{DynamicResource HighlightBrush}"/>
</Style>
</Grid.Styles>
<Rectangle Grid.ColumnSpan="3"
Fill="{TemplateBinding HeaderBackground}"
Stretch="Fill"
VerticalAlignment="Top"
Height="22"/>
<Button Name="PreviousButton"
Classes="CalendarHeader CalendarNavigation"
IsVisible="False"
HorizontalAlignment="Left">
<Path Margin="14,-6,0,0"
Height="10"
Width="6"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Stretch="Fill"
Data="M288.75,232.25 L288.75,240.625 L283,236.625 z" />
</Button>
<Button Name="HeaderButton"
Classes="CalendarHeader"
Grid.Column="1"
FontWeight="Bold"
FontSize="10.5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Padding="1,5,1,9"/>
<Button Name="NextButton"
Classes="CalendarHeader CalendarNavigation"
Grid.Column="2"
IsVisible="False"
HorizontalAlignment="Right" >
<Path Margin="0,-6,14,0"
Height="10"
Width="6"
Stretch="Fill"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Data="M282.875,231.875 L282.875,240.375 L288.625,236 z" />
</Button>
<Grid Name="MonthView"
Grid.Row="1"
Grid.ColumnSpan="3"
IsVisible="False"
Margin="6,-1,6,6">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
<Grid Name="YearView"
Grid.Row="1"
Grid.ColumnSpan="3"
IsVisible="False"
Margin="6,-3,7,6">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
</Grid>
</Border>
</Border>
<Rectangle Name="DisabledVisual"
Stretch="Fill"
Fill="{DynamicResource ThemeControlLowBrush}"
Opacity="{DynamicResource ThemeDisabledOpacity}"
Margin="0,2,0,2" />
</Panel>
</ControlTemplate>
</Setter>
<Setter Property="DayTitleTemplate">
<Template>
<TextBlock FontWeight="Bold"
FontSize="9.5"
Margin="0,4,0,4"
<TextBlock Text="{Binding}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding}" />
FontSize="12"/>
</Template>
</Setter>
<Setter Property="Template">
<ControlTemplate>
<Border BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="{DynamicResource ControlCornerRadius}">
<Border.Styles>
<Style Selector="Button.CalendarHeader">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="FontSize" Value="20" />
<Setter Property="Background" Value="{DynamicResource CalendarViewNavigationButtonBackground}"/>
<Setter Property="Template">
<ControlTemplate>
<!-- HCA was changed here to ensure nav arrows display correctly -->
<ContentPresenter Name="Text" Background="{TemplateBinding Background}"
BorderBrush="{DynamicResource CalendarViewNavigationButtonBorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</ControlTemplate>
</Setter>
</Style>
<Style Selector="Button.CalendarNavigation > Path">
<Setter Property="Stroke" Value="{DynamicResource CalendarViewForeground}"/>
</Style>
<Style Selector="Button.CalendarNavigation:pointerover > Path">
<Setter Property="Stroke" Value="{DynamicResource CalendarViewNavigationButtonForegroundPointerOver}"/>
</Style>
<Style Selector="Button.CalendarNavigation:pressed > Path">
<Setter Property="Stroke" Value="{DynamicResource CalendarViewNavigationButtonForegroundPressed}"/>
</Style>
<Style Selector="Button.CalendarHeader:pointerover /template/ ContentPresenter#Text">
<Setter Property="BorderBrush" Value="{DynamicResource CalendarViewNavigationButtonBorderBrushPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource CalendarViewNavigationButtonForegroundPointerOver}"/>
<!-- Prevent base button template:pointerover from overriding background here -->
<Setter Property="Background" Value="{DynamicResource CalendarViewNavigationButtonBackground}"/>
</Style>
<Style Selector="Button.CalendarHeader:pressed /template/ ContentPresenter#Text">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource CalendarViewNavigationButtonForegroundPressed}"/>
<!-- Prevent base button template:pointerover from overriding background here -->
<Setter Property="Background" Value="{DynamicResource CalendarViewNavigationButtonBackground}"/>
</Style>
<Style Selector="Button.CalendarHeader:disabled /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource CalendarViewWeekDayForegroundDisabled}"/>
</Style>
</Border.Styles>
<!-- To keep calendar from resizing when switching DisplayMode
In WinUI Min-Width from TemplateSettings
basically...MinWidth of DayItem = 40, 40 * 7 = 280 + margins/padding = ~294
Viewport height is set from # of rows displayed (2-8) in Month mode, = ~290 for 6 weeks (+ day names)
-->
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" RowDefinitions="40,*" MinWidth="294">
<Grid ColumnDefinitions="5*,*,*">
<Button Name="HeaderButton" Classes="CalendarHeader" Foreground="{TemplateBinding Foreground}" Padding="12,0,0,0" HorizontalContentAlignment="Left" />
<Button Name="PreviousButton" Grid.Column="1" Classes="CalendarHeader CalendarNavigation" Foreground="{TemplateBinding Foreground}" Padding="1" HorizontalContentAlignment="Left">
<!--Path mimics Segoe MDL2 Assets font glyph used in WinUI-->
<Path StrokeThickness="1.5" Data="M 0,9 L 9,0 L 18,9" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Button>
<Button Name="NextButton" Grid.Column="2" Classes="CalendarHeader CalendarNavigation" Foreground="{TemplateBinding Foreground}" Padding="1" HorizontalContentAlignment="Left">
<!--Path mimics Segoe MDL2 Assets font glyph used in WinUI-->
<Path StrokeThickness="1.5" Data="M 0,0 L 9,9 L 18,0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Button>
</Grid>
<Border Name="BackgroundLayer" Background="{TemplateBinding BorderBrush}" Grid.Row="1" />
<Grid Name="MonthView" Grid.Row="1" IsVisible="False" MinHeight="290" >
<Grid.RowDefinitions>
<!--This should always be the week day names??-->
<RowDefinition Height="38" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
<Grid Name="YearView" MinHeight="290"
Grid.Row="1" IsVisible="False">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="CalendarItem /template/ Rectangle#DisabledVisual">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="CalendarItem:calendardisabled /template/ Rectangle#DisabledVisual">
<Setter Property="IsVisible" Value="True"/>
<!-- BackgroundLayer shouldn't show in the week day names row-->
<Style Selector="Calendar[DisplayMode=Month] CalendarItem /template/ Border#BackgroundLayer">
<Setter Property="Margin" Value="0,38,0,0"/>
</Style>
</Styles>

2
src/Avalonia.Themes.Fluent/ComboBox.xaml

@ -21,7 +21,7 @@
<Thickness x:Key="ComboBoxPadding">12,5,0,7</Thickness>
<Thickness x:Key="ComboBoxEditableTextPadding">11,5,32,6</Thickness>
<Thickness x:Key="ComboBoxMinHeight">32</Thickness>
<x:Double x:Key="ComboBoxMinHeight">32</x:Double>
</Styles.Resources>
<Style Selector="ComboBox">
<Setter Property="Padding" Value="{DynamicResource ComboBoxPadding}" />

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

@ -45,7 +45,7 @@
<StyleInclude Source="resm:Avalonia.Themes.Fluent.CalendarDayButton.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.CalendarItem.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.Calendar.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.DatePicker.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.CalendarDatePicker.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.ButtonSpinner.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.NumericUpDown.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.AutoCompleteBox.xaml?assembly=Avalonia.Themes.Fluent"/>

100
src/Avalonia.Themes.Fluent/RepeatButton.xaml

@ -1,40 +1,62 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="RepeatButton">
<Setter Property="Background"
Value="{DynamicResource ThemeControlMidBrush}" />
<Setter Property="BorderBrush"
Value="{DynamicResource ThemeBorderLowBrush}" />
<Setter Property="BorderThickness"
Value="{DynamicResource ThemeBorderThickness}" />
<Setter Property="Foreground"
Value="{DynamicResource ThemeForegroundBrush}" />
<Setter Property="HorizontalContentAlignment"
Value="Center" />
<Setter Property="VerticalContentAlignment"
Value="Center" />
<Setter Property="Padding"
Value="4" />
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="RepeatButton:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush"
Value="{DynamicResource ThemeBorderMidBrush}" />
</Style>
<Style Selector="RepeatButton:disabled">
<Setter Property="Opacity"
Value="{DynamicResource ThemeDisabledOpacity}" />
</Style>
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<StackPanel Spacing="20">
<RepeatButton Content="Click Me!" />
</StackPanel>
</Border>
</Design.PreviewWith>
<Styles.Resources>
<Thickness x:Key="ButtonPadding">8,5,8,6</Thickness>
</Styles.Resources>
<Style Selector="RepeatButton">
<Setter Property="Background" Value="{DynamicResource RepeatButtonBackground}" />
<!--<Setter Property="BackgroundSizing" Value="OuterBorderEdge" />-->
<Setter Property="Foreground" Value="{DynamicResource RepeatButtonForeground}" />
<Setter Property="BorderBrush" Value="{DynamicResource RepeatButtonBorderBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource ButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<!--<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />-->
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter x:Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</ControlTemplate>
</Setter>
</Style>
<Style Selector="RepeatButton /template/ ContentPresenter">
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
</Style>
<Style Selector="RepeatButton:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource RepeatButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource RepeatButtonBorderBrushPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource RepeatButtonForegroundPointerOver}" />
</Style>
<Style Selector="RepeatButton:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource RepeatButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource RepeatButtonBorderBrushPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource RepeatButtonForegroundPressed}" />
</Style>
<Style Selector="RepeatButton:disabled">
<Setter Property="Background" Value="{DynamicResource RepeatButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource RepeatButtonBorderBrushDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource RepeatButtonForegroundDisabled}" />
</Style>
</Styles>

323
src/Avalonia.Themes.Fluent/Slider.xaml

@ -1,93 +1,264 @@
<Styles xmlns="https://github.com/avaloniaui">
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Margin="20" Width="200" Height="200">
<DockPanel LastChildFill="True">
<StackPanel Spacing="10" DockPanel.Dock="Top">
<Slider Value="50" />
<Slider IsEnabled="False" Value="50" />
</StackPanel>
<StackPanel Spacing="10" Orientation="Horizontal">
<Slider Value="50" Orientation="Vertical" />
<Slider IsEnabled="False" Orientation="Vertical" Value="50" />
</StackPanel>
</DockPanel>
</Border>
</Design.PreviewWith>
<Styles.Resources>
<Thickness x:Key="SliderTopHeaderMargin">0,0,0,4</Thickness>
<GridLength x:Key="SliderPreContentMargin">15</GridLength>
<GridLength x:Key="SliderPostContentMargin">15</GridLength>
<x:Double x:Key="SliderHorizontalHeight">32</x:Double>
<x:Double x:Key="SliderVerticalWidth">32</x:Double>
<CornerRadius x:Key="SliderThumbCornerRadius">10</CornerRadius>
<x:Double x:Key="SliderHorizontalThumbWidth">20</x:Double>
<x:Double x:Key="SliderHorizontalThumbHeight">20</x:Double>
<x:Double x:Key="SliderVerticalThumbWidth">20</x:Double>
<x:Double x:Key="SliderVerticalThumbHeight">20</x:Double>
</Styles.Resources>
<Style Selector="Thumb.SliderThumbStyle">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{DynamicResource SliderThumbCornerRadius}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style Selector="Slider:horizontal">
<Setter Property="MinWidth" Value="40"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="Background" Value="{DynamicResource SliderTrackFill}" />
<Setter Property="BorderThickness" Value="{DynamicResource SliderBorderThemeThickness}" />
<Setter Property="Foreground" Value="{DynamicResource SliderTrackValueFill}" />
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="Template">
<ControlTemplate>
<Grid Name="grid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Name="TrackBackground" Grid.Row="1" Height="4" Margin="6,0" VerticalAlignment="Center"/>
<Track Name="PART_Track" Grid.Row="1" Orientation="Horizontal">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton"
Classes="repeattrack" />
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton"
Classes="repeattrack" />
</Track.IncreaseButton>
<Thumb Name="thumb" MinWidth="20" MinHeight="20">
<Thumb.Template>
<ControlTemplate>
<Grid>
<Ellipse Width="12" Height="12" Fill="{DynamicResource ThemeAccentBrush}"/>
</Grid>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track>
</Grid>
<Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
<ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}"
Margin="{DynamicResource SliderTopHeaderMargin}" />
<Grid x:Name="SliderContainer" Grid.Row="1">
<Grid.Styles>
<Style Selector="TickBar">
<Setter Property="ReservedSpace" Value="{Binding #PART_Track.Thumb.Bounds}" />
</Style>
</Grid.Styles>
<Grid x:Name="HorizontalTemplate" ColumnDefinitions="Auto,Auto,*" MinHeight="{DynamicResource SliderHorizontalHeight}">
<Grid.RowDefinitions>
<RowDefinition Height="{DynamicResource SliderPreContentMargin}" />
<RowDefinition Height="Auto" />
<RowDefinition Height="{DynamicResource SliderPostContentMargin}" />
</Grid.RowDefinitions>
<TickBar Name="TopTickBar" Placement="Top" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Bottom" Margin="0,0,0,4" Grid.ColumnSpan="3" />
<!-- <TickBar Name="HorizontalInlineTickBar" Placement="Top" Fill="{DynamicResource SliderInlineTickBarFill}" Height="{DynamicResource SliderTrackThemeHeight}" Grid.Row="1" Grid.ColumnSpan="3" /> -->
<TickBar Name="BottomTickBar" Placement="Bottom" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Top" Margin="0,4,0,0" Grid.Row="2" Grid.ColumnSpan="3" />
<Track Name="PART_Track" Grid.Row="1" Grid.ColumnSpan="3" Orientation="Horizontal">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Height="{DynamicResource SliderTrackThemeHeight}" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Height="{DynamicResource SliderTrackThemeHeight}" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.IncreaseButton>
<Thumb Classes="SliderThumbStyle" Name="thumb" Margin="0" Padding="0" DataContext="{TemplateBinding Value}" Height="{DynamicResource SliderHorizontalThumbHeight}" Width="{DynamicResource SliderHorizontalThumbWidth}" />
</Track>
</Grid>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="Slider:vertical">
<Setter Property="MinWidth" Value="20"/>
<Setter Property="MinHeight" Value="40"/>
<Setter Property="Background" Value="{DynamicResource SliderTrackFill}" />
<Setter Property="BorderThickness" Value="{DynamicResource SliderBorderThemeThickness}" />
<Setter Property="Foreground" Value="{DynamicResource SliderTrackValueFill}" />
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="Template">
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" MinWidth="26"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Name="TrackBackground" Grid.Column="1" Width="4" Margin="0,6" HorizontalAlignment="Center"/>
<Track Name="PART_Track" Grid.Column="1" Orientation="Vertical" IsDirectionReversed="True">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton"
Classes="repeattrack" />
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton"
Classes="repeattrack" />
</Track.IncreaseButton>
<Thumb Name="thumb" MinWidth="20" MinHeight="20">
<Thumb.Template>
<ControlTemplate>
<Grid>
<Ellipse Width="12" Height="12" Fill="{DynamicResource ThemeAccentBrush}"/>
</Grid>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track>
</Grid>
<Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
<ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}"
Margin="{DynamicResource SliderTopHeaderMargin}" />
<Grid x:Name="SliderContainer" Grid.Row="1">
<Grid.Styles>
<Style Selector="TickBar">
<Setter Property="ReservedSpace" Value="{Binding #PART_Track.Thumb.Bounds}" />
</Style>
</Grid.Styles>
<Grid x:Name="VerticalTemplate" RowDefinitions="*,Auto,Auto" MinWidth="{DynamicResource SliderVerticalWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{DynamicResource SliderPreContentMargin}" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="{DynamicResource SliderPostContentMargin}" />
</Grid.ColumnDefinitions>
<TickBar Name="LeftTickBar" Placement="Left" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Right" Margin="0,0,4,0" Grid.RowSpan="3" />
<!-- <TickBar Name="VerticalInlineTickBar" Placement="Inline" Fill="{DynamicResource SliderInlineTickBarFill}" Width="{DynamicResource SliderTrackThemeHeight}" Grid.Column="1" Grid.RowSpan="3" /> -->
<TickBar Name="RightTickBar" Placement="Right" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Column="2" Grid.RowSpan="3" />
<Track Name="PART_Track" Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="3" Orientation="Vertical">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Width="{DynamicResource SliderTrackThemeHeight}" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Width="{DynamicResource SliderTrackThemeHeight}" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.IncreaseButton>
<Thumb Classes="SliderThumbStyle" Name="SliderThumb" Margin="0" Padding="0" DataContext="{TemplateBinding Value}" Height="{DynamicResource SliderVerticalThumbHeight}" Width="{DynamicResource SliderVerticalThumbWidth}" />
</Track>
</Grid>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="Slider /template/ Track#PART_Track">
<Setter Property="Minimum" Value="{TemplateBinding Minimum}"/>
<Setter Property="Maximum" Value="{TemplateBinding Maximum}"/>
<Setter Property="Value" Value="{TemplateBinding Value, Mode=TwoWay}"/>
<Setter Property="Minimum" Value="{TemplateBinding Minimum}" />
<Setter Property="Maximum" Value="{TemplateBinding Maximum}" />
<Setter Property="Value" Value="{TemplateBinding Value, Mode=TwoWay}" />
</Style>
<Style Selector="Slider /template/ Border#TrackBackground">
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowBrush}"/>
<Style Selector="Slider /template/ TickBar">
<Setter Property="Fill" Value="{DynamicResource SliderTickBarFill}" />
<Setter Property="TickFrequency" Value="{TemplateBinding Slider.TickFrequency}" />
<Setter Property="Orientation" Value="{TemplateBinding Slider.Orientation}" />
<Setter Property="Minimum" Value="{TemplateBinding Slider.Minimum}" />
<Setter Property="Maximum" Value="{TemplateBinding Slider.Maximum}" />
</Style>
<Style Selector="Slider /template/ RepeatButton.repeattrack">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{DynamicResource ThemeBorderLowBrush}"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}" />
</ControlTemplate>
</Setter>
<!-- Normal State -->
<Style Selector="Slider /template/ Thumb.SliderThumbStyle">
<Setter Property="Background" Value="{DynamicResource SliderThumbBackground}" />
</Style>
<Style Selector="Slider /template/ Grid#SliderContainer">
<Setter Property="Background" Value="{DynamicResource SliderContainerBackground}" />
</Style>
<Style Selector="Slider /template/ TickBar">
<Setter Property="IsVisible" Value="False" />
</Style>
<!-- TickBar Placement States -->
<Style Selector="Slider[TickPlacement=TopLeft] /template/ TickBar#LeftTickBar, Slider[TickPlacement=Outside] /template/ TickBar#LeftTickBar">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="Slider[TickPlacement=TopLeft] /template/ TickBar#TopTickBar, Slider[TickPlacement=Outside] /template/ TickBar#TopTickBar">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="Slider[TickPlacement=BottomRight] /template/ TickBar#BottomTickBar, Slider[TickPlacement=Outside] /template/ TickBar#BottomTickBar">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="Slider[TickPlacement=BottomRight] /template/ TickBar#RightTickBar, Slider[TickPlacement=Outside] /template/ TickBar#RightTickBar">
<Setter Property="IsVisible" Value="True" />
</Style>
<!-- Disabled State -->
<Style Selector="Slider:disabled /template/ ContentPresenter#HeaderContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SliderHeaderForegroundDisabled}" />
</Style>
<Style Selector="Slider:disabled /template/ RepeatButton#PART_DecreaseButton">
<Setter Property="Background" Value="{DynamicResource SliderTrackValueFillDisabled}" />
</Style>
<Style Selector="Slider:disabled /template/ RepeatButton#PART_IncreaseButton">
<Setter Property="Background" Value="{DynamicResource SliderTrackFillDisabled}" />
</Style>
<Style Selector="Slider:disabled /template/ Thumb.SliderThumbStyle">
<Setter Property="Background" Value="{DynamicResource SliderThumbBackgroundDisabled}" />
</Style>
<Style Selector="Slider:disabled /template/ TickBar">
<Setter Property="Fill" Value="{DynamicResource SliderTickBarFillDisabled}" />
</Style>
<Style Selector="Slider:pointerover /template/ Grid#SliderContainer">
<Setter Property="Background" Value="{DynamicResource SliderContainerBackgroundDisabled}" />
</Style>
<!-- PointerOver State -->
<Style Selector="Slider:pointerover /template/ RepeatButton#PART_IncreaseButton">
<Setter Property="Background" Value="{DynamicResource SliderTrackFillPointerOver}" />
</Style>
<Style Selector="Slider:pointerover /template/ Thumb.SliderThumbStyle">
<Setter Property="Background" Value="{DynamicResource SliderThumbBackgroundPointerOver}" />
</Style>
<Style Selector="Slider:pointerover /template/ Grid#SliderContainer">
<Setter Property="Background" Value="{DynamicResource SliderContainerBackgroundPointerOver}" />
</Style>
<Style Selector="Slider:pointerover /template/ RepeatButton#PART_DecreaseButton">
<Setter Property="Background" Value="{DynamicResource SliderTrackValueFillPointerOver}" />
</Style>
<!-- Pressed State -->
<Style Selector="Slider:pressed /template/ RepeatButton#PART_IncreaseButton">
<Setter Property="Background" Value="{DynamicResource SliderTrackFillPressed}" />
</Style>
<Style Selector="Slider:pressed /template/ Thumb.SliderThumbStyle">
<Setter Property="Background" Value="{DynamicResource SliderThumbBackgroundPressed}" />
</Style>
<Style Selector="Slider:pointerover /template/ Grid#SliderContainer">
<Setter Property="Background" Value="{DynamicResource SliderContainerBackgroundPressed}" />
</Style>
<Style Selector="Slider:pointerover /template/ RepeatButton#PART_DecreaseButton">
<Setter Property="Background" Value="{DynamicResource SliderTrackValueFillPressed}" />
</Style>
<Style Selector="Slider:disabled /template/ Grid#grid">
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" />
</Style>
</Styles>

113
src/Avalonia.Themes.Fluent/ToggleButton.xaml

@ -1,38 +1,109 @@
<Styles xmlns="https://github.com/avaloniaui">
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<StackPanel Spacing="20">
<ToggleButton Content="Click Me!" />
<ToggleButton Content="Disabled" IsEnabled="False" />
<ToggleButton Content="Three state" IsThreeState="True" />
</StackPanel>
</Border>
</Design.PreviewWith>
<Styles.Resources>
<Thickness x:Key="ButtonPadding">8,5,8,6</Thickness>
</Styles.Resources>
<Style Selector="ToggleButton">
<Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackground}" />
<Setter Property="Foreground" Value="{DynamicResource ToggleButtonForeground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource ToggleButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="{DynamicResource ButtonPadding}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter"
<ContentPresenter x:Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CornerRadius="{DynamicResource ControlCornerRadius}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Padding="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ToggleButton:checked /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
</Style>
<!-- PointerOverState -->
<Style Selector="ToggleButton:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundPointerOver}" />
</Style>
<Style Selector="ToggleButton:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighBrush}"/>
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundPressed}" />
</Style>
<Style Selector="ToggleButton:disabled /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundDisabled}" />
</Style>
<Style Selector="ToggleButton:checked /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundChecked}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushChecked}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundChecked}" />
</Style>
<Style Selector="ToggleButton:checked:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushCheckedPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundCheckedPointerOver}" />
</Style>
<Style Selector="ToggleButton:checked:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushCheckedPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundCheckedPressed}" />
</Style>
<Style Selector="ToggleButton:checked:disabled /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundCheckedDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushCheckedDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundCheckedDisabled}" />
</Style>
<Style Selector="ToggleButton:indeterminate /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundIndeterminate}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushIndeterminate}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundIndeterminate}" />
</Style>
<Style Selector="ToggleButton:indeterminate:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundIndeterminatePointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushIndeterminatePointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundIndeterminatePointerOver}" />
</Style>
<Style Selector="ToggleButton:indeterminate:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundIndeterminatePressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushIndeterminatePressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundIndeterminatePressed}" />
</Style>
<Style Selector="ToggleButton:disabled">
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
<Style Selector="ToggleButton:indeterminate:disabled /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ToggleButtonBackgroundIndeterminateDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrushIndeterminateDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForegroundIndeterminateDisabled}" />
</Style>
</Styles>
</Styles>

95
src/Avalonia.Themes.Fluent/ToolTip.xaml

@ -1,17 +1,78 @@
<Style xmlns="https://github.com/avaloniaui" Selector="ToolTip">
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Padding" Value="4,2"/>
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter>
</Style>
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Grid RowDefinitions="Auto,Auto"
ColumnDefinitions="Auto,Auto"
HorizontalAlignment="Center">
<Border Grid.Column="0"
Grid.Row="1"
Background="{DynamicResource ThemeAccentBrush}"
Margin="5"
Padding="50"
ToolTip.Tip="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.">
<TextBlock>Hover Here</TextBlock>
</Border>
<CheckBox Grid.Column="1"
Margin="5"
Grid.Row="0"
IsChecked="{Binding ElementName=Border, Path=(ToolTip.IsOpen)}"
Content="ToolTip Open" />
<Border Name="Border"
Grid.Column="1"
Grid.Row="1"
Background="{DynamicResource ThemeAccentBrush}"
Margin="5"
Padding="50"
ToolTip.Placement="Bottom">
<ToolTip.Tip>
<StackPanel>
<TextBlock Classes="h1">ToolTip</TextBlock>
<TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock>
</StackPanel>
</ToolTip.Tip>
<TextBlock>ToolTip bottom placement</TextBlock>
</Border>
</Grid>
</Design.PreviewWith>
<Style Selector="ToolTip">
<Setter Property="Foreground" Value="{DynamicResource ToolTipForeground}" />
<Setter Property="Background" Value="{DynamicResource ToolTipBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ToolTipBorderBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource ToolTipBorderThemeThickness}" />
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{DynamicResource ToolTipContentThemeFontSize}" />
<Setter Property="Padding" Value="{DynamicResource ToolTipBorderThemePadding}" />
<Setter Property="Transitions">
<Transitions>
<DoubleTransition Property="Opacity" Duration="0:0:0.15" />
</Transitions>
</Setter>
<Setter Property="Template">
<ControlTemplate>
<Border Name="PART_LayoutRoot"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
Padding="{TemplateBinding Padding}"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ContentPresenter Name="PART_ContentPresenter"
MaxWidth="320"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ToolTip > TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
<Style Selector="ToolTip">
<Setter Property="Opacity" Value="0" />
</Style>
<Style Selector="ToolTip:open">
<Setter Property="Opacity" Value="1" />
</Style>
</Styles>

5
src/Avalonia.Visuals/Media/DrawingContext.cs

@ -4,6 +4,7 @@ using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.Visuals.Media.Imaging;
namespace Avalonia.Media
@ -154,12 +155,12 @@ namespace Avalonia.Media
return;
}
if (Math.Abs(radiusX) > double.Epsilon)
if (!MathUtilities.IsZero(radiusX))
{
radiusX = Math.Min(radiusX, rect.Width / 2);
}
if (Math.Abs(radiusY) > double.Epsilon)
if (!MathUtilities.IsZero(radiusY))
{
radiusY = Math.Min(radiusY, rect.Height / 2);
}

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

@ -4,6 +4,7 @@ using System.Linq;
using Avalonia.Media.Immutable;
using Avalonia.Media.TextFormatting.Unicode;
using Avalonia.Platform;
using Avalonia.Utilities;
using Avalonia.Utility;
namespace Avalonia.Media.TextFormatting
@ -32,6 +33,7 @@ namespace Avalonia.Media.TextFormatting
/// <param name="textDecorations">The text decorations.</param>
/// <param name="maxWidth">The maximum width.</param>
/// <param name="maxHeight">The maximum height.</param>
/// <param name="maxLines">The maximum number of text lines.</param>
/// <param name="textStyleOverrides">The text style overrides.</param>
public TextLayout(
string text,
@ -44,6 +46,7 @@ namespace Avalonia.Media.TextFormatting
TextDecorationCollection textDecorations = null,
double maxWidth = double.PositiveInfinity,
double maxHeight = double.PositiveInfinity,
int maxLines = 0,
IReadOnlyList<TextStyleRun> textStyleOverrides = null)
{
_text = string.IsNullOrEmpty(text) ?
@ -59,6 +62,8 @@ namespace Avalonia.Media.TextFormatting
MaxHeight = maxHeight;
MaxLines = maxLines;
UpdateLayout();
}
@ -73,6 +78,12 @@ namespace Avalonia.Media.TextFormatting
/// </summary>
public double MaxHeight { get; }
/// <summary>
/// Gets the maximum number of text lines.
/// </summary>
public double MaxLines { get; }
/// <summary>
/// Gets the text lines.
/// </summary>
@ -174,7 +185,7 @@ namespace Avalonia.Media.TextFormatting
/// </summary>
private void UpdateLayout()
{
if (_text.IsEmpty || Math.Abs(MaxWidth) < double.Epsilon || Math.Abs(MaxHeight) < double.Epsilon)
if (_text.IsEmpty || MathUtilities.IsZero(MaxWidth) || MathUtilities.IsZero(MaxHeight))
{
var textLine = CreateEmptyTextLine(0);
@ -192,7 +203,7 @@ namespace Avalonia.Media.TextFormatting
var currentPosition = 0;
while (currentPosition < _text.Length)
while (currentPosition < _text.Length && (MaxLines == 0 || textLines.Count < MaxLines))
{
int length;
@ -222,7 +233,7 @@ namespace Avalonia.Media.TextFormatting
var remainingLength = length;
while (remainingLength > 0)
while (remainingLength > 0 && (MaxLines == 0 || textLines.Count < MaxLines))
{
var textSlice = _text.AsSlice(currentPosition, remainingLength);

35
src/Avalonia.X11/X11Atoms.cs

@ -22,6 +22,7 @@
//
using System;
using System.Collections.Generic;
using System.Linq;
using static Avalonia.X11.XLib;
// ReSharper disable FieldCanBeMadeReadOnly.Global
@ -40,8 +41,9 @@ namespace Avalonia.X11
internal class X11Atoms
{
private readonly IntPtr _display;
// Our atoms
// Our atoms
public readonly IntPtr AnyPropertyType = (IntPtr)0;
public readonly IntPtr XA_PRIMARY = (IntPtr)1;
public readonly IntPtr XA_SECONDARY = (IntPtr)2;
@ -187,10 +189,13 @@ namespace Avalonia.X11
public readonly IntPtr ATOM_PAIR;
public readonly IntPtr MANAGER;
public readonly IntPtr _KDE_NET_WM_BLUR_BEHIND_REGION;
public readonly IntPtr INCR;
private readonly Dictionary<string, IntPtr> _namesToAtoms = new Dictionary<string, IntPtr>();
private readonly Dictionary<IntPtr, string> _atomsToNames = new Dictionary<IntPtr, string>();
public X11Atoms(IntPtr display)
{
_display = display;
// make sure this array stays in sync with the statements below
@ -204,7 +209,33 @@ namespace Avalonia.X11
XInternAtoms(display, atomNames, atomNames.Length, true, atoms);
for (var c = 0; c < fields.Length; c++)
{
_namesToAtoms[fields[c].Name] = atoms[c];
_atomsToNames[atoms[c]] = fields[c].Name;
fields[c].SetValue(this, atoms[c]);
}
}
public IntPtr GetAtom(string name)
{
if (_namesToAtoms.TryGetValue(name, out var rv))
return rv;
var atom = XInternAtom(_display, name, false);
_namesToAtoms[name] = atom;
_atomsToNames[atom] = name;
return atom;
}
public string GetAtomName(IntPtr atom)
{
if (_atomsToNames.TryGetValue(atom, out var rv))
return rv;
var name = XLib.GetAtomName(_display, atom);
if (name == null)
return null;
_atomsToNames[atom] = name;
_namesToAtoms[name] = atom;
return name;
}
}
}

135
src/Avalonia.X11/X11Clipboard.cs

@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Input;
using Avalonia.Input.Platform;
using static Avalonia.X11.XLib;
namespace Avalonia.X11
@ -10,12 +12,14 @@ namespace Avalonia.X11
class X11Clipboard : IClipboard
{
private readonly X11Info _x11;
private string _storedString;
private IDataObject _storedDataObject;
private IntPtr _handle;
private TaskCompletionSource<IntPtr[]> _requestedFormatsTcs;
private TaskCompletionSource<string> _requestedTextTcs;
private TaskCompletionSource<object> _requestedDataTcs;
private readonly IntPtr[] _textAtoms;
private readonly IntPtr _avaloniaSaveTargetsAtom;
private readonly Dictionary<string, IntPtr> _formatAtoms = new Dictionary<string, IntPtr>();
private readonly Dictionary<IntPtr, string> _atomFormats = new Dictionary<IntPtr, string>();
public X11Clipboard(AvaloniaX11Platform platform)
{
@ -31,6 +35,11 @@ namespace Avalonia.X11
}.Where(a => a != IntPtr.Zero).ToArray();
}
bool IsStringAtom(IntPtr atom)
{
return _textAtoms.Contains(atom);
}
Encoding GetStringEncoding(IntPtr atom)
{
return (atom == _x11.Atoms.XA_STRING
@ -75,21 +84,31 @@ namespace Avalonia.X11
Encoding textEnc;
if (target == _x11.Atoms.TARGETS)
{
var atoms = _textAtoms;
atoms = atoms.Concat(new[] {_x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE})
.ToArray();
var atoms = new HashSet<IntPtr> { _x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE };
foreach (var fmt in _storedDataObject.GetDataFormats())
{
if (fmt == DataFormats.Text)
foreach (var ta in _textAtoms)
atoms.Add(ta);
else
atoms.Add(_x11.Atoms.GetAtom(fmt));
}
XChangeProperty(_x11.Display, window, property,
_x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, atoms, atoms.Length);
_x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, atoms.ToArray(), atoms.Count);
return property;
}
else if(target == _x11.Atoms.SAVE_TARGETS && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero)
{
return property;
}
else if ((textEnc = GetStringEncoding(target)) != null)
else if ((textEnc = GetStringEncoding(target)) != null
&& _storedDataObject?.Contains(DataFormats.Text) == true)
{
var data = textEnc.GetBytes(_storedString ?? "");
var text = _storedDataObject.GetText();
if(text == null)
return IntPtr.Zero;
var data = textEnc.GetBytes(text);
fixed (void* pdata = data)
XChangeProperty(_x11.Display, window, property, target, 8,
PropertyMode.Replace,
@ -121,6 +140,23 @@ namespace Avalonia.X11
return property;
}
else if(_storedDataObject?.Contains(_x11.Atoms.GetAtomName(target)) == true)
{
var objValue = _storedDataObject.Get(_x11.Atoms.GetAtomName(target));
if(!(objValue is byte[] bytes))
{
if (objValue is string s)
bytes = Encoding.UTF8.GetBytes(s);
else
return IntPtr.Zero;
}
XChangeProperty(_x11.Display, window, property, target, 8,
PropertyMode.Replace,
bytes, bytes.Length);
return property;
}
else
return IntPtr.Zero;
}
@ -131,15 +167,15 @@ namespace Avalonia.X11
if (sel.property == IntPtr.Zero)
{
_requestedFormatsTcs?.TrySetResult(null);
_requestedTextTcs?.TrySetResult(null);
_requestedDataTcs?.TrySetResult(null);
}
XGetWindowProperty(_x11.Display, _handle, sel.property, IntPtr.Zero, new IntPtr (0x7fffffff), true, (IntPtr)Atom.AnyPropertyType,
out var actualAtom, out var actualFormat, out var nitems, out var bytes_after, out var prop);
out var actualTypeAtom, out var actualFormat, out var nitems, out var bytes_after, out var prop);
Encoding textEnc = null;
if (nitems == IntPtr.Zero)
{
_requestedFormatsTcs?.TrySetResult(null);
_requestedTextTcs?.TrySetResult(null);
_requestedDataTcs?.TrySetResult(null);
}
else
{
@ -154,10 +190,24 @@ namespace Avalonia.X11
_requestedFormatsTcs?.TrySetResult(formats);
}
}
else if ((textEnc = GetStringEncoding(sel.property)) != null)
else if ((textEnc = GetStringEncoding(actualTypeAtom)) != null)
{
var text = textEnc.GetString((byte*)prop.ToPointer(), nitems.ToInt32());
_requestedTextTcs?.TrySetResult(text);
_requestedDataTcs?.TrySetResult(text);
}
else
{
if (actualTypeAtom == _x11.Atoms.INCR)
{
// TODO: Actually implement that monstrosity
_requestedDataTcs.TrySetResult(null);
}
else
{
var data = new byte[(int)nitems * (actualFormat / 8)];
Marshal.Copy(prop, data, 0, data.Length);
_requestedDataTcs?.TrySetResult(data);
}
}
}
@ -174,17 +224,19 @@ namespace Avalonia.X11
return _requestedFormatsTcs.Task;
}
Task<string> SendTextRequest(IntPtr format)
Task<object> SendDataRequest(IntPtr format)
{
if (_requestedTextTcs == null || _requestedFormatsTcs.Task.IsCompleted)
_requestedTextTcs = new TaskCompletionSource<string>();
if (_requestedDataTcs == null || _requestedFormatsTcs.Task.IsCompleted)
_requestedDataTcs = new TaskCompletionSource<object>();
XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD, format, format, _handle, IntPtr.Zero);
return _requestedTextTcs.Task;
return _requestedDataTcs.Task;
}
bool HasOwner => XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD) != IntPtr.Zero;
public async Task<string> GetTextAsync()
{
if (XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD) == IntPtr.Zero)
if (!HasOwner)
return null;
var res = await SendFormatRequest();
var target = _x11.Atoms.UTF8_STRING;
@ -199,7 +251,7 @@ namespace Avalonia.X11
}
}
return await SendTextRequest(target);
return (string)await SendDataRequest(target);
}
void StoreAtomsInClipboardManager(IntPtr[] atoms)
@ -220,15 +272,52 @@ namespace Avalonia.X11
public Task SetTextAsync(string text)
{
_storedString = text;
var data = new DataObject();
data.Set(DataFormats.Text, text);
return SetDataObjectAsync(data);
}
public Task ClearAsync()
{
return SetTextAsync(null);
}
public Task SetDataObjectAsync(IDataObject data)
{
_storedDataObject = data;
XSetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD, _handle, IntPtr.Zero);
StoreAtomsInClipboardManager(_textAtoms);
return Task.CompletedTask;
}
public Task ClearAsync()
public async Task<string[]> GetFormatsAsync()
{
return SetTextAsync(null);
if (!HasOwner)
return null;
var res = await SendFormatRequest();
if (res == null)
return null;
var rv = new List<string>();
if (_textAtoms.Any(res.Contains))
rv.Add(DataFormats.Text);
foreach (var t in res)
rv.Add(_x11.Atoms.GetAtomName(t));
return rv.ToArray();
}
public async Task<object> GetDataAsync(string format)
{
if (!HasOwner)
return null;
if (format == DataFormats.Text)
return await GetTextAsync();
var formatAtom = _x11.Atoms.GetAtom(format);
var res = await SendFormatRequest();
if (!res.Contains(formatAtom))
return null;
return await SendDataRequest(formatAtom);
}
}
}

4
src/Avalonia.X11/XLib.cs

@ -236,6 +236,10 @@ namespace Avalonia.X11
public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
int format, PropertyMode mode, ref IntPtr value, int nelements);
[DllImport(libX11)]
public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
int format, PropertyMode mode, byte[] data, int nelements);
[DllImport(libX11)]
public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
int format, PropertyMode mode, uint[] data, int nelements);

12
src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs

@ -176,7 +176,13 @@ namespace Avalonia.LinuxFramebuffer.Output
[DllImport(libdrm, SetLastError = true)]
public static extern int drmModeAddFB(int fd, uint width, uint height, byte depth,
byte bpp, uint pitch, uint bo_handle,
out uint buf_id);
out uint buf_id);
[DllImport(libdrm, SetLastError = true)]
public static extern int drmModeAddFB2(int fd, uint width, uint height,
uint pixel_format, uint[] bo_handles, uint[] pitches,
uint[] offsets, out uint buf_id, uint flags);
[DllImport(libdrm, SetLastError = true)]
public static extern int drmModeSetCrtc(int fd, uint crtcId, uint bufferId,
uint x, uint y, uint *connectors, int count,
@ -261,6 +267,8 @@ namespace Avalonia.LinuxFramebuffer.Output
[DllImport(libgbm, SetLastError = true)]
public static extern uint gbm_bo_get_stride(IntPtr bo);
[DllImport(libgbm, SetLastError = true)]
public static extern uint gbm_bo_get_format(IntPtr bo);
[StructLayout(LayoutKind.Explicit)]
public struct GbmBoHandle
@ -278,7 +286,7 @@ namespace Avalonia.LinuxFramebuffer.Output
}
[DllImport(libgbm, SetLastError = true)]
public static extern ulong gbm_bo_get_handle(IntPtr bo);
public static extern GbmBoHandle gbm_bo_get_handle(IntPtr bo);
public static class GbmColorFormats
{

23
src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs

@ -7,6 +7,8 @@ using Avalonia.OpenGL;
using Avalonia.Platform.Interop;
using static Avalonia.LinuxFramebuffer.NativeUnsafeMethods;
using static Avalonia.LinuxFramebuffer.Output.LibDrm;
using static Avalonia.LinuxFramebuffer.Output.LibDrm.GbmColorFormats;
namespace Avalonia.LinuxFramebuffer.Output
{
public unsafe class DrmOutput : IOutputBackend, IGlPlatformSurface, IWindowingPlatformGlFeature
@ -71,11 +73,26 @@ namespace Avalonia.LinuxFramebuffer.Output
var w = gbm_bo_get_width(bo);
var h = gbm_bo_get_height(bo);
var stride = gbm_bo_get_stride(bo);
var handle = gbm_bo_get_handle(bo);
var handle = gbm_bo_get_handle(bo).u32;
var format = gbm_bo_get_format(bo);
// prepare for the new ioctl call
var handles = new uint[] {handle, 0, 0, 0};
var pitches = new uint[] {stride, 0, 0, 0};
var offsets = new uint[] {};
var ret = drmModeAddFB2(_card.Fd, w, h, format, handles, pitches,
offsets, out var fbHandle, 0);
var ret = drmModeAddFB(_card.Fd, w, h, 24, 32, stride, (uint)handle, out var fbHandle);
if (ret != 0)
throw new Win32Exception(ret, "drmModeAddFb failed");
{
// legacy fallback
ret = drmModeAddFB(_card.Fd, w, h, 24, 32, stride, (uint)handle,
out fbHandle);
if (ret != 0)
throw new Win32Exception(ret, $"drmModeAddFb failed {ret}");
}
gbm_bo_set_user_data(bo, new IntPtr((int)fbHandle), FbDestroyDelegate);

8
src/Markup/Avalonia.Markup/Data/MultiBinding.cs

@ -107,6 +107,14 @@ namespace Avalonia.Data
private object ConvertValue(IList<object> values, Type targetType, IMultiValueConverter converter)
{
for (var i = 0; i < values.Count; ++i)
{
if (values[i] is BindingNotification notification)
{
values[i] = notification.Value;
}
}
var culture = CultureInfo.CurrentCulture;
var converted = converter.Convert(values, targetType, ConverterParameter, culture);

2
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -236,7 +236,7 @@ namespace Avalonia.Direct2D1.Media
Math.Max(rrect.RadiiTopRight.X, Math.Max(rrect.RadiiBottomRight.X, rrect.RadiiBottomLeft.X)));
var radiusY = Math.Max(rrect.RadiiTopLeft.Y,
Math.Max(rrect.RadiiTopRight.Y, Math.Max(rrect.RadiiBottomRight.Y, rrect.RadiiBottomLeft.Y)));
var isRounded = Math.Abs(radiusX) > double.Epsilon || Math.Abs(radiusY) > double.Epsilon;
var isRounded = !MathUtilities.IsZero(radiusX) || !MathUtilities.IsZero(radiusY);
if (brush != null)
{

3
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -6,6 +6,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001" />
</ItemGroup>
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\build\System.Drawing.Common.props" />
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\build\System.Drawing.Common.props" />
</Project>

76
src/Windows/Avalonia.Win32/ClipboardImpl.cs

@ -1,25 +1,30 @@
using System;
using System.Linq;
using System.Reactive.Disposables;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Threading;
using Avalonia.Win32.Interop;
namespace Avalonia.Win32
{
internal class ClipboardImpl : IClipboard
{
private async Task OpenClipboard()
private async Task<IDisposable> OpenClipboard()
{
while (!UnmanagedMethods.OpenClipboard(IntPtr.Zero))
{
await Task.Delay(100);
}
return Disposable.Create(() => UnmanagedMethods.CloseClipboard());
}
public async Task<string> GetTextAsync()
{
await OpenClipboard();
try
using(await OpenClipboard())
{
IntPtr hText = UnmanagedMethods.GetClipboardData(UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT);
if (hText == IntPtr.Zero)
@ -37,10 +42,6 @@ namespace Avalonia.Win32
UnmanagedMethods.GlobalUnlock(hText);
return rv;
}
finally
{
UnmanagedMethods.CloseClipboard();
}
}
public async Task SetTextAsync(string text)
@ -50,31 +51,66 @@ namespace Avalonia.Win32
throw new ArgumentNullException(nameof(text));
}
await OpenClipboard();
UnmanagedMethods.EmptyClipboard();
try
using(await OpenClipboard())
{
UnmanagedMethods.EmptyClipboard();
var hGlobal = Marshal.StringToHGlobalUni(text);
UnmanagedMethods.SetClipboardData(UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, hGlobal);
}
finally
{
UnmanagedMethods.CloseClipboard();
}
}
public async Task ClearAsync()
{
await OpenClipboard();
try
using(await OpenClipboard())
{
UnmanagedMethods.EmptyClipboard();
}
finally
}
public async Task SetDataObjectAsync(IDataObject data)
{
Dispatcher.UIThread.VerifyAccess();
var wrapper = new DataObject(data);
while (true)
{
UnmanagedMethods.CloseClipboard();
if (UnmanagedMethods.OleSetClipboard(wrapper) == 0)
break;
await Task.Delay(100);
}
}
public async Task<string[]> GetFormatsAsync()
{
Dispatcher.UIThread.VerifyAccess();
while (true)
{
if (UnmanagedMethods.OleGetClipboard(out var dataObject) == 0)
{
var wrapper = new OleDataObject(dataObject);
var formats = wrapper.GetDataFormats().ToArray();
Marshal.ReleaseComObject(dataObject);
return formats;
}
await Task.Delay(100);
}
}
public async Task<object> GetDataAsync(string format)
{
Dispatcher.UIThread.VerifyAccess();
while (true)
{
if (UnmanagedMethods.OleGetClipboard(out var dataObject) == 0)
{
var wrapper = new OleDataObject(dataObject);
var rv = wrapper.Get(format);
Marshal.ReleaseComObject(dataObject);
return rv;
}
await Task.Delay(100);
}
}
}

6
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -1169,6 +1169,12 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern IntPtr SetClipboardData(ClipboardFormat uFormat, IntPtr hMem);
[DllImport("ole32.dll", PreserveSig = false)]
public static extern int OleGetClipboard(out IOleDataObject dataObject);
[DllImport("ole32.dll", PreserveSig = true)]
public static extern int OleSetClipboard(IOleDataObject dataObject);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalLock(IntPtr handle);

2
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -36,7 +36,7 @@ namespace Avalonia
public class Win32PlatformOptions
{
public bool UseDeferredRendering { get; set; } = true;
public bool AllowEglInitialization { get; set; }
public bool AllowEglInitialization { get; set; } = true;
public bool? EnableMultitouch { get; set; }
public bool OverlayPopups { get; set; }
}

6
src/iOS/Avalonia.iOS/Clipboard.cs

@ -22,5 +22,11 @@ namespace Avalonia.iOS
UIPasteboard.General.String = "";
return Task.FromResult(0);
}
public Task SetDataObjectAsync(IDataObject data) => throw new PlatformNotSupportedException();
public Task<string[]> GetFormatsAsync() => throw new PlatformNotSupportedException();
public Task<object> GetDataAsync(string format) => throw new PlatformNotSupportedException();
}
}

65
tests/Avalonia.Animation.UnitTests/AnimatableTests.cs

@ -2,6 +2,7 @@
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Moq;
@ -265,6 +266,70 @@ namespace Avalonia.Animation.UnitTests
}
}
[Fact]
public void Replacing_Transitions_During_Animation_Does_Not_Throw_KeyNotFound()
{
// Issue #4059
using (UnitTestApplication.Start(TestServices.RealStyler))
{
Border target;
var clock = new TestClock();
var root = new TestRoot
{
Clock = clock,
Styles =
{
new Style(x => x.OfType<Border>())
{
Setters =
{
new Setter(Border.TransitionsProperty,
new Transitions
{
new DoubleTransition
{
Property = Border.OpacityProperty,
Duration = TimeSpan.FromSeconds(1),
},
}),
},
},
new Style(x => x.OfType<Border>().Class("foo"))
{
Setters =
{
new Setter(Border.TransitionsProperty,
new Transitions
{
new DoubleTransition
{
Property = Border.OpacityProperty,
Duration = TimeSpan.FromSeconds(1),
},
}),
new Setter(Border.OpacityProperty, 0.0),
},
},
},
Child = target = new Border
{
Background = Brushes.Red,
}
};
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
target.Classes.Add("foo");
clock.Step(TimeSpan.FromSeconds(0));
clock.Step(TimeSpan.FromSeconds(0.5));
Assert.Equal(0.5, target.Opacity);
target.Classes.Remove("foo");
}
}
private static Mock<ITransition> CreateTarget()
{
return CreateTransition(Visual.OpacityProperty);

2
tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs

@ -322,7 +322,7 @@ namespace Avalonia.Base.UnitTests.Data.Core
{
"bar",
new BindingNotification(
new MissingMemberException("Could not find CLR property 'Bar' on 'Avalonia.Base.UnitTests.Data.Core.ExpressionObserverTests_Property+WithoutBar'"),
new MissingMemberException("Could not find a matching property accessor for 'Bar' on 'Avalonia.Base.UnitTests.Data.Core.ExpressionObserverTests_Property+WithoutBar'"),
BindingErrorType.Error),
"baz",
},

119
tests/Avalonia.Base.UnitTests/Utilities/MathUtilitiesTests.cs

@ -0,0 +1,119 @@
using System;
using Avalonia.Utilities;
using Xunit;
namespace Avalonia.Base.UnitTests.Utilities
{
public class MathUtilitiesTests
{
private const double AnyValue = 42.42;
private readonly double _calculatedAnyValue;
private readonly double _one;
private readonly double _zero;
public MathUtilitiesTests()
{
_calculatedAnyValue = 0.0;
_one = 0.0;
_zero = 1.0;
const int N = 10;
var dxAny = AnyValue / N;
var dxOne = 1.0 / N;
var dxZero = _zero / N;
for (var i = 0; i < N; ++i)
{
_calculatedAnyValue += dxAny;
_one += dxOne;
_zero -= dxZero;
}
}
[Fact]
public void Two_Equivalent_Double_Values_Are_Close()
{
var actual = MathUtilities.AreClose(AnyValue, _calculatedAnyValue);
Assert.True(actual);
Assert.Equal(AnyValue, Math.Round(_calculatedAnyValue, 14));
}
[Fact]
public void Two_Equivalent_Single_Values_Are_Close()
{
var expectedValue = (float)AnyValue;
var actualValue = (float)_calculatedAnyValue;
var actual = MathUtilities.AreClose(expectedValue, actualValue);
Assert.True(actual);
Assert.Equal((float) Math.Round(expectedValue, 5), (float) Math.Round(actualValue, 4));
}
[Fact]
public void Calculated_Double_One_Is_One()
{
var actual = MathUtilities.IsOne(_one);
Assert.True(actual);
Assert.Equal(1.0, Math.Round(_one, 15));
}
[Fact]
public void Calculated_Single_One_Is_One()
{
var actualValue = (float)_one;
var actual = MathUtilities.IsOne(actualValue);
Assert.True(actual);
Assert.Equal(1.0f, (float) Math.Round(actualValue, 7));
}
[Fact]
public void Calculated_Double_Zero_Is_Zero()
{
var actual = MathUtilities.IsZero(_zero);
Assert.True(actual);
Assert.Equal(0.0, Math.Round(_zero, 15));
}
[Fact]
public void Calculated_Single_Zero_Is_Zero()
{
var actualValue = (float)_zero;
var actual = MathUtilities.IsZero(actualValue);
Assert.True(actual);
Assert.Equal(0.0f, (float) Math.Round(actualValue, 7));
}
[Fact]
public void Clamp_Input_NaN_Return_NaN()
{
var clamp = MathUtilities.Clamp(double.NaN, 0.0, 1.0);
Assert.True(double.IsNaN(clamp));
}
[Fact]
public void Clamp_Input_NegativeInfinity_Return_Min()
{
const double min = 0.0;
const double max = 1.0;
var actual = MathUtilities.Clamp(double.NegativeInfinity, min, max);
Assert.Equal(min, actual);
}
[Fact]
public void Clamp_Input_PositiveInfinity_Return_Max()
{
const double min = 0.0;
const double max = 1.0;
var actual = MathUtilities.Clamp(double.PositiveInfinity, min, max);
Assert.Equal(max, actual);
}
}
}

47
tests/Avalonia.Benchmarks/Data/AccessorTestObject.cs

@ -0,0 +1,47 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace Avalonia.Benchmarks.Data
{
internal class AccessorTestObject : INotifyPropertyChanged
{
private string _test;
public string Test
{
get => _test;
set
{
if (_test == value)
{
return;
}
_test = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void Execute()
{
}
public void Execute(object p0)
{
}
public void Execute(object p0, object p1)
{
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

44
tests/Avalonia.Benchmarks/Data/PropertyAccessorBenchmarks.cs

@ -0,0 +1,44 @@
using System;
using Avalonia.Data.Core.Plugins;
using BenchmarkDotNet.Attributes;
namespace Avalonia.Benchmarks.Data
{
[MemoryDiagnoser, InProcess]
public class PropertyAccessorBenchmarks
{
private readonly InpcPropertyAccessorPlugin _inpcPlugin = new InpcPropertyAccessorPlugin();
private readonly MethodAccessorPlugin _methodPlugin = new MethodAccessorPlugin();
private readonly AccessorTestObject _targetStrongRef = new AccessorTestObject();
private readonly WeakReference<object> _targetWeakRef;
public PropertyAccessorBenchmarks()
{
_targetWeakRef = new WeakReference<object>(_targetStrongRef);
}
[Benchmark]
public void InpcAccessorMatch()
{
_inpcPlugin.Match(_targetWeakRef, nameof(AccessorTestObject.Test));
}
[Benchmark]
public void InpcAccessorStart()
{
_inpcPlugin.Start(_targetWeakRef, nameof(AccessorTestObject.Test));
}
[Benchmark]
public void MethodAccessorMatch()
{
_methodPlugin.Match(_targetWeakRef, nameof(AccessorTestObject.Execute));
}
[Benchmark]
public void MethodAccessorStart()
{
_methodPlugin.Start(_targetWeakRef, nameof(AccessorTestObject.Execute));
}
}
}

60
tests/Avalonia.Benchmarks/Data/PropertyAccessorPluginBenchmarks.cs

@ -0,0 +1,60 @@
using System.Collections.Generic;
using Avalonia.Data.Core.Plugins;
using BenchmarkDotNet.Attributes;
namespace Avalonia.Benchmarks.Data
{
[MemoryDiagnoser, InProcess]
public class PropertyAccessorPluginBenchmarks
{
private readonly AccessorTestObject _targetStrongRef = new AccessorTestObject();
private readonly List<IPropertyAccessorPlugin> _oldPlugins;
private readonly List<IPropertyAccessorPlugin> _newPlugins;
public PropertyAccessorPluginBenchmarks()
{
_oldPlugins = new List<IPropertyAccessorPlugin>
{
new AvaloniaPropertyAccessorPlugin(),
new MethodAccessorPlugin(),
new InpcPropertyAccessorPlugin()
};
_newPlugins = new List<IPropertyAccessorPlugin>
{
new AvaloniaPropertyAccessorPlugin(),
new InpcPropertyAccessorPlugin(),
new MethodAccessorPlugin()
};
}
[Benchmark]
public void MatchAccessorOld()
{
var propertyName = nameof(AccessorTestObject.Test);
foreach (IPropertyAccessorPlugin x in _oldPlugins)
{
if (x.Match(_targetStrongRef, propertyName))
{
break;
}
}
}
[Benchmark]
public void MatchAccessorNew()
{
var propertyName = nameof(AccessorTestObject.Test);
foreach (IPropertyAccessorPlugin x in _newPlugins)
{
if (x.Match(_targetStrongRef, propertyName))
{
break;
}
}
}
}
}

14
tests/Avalonia.Controls.UnitTests/DatePickerTests.cs → tests/Avalonia.Controls.UnitTests/CalendarDatePickerTests.cs

@ -15,7 +15,7 @@ using Xunit;
namespace Avalonia.Controls.UnitTests
{
public class DatePickerTests
public class CalendarDatePickerTests
{
private static bool CompareDates(DateTime first, DateTime second)
{
@ -30,7 +30,7 @@ namespace Avalonia.Controls.UnitTests
using (UnitTestApplication.Start(Services))
{
bool handled = false;
DatePicker datePicker = CreateControl();
CalendarDatePicker datePicker = CreateControl();
datePicker.SelectedDateChanged += (s,e) =>
{
handled = true;
@ -47,7 +47,7 @@ namespace Avalonia.Controls.UnitTests
{
using (UnitTestApplication.Start(Services))
{
DatePicker datePicker = CreateControl();
CalendarDatePicker datePicker = CreateControl();
datePicker.BlackoutDates.AddDatesInPast();
DateTime goodValue = DateTime.Today.AddDays(1);
@ -65,7 +65,7 @@ namespace Avalonia.Controls.UnitTests
{
using (UnitTestApplication.Start(Services))
{
DatePicker datePicker = CreateControl();
CalendarDatePicker datePicker = CreateControl();
datePicker.SelectedDate = DateTime.Today.AddDays(5);
Assert.ThrowsAny<ArgumentOutOfRangeException>(
@ -76,10 +76,10 @@ namespace Avalonia.Controls.UnitTests
private static TestServices Services => TestServices.MockThreadingInterface.With(
standardCursorFactory: Mock.Of<IStandardCursorFactory>());
private DatePicker CreateControl()
private CalendarDatePicker CreateControl()
{
var datePicker =
new DatePicker
new CalendarDatePicker
{
Template = CreateTemplate()
};
@ -90,7 +90,7 @@ namespace Avalonia.Controls.UnitTests
private IControlTemplate CreateTemplate()
{
return new FuncControlTemplate<DatePicker>((control, scope) =>
return new FuncControlTemplate<CalendarDatePicker>((control, scope) =>
{
var textBox =
new TextBox

82
tests/Avalonia.Controls.UnitTests/IndexRangeTests.cs

@ -127,6 +127,88 @@ namespace Avalonia.Controls.UnitTests
Assert.Empty(selected);
}
[Fact]
public void Intersect_Should_Remove_Items_From_Beginning()
{
var ranges = new List<IndexRange> { new IndexRange(0, 10) };
var removed = new List<IndexRange>();
var result = IndexRange.Intersect(ranges, new IndexRange(2, 12), removed);
Assert.Equal(2, result);
Assert.Equal(new[] { new IndexRange(2, 10) }, ranges);
Assert.Equal(new[] { new IndexRange(0, 1) }, removed);
}
[Fact]
public void Intersect_Should_Remove_Items_From_End()
{
var ranges = new List<IndexRange> { new IndexRange(0, 10) };
var removed = new List<IndexRange>();
var result = IndexRange.Intersect(ranges, new IndexRange(0, 8), removed);
Assert.Equal(2, result);
Assert.Equal(new[] { new IndexRange(0, 8) }, ranges);
Assert.Equal(new[] { new IndexRange(9, 10) }, removed);
}
[Fact]
public void Intersect_Should_Remove_Entire_Range_Start()
{
var ranges = new List<IndexRange> { new IndexRange(0, 5), new IndexRange(6, 10) };
var removed = new List<IndexRange>();
var result = IndexRange.Intersect(ranges, new IndexRange(6, 10), removed);
Assert.Equal(6, result);
Assert.Equal(new[] { new IndexRange(6, 10) }, ranges);
Assert.Equal(new[] { new IndexRange(0, 5) }, removed);
}
[Fact]
public void Intersect_Should_Remove_Entire_Range_End()
{
var ranges = new List<IndexRange> { new IndexRange(0, 5), new IndexRange(6, 10) };
var removed = new List<IndexRange>();
var result = IndexRange.Intersect(ranges, new IndexRange(0, 4), removed);
Assert.Equal(6, result);
Assert.Equal(new[] { new IndexRange(0, 4) }, ranges);
Assert.Equal(new[] { new IndexRange(5, 10) }, removed);
}
[Fact]
public void Intersect_Should_Remove_Entire_Range_Start_End()
{
var ranges = new List<IndexRange>
{
new IndexRange(0, 2),
new IndexRange(3, 7),
new IndexRange(8, 10)
};
var removed = new List<IndexRange>();
var result = IndexRange.Intersect(ranges, new IndexRange(3, 7), removed);
Assert.Equal(6, result);
Assert.Equal(new[] { new IndexRange(3, 7) }, ranges);
Assert.Equal(new[] { new IndexRange(0, 2), new IndexRange(8, 10) }, removed);
}
[Fact]
public void Intersect_Should_Remove_Entire_And_Partial_Range_Start_End()
{
var ranges = new List<IndexRange>
{
new IndexRange(0, 2),
new IndexRange(3, 7),
new IndexRange(8, 10)
};
var removed = new List<IndexRange>();
var result = IndexRange.Intersect(ranges, new IndexRange(4, 6), removed);
Assert.Equal(8, result);
Assert.Equal(new[] { new IndexRange(4, 6) }, ranges);
Assert.Equal(new[] { new IndexRange(0, 3), new IndexRange(7, 10) }, removed);
}
[Fact]
public void Remove_Should_Remove_Entire_Range()
{

146
tests/Avalonia.Controls.UnitTests/SelectionModelTests.cs

@ -1512,6 +1512,47 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(0, raised);
}
[Fact]
public void Batch_Update_Selection_Is_Correct_Throughout()
{
var data = new[] { "foo", "bar", "baz", "qux" };
var target = new SelectionModel { Source = data };
var raised = 0;
using (target.Update())
{
target.Select(1);
Assert.Equal(new IndexPath(1), target.SelectedIndex);
Assert.Equal(new[] { new IndexPath(1) }, target.SelectedIndices);
Assert.Equal("bar", target.SelectedItem);
Assert.Equal(new[] { "bar" }, target.SelectedItems);
target.Deselect(1);
Assert.Equal(new IndexPath(), target.SelectedIndex);
Assert.Empty(target.SelectedIndices);
Assert.Null(target.SelectedItem);
Assert.Empty(target.SelectedItems);
target.SelectRange(new IndexPath(1), new IndexPath(1));
Assert.Equal(new IndexPath(1), target.SelectedIndex);
Assert.Equal(new[] { new IndexPath(1) }, target.SelectedIndices);
Assert.Equal("bar", target.SelectedItem);
Assert.Equal(new[] { "bar" }, target.SelectedItems);
target.ClearSelection();
Assert.Equal(new IndexPath(), target.SelectedIndex);
Assert.Empty(target.SelectedIndices);
Assert.Null(target.SelectedItem);
Assert.Empty(target.SelectedItems);
}
Assert.Equal(0, raised);
}
[Fact]
public void AutoSelect_Selects_When_Enabled()
{
@ -1713,6 +1754,30 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(0, raised);
}
[Fact]
public void AutoSelect_Is_Applied_At_End_Of_Batch_Update()
{
var data = new[] { "foo", "bar", "baz" };
var target = new SelectionModel { AutoSelect = true, Source = data };
using (target.Update())
{
target.ClearSelection();
Assert.Equal(new IndexPath(), target.SelectedIndex);
Assert.Empty(target.SelectedIndices);
Assert.Null(target.SelectedItem);
Assert.Empty(target.SelectedItems);
}
Assert.Equal(new IndexPath(0), target.SelectedIndex);
Assert.Equal(new[] { new IndexPath(0) }, target.SelectedIndices);
Assert.Equal("foo", target.SelectedItem);
Assert.Equal(new[] { "foo" }, target.SelectedItems);
Assert.Equal(new IndexPath(0), target.SelectedIndex);
}
[Fact]
public void Can_Replace_Parent_Children_Collection()
{
@ -1806,6 +1871,87 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(0, node.PropertyChangedSubscriptions);
}
[Fact]
public void Setting_SelectedIndex_To_Minus_1_Clears_Selection()
{
var data = new[] { "foo", "bar", "baz" };
var target = new SelectionModel { Source = data };
target.SelectedIndex = new IndexPath(1);
target.SelectedIndex = new IndexPath(-1);
Assert.Empty(target.SelectedIndices);
}
[Fact]
public void Assigning_Source_With_Less_Items_Than_Previous_Clears_Selection()
{
var data = new[] { "foo", "bar", "baz", "boo", "hoo" };
var smallerData = new[] { "foo", "bar", "baz" };
var target = new SelectionModel { RetainSelectionOnReset = true };
target.Source = data;
target.SelectedIndex = new IndexPath(4);
target.Source = smallerData;
Assert.Empty(target.SelectedIndices);
}
[Fact]
public void Initializing_Source_With_Less_Items_Than_Selection_Trims_Selection()
{
var data = new[] { "foo", "bar", "baz" };
var target = new SelectionModel();
target.SelectedIndex = new IndexPath(4);
target.Source = data;
Assert.Empty(target.SelectedIndices);
}
[Fact]
public void Initializing_Source_With_Less_Items_Than_Selection_Trims_Selection_RetainSelection()
{
var data = new[] { "foo", "bar", "baz" };
var target = new SelectionModel { RetainSelectionOnReset = true };
target.SelectedIndex = new IndexPath(4);
target.Source = data;
Assert.Empty(target.SelectedIndices);
}
[Fact]
public void Initializing_Source_With_Less_Items_Than_Multiple_Selection_Trims_Selection()
{
var data = new[] { "foo", "bar", "baz" };
var target = new SelectionModel { RetainSelectionOnReset = true };
target.Select(4);
target.Select(2);
target.Source = data;
Assert.Equal(1, target.SelectedIndices.Count);
Assert.Equal(new IndexPath(2), target.SelectedIndices.First());
}
[Fact]
public void Initializing_Source_With_Less_Items_Than_Selection_Raises_SelectionChanged()
{
var data = new[] { "foo", "bar", "baz" };
var target = new SelectionModel();
var raised = 0;
target.SelectedIndex = new IndexPath(4);
target.SelectionChanged += (s, e) =>
{
if (raised == 0)
{
Assert.Equal(new[] { Path(4) }, e.DeselectedIndices);
Assert.Equal(new object[] { null }, e.DeselectedItems);
Assert.Empty(e.SelectedIndices);
Assert.Empty(e.SelectedItems);
}
++raised;
};
target.Source = data;
Assert.Equal(2, raised);
}
private int GetSubscriberCount(AvaloniaList<object> list)
{
return ((INotifyCollectionChangedDebug)list).GetCollectionChangedSubscribers()?.Length ?? 0;

24
tests/Avalonia.Controls.UnitTests/TabControlTests.cs

@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Avalonia.Collections;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils;
using Avalonia.LogicalTree;
using Avalonia.Styling;
using Avalonia.UnitTests;
@ -325,6 +327,28 @@ namespace Avalonia.Controls.UnitTests
Assert.NotEqual(dataContext, tabItem.Content);
}
[Fact]
public void Can_Have_Empty_Tab_Control()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
<TabControl Name='tabs' Items='{Binding Tabs}'/>
</Window>";
var loader = new Markup.Xaml.AvaloniaXamlLoader();
var window = (Window)loader.Load(xaml);
var tabControl = window.FindControl<TabControl>("tabs");
tabControl.DataContext = new { Tabs = new List<string>() };
window.ApplyTemplate();
Assert.Equal(0, tabControl.Items.Count());
}
}
private IControlTemplate TabControlTemplate()
{
return new FuncControlTemplate<TabControl>((parent, scope) =>

5
tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

@ -654,6 +654,11 @@ namespace Avalonia.Controls.UnitTests
public Task SetTextAsync(string text) => Task.CompletedTask;
public Task ClearAsync() => Task.CompletedTask;
public Task SetDataObjectAsync(IDataObject data) => Task.CompletedTask;
public Task<string[]> GetFormatsAsync() => Task.FromResult(Array.Empty<string>());
public Task<object> GetDataAsync(string format) => Task.FromResult((object)null);
}
}
}

71
tests/Avalonia.Controls.UnitTests/ToolTipTests.cs

@ -102,5 +102,76 @@ namespace Avalonia.Controls.UnitTests
Assert.True(ToolTip.GetIsOpen(target));
}
}
[Fact]
public void Open_Class_Should_Not_Initially_Be_Added()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var toolTip = new ToolTip();
var window = new Window();
var decorator = new Decorator()
{
[ToolTip.TipProperty] = toolTip
};
window.Content = decorator;
window.ApplyTemplate();
window.Presenter.ApplyTemplate();
Assert.Empty(toolTip.Classes);
}
}
[Fact]
public void Setting_IsOpen_Should_Add_Open_Class()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var toolTip = new ToolTip();
var window = new Window();
var decorator = new Decorator()
{
[ToolTip.TipProperty] = toolTip
};
window.Content = decorator;
window.ApplyTemplate();
window.Presenter.ApplyTemplate();
ToolTip.SetIsOpen(decorator, true);
Assert.Equal(new[] { ":open" }, toolTip.Classes);
}
}
[Fact]
public void Clearing_IsOpen_Should_Remove_Open_Class()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var toolTip = new ToolTip();
var window = new Window();
var decorator = new Decorator()
{
[ToolTip.TipProperty] = toolTip
};
window.Content = decorator;
window.ApplyTemplate();
window.Presenter.ApplyTemplate();
ToolTip.SetIsOpen(decorator, true);
ToolTip.SetIsOpen(decorator, false);
Assert.Empty(toolTip.Classes);
}
}
}
}

548
tests/Avalonia.Controls.UnitTests/TreeViewTests.cs

@ -118,313 +118,340 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void Clicking_Item_Should_Select_It()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree,
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree,
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
var item = tree[0].Children[1].Children[0];
var container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item);
var item = tree[0].Children[1].Children[0];
var container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item);
Assert.NotNull(container);
Assert.NotNull(container);
_mouse.Click(container);
_mouse.Click(container);
Assert.Equal(item, target.SelectedItem);
Assert.True(container.IsSelected);
Assert.Equal(item, target.SelectedItem);
Assert.True(container.IsSelected);
}
}
[Fact]
public void Clicking_WithControlModifier_Selected_Item_Should_Deselect_It()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
var item = tree[0].Children[1].Children[0];
var container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item);
var item = tree[0].Children[1].Children[0];
var container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item);
Assert.NotNull(container);
Assert.NotNull(container);
target.SelectedItem = item;
target.SelectedItem = item;
Assert.True(container.IsSelected);
Assert.True(container.IsSelected);
_mouse.Click(container, modifiers: KeyModifiers.Control);
_mouse.Click(container, modifiers: KeyModifiers.Control);
Assert.Null(target.SelectedItem);
Assert.False(container.IsSelected);
Assert.Null(target.SelectedItem);
Assert.False(container.IsSelected);
}
}
[Fact]
public void Clicking_WithControlModifier_Not_Selected_Item_Should_Select_It()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
var item1 = tree[0].Children[1].Children[0];
var container1 = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item1);
var item1 = tree[0].Children[1].Children[0];
var container1 = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item1);
var item2 = tree[0].Children[1];
var container2 = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item2);
var item2 = tree[0].Children[1];
var container2 = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item2);
Assert.NotNull(container1);
Assert.NotNull(container2);
Assert.NotNull(container1);
Assert.NotNull(container2);
target.SelectedItem = item1;
target.SelectedItem = item1;
Assert.True(container1.IsSelected);
Assert.True(container1.IsSelected);
_mouse.Click(container2, modifiers: KeyModifiers.Control);
Assert.Equal(item2, target.SelectedItem);
Assert.False(container1.IsSelected);
Assert.True(container2.IsSelected);
_mouse.Click(container2, modifiers: KeyModifiers.Control);
Assert.Equal(item2, target.SelectedItem);
Assert.False(container1.IsSelected);
Assert.True(container2.IsSelected);
}
}
[Fact]
public void Clicking_WithControlModifier_Selected_Item_Should_Deselect_And_Remove_From_SelectedItems()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
var rootNode = tree[0];
var rootNode = tree[0];
var item1 = rootNode.Children[0];
var item2 = rootNode.Children.Last();
var item1 = rootNode.Children[0];
var item2 = rootNode.Children.Last();
var item1Container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item1);
var item2Container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item2);
var item1Container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item1);
var item2Container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item2);
ClickContainer(item1Container, KeyModifiers.Control);
Assert.True(item1Container.IsSelected);
ClickContainer(item1Container, KeyModifiers.Control);
Assert.True(item1Container.IsSelected);
ClickContainer(item2Container, KeyModifiers.Control);
Assert.True(item2Container.IsSelected);
ClickContainer(item2Container, KeyModifiers.Control);
Assert.True(item2Container.IsSelected);
Assert.Equal(new[] {item1, item2}, target.Selection.SelectedItems.OfType<Node>());
Assert.Equal(new[] { item1, item2 }, target.Selection.SelectedItems.OfType<Node>());
ClickContainer(item1Container, KeyModifiers.Control);
Assert.False(item1Container.IsSelected);
ClickContainer(item1Container, KeyModifiers.Control);
Assert.False(item1Container.IsSelected);
Assert.DoesNotContain(item1, target.Selection.SelectedItems.OfType<Node>());
Assert.DoesNotContain(item1, target.Selection.SelectedItems.OfType<Node>());
}
}
[Fact]
public void Clicking_WithShiftModifier_DownDirection_Should_Select_Range_Of_Items()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
var rootNode = tree[0];
var rootNode = tree[0];
var from = rootNode.Children[0];
var to = rootNode.Children.Last();
var from = rootNode.Children[0];
var to = rootNode.Children.Last();
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
ClickContainer(fromContainer, KeyModifiers.None);
ClickContainer(fromContainer, KeyModifiers.None);
Assert.True(fromContainer.IsSelected);
Assert.True(fromContainer.IsSelected);
ClickContainer(toContainer, KeyModifiers.Shift);
AssertChildrenSelected(target, rootNode);
ClickContainer(toContainer, KeyModifiers.Shift);
AssertChildrenSelected(target, rootNode);
}
}
[Fact]
public void Clicking_WithShiftModifier_UpDirection_Should_Select_Range_Of_Items()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
var rootNode = tree[0];
var rootNode = tree[0];
var from = rootNode.Children.Last();
var to = rootNode.Children[0];
var from = rootNode.Children.Last();
var to = rootNode.Children[0];
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
ClickContainer(fromContainer, KeyModifiers.None);
ClickContainer(fromContainer, KeyModifiers.None);
Assert.True(fromContainer.IsSelected);
Assert.True(fromContainer.IsSelected);
ClickContainer(toContainer, KeyModifiers.Shift);
AssertChildrenSelected(target, rootNode);
ClickContainer(toContainer, KeyModifiers.Shift);
AssertChildrenSelected(target, rootNode);
}
}
[Fact]
public void Clicking_First_Item_Of_SelectedItems_Should_Select_Only_It()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
var rootNode = tree[0];
var rootNode = tree[0];
var from = rootNode.Children.Last();
var to = rootNode.Children[0];
var from = rootNode.Children.Last();
var to = rootNode.Children[0];
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
ClickContainer(fromContainer, KeyModifiers.None);
ClickContainer(fromContainer, KeyModifiers.None);
ClickContainer(toContainer, KeyModifiers.Shift);
AssertChildrenSelected(target, rootNode);
ClickContainer(toContainer, KeyModifiers.Shift);
AssertChildrenSelected(target, rootNode);
ClickContainer(fromContainer, KeyModifiers.None);
ClickContainer(fromContainer, KeyModifiers.None);
Assert.True(fromContainer.IsSelected);
Assert.True(fromContainer.IsSelected);
foreach (var child in rootNode.Children)
{
if (child == from)
foreach (var child in rootNode.Children)
{
continue;
}
if (child == from)
{
continue;
}
var container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(child);
var container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(child);
Assert.False(container.IsSelected);
Assert.False(container.IsSelected);
}
}
}
[Fact]
public void Setting_SelectedItem_Should_Set_Container_Selected()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree,
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree,
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
var item = tree[0].Children[1].Children[0];
var container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item);
var item = tree[0].Children[1].Children[0];
var container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item);
Assert.NotNull(container);
Assert.NotNull(container);
target.SelectedItem = item;
target.SelectedItem = item;
Assert.True(container.IsSelected);
Assert.True(container.IsSelected);
}
}
[Fact]
public void Setting_SelectedItem_Should_Raise_SelectedItemChanged_Event()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree,
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree,
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
ExpandAll(target);
var item = tree[0].Children[1].Children[0];
var item = tree[0].Children[1].Children[0];
var called = false;
target.SelectionChanged += (s, e) =>
{
Assert.Empty(e.RemovedItems);
Assert.Equal(1, e.AddedItems.Count);
Assert.Same(item, e.AddedItems[0]);
called = true;
};
var called = false;
target.SelectionChanged += (s, e) =>
{
Assert.Empty(e.RemovedItems);
Assert.Equal(1, e.AddedItems.Count);
Assert.Same(item, e.AddedItems[0]);
called = true;
};
target.SelectedItem = item;
Assert.True(called);
target.SelectedItem = item;
Assert.True(called);
}
}
[Fact]
@ -564,7 +591,7 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void Keyboard_Navigation_Should_Move_To_Last_Selected_Node()
{
using (UnitTestApplication.Start(TestServices.RealFocus))
using (Application())
{
var focus = FocusManager.Instance;
var navigation = AvaloniaLocator.Current.GetService<IKeyboardNavigationHandler>();
@ -647,7 +674,7 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void Pressing_SelectAll_Gesture_With_Downward_Range_Selected_Should_Select_All_Nodes()
{
using (UnitTestApplication.Start())
using (Application())
{
var tree = CreateTestTreeData();
var target = new TreeView
@ -694,7 +721,7 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void Pressing_SelectAll_Gesture_With_Upward_Range_Selected_Should_Select_All_Nodes()
{
using (UnitTestApplication.Start())
using (Application())
{
var tree = CreateTestTreeData();
var target = new TreeView
@ -768,97 +795,106 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void Right_Click_On_UnselectedItem_Should_Clear_Existing_Selection()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple,
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple,
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
var rootNode = tree[0];
var to = rootNode.Children[0];
var then = rootNode.Children[1];
var rootNode = tree[0];
var to = rootNode.Children[0];
var then = rootNode.Children[1];
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(rootNode);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
var thenContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(then);
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(rootNode);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
var thenContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(then);
ClickContainer(fromContainer, KeyModifiers.None);
ClickContainer(toContainer, KeyModifiers.Shift);
ClickContainer(fromContainer, KeyModifiers.None);
ClickContainer(toContainer, KeyModifiers.Shift);
Assert.Equal(2, target.Selection.SelectedItems.Count);
Assert.Equal(2, target.Selection.SelectedItems.Count);
_mouse.Click(thenContainer, MouseButton.Right);
_mouse.Click(thenContainer, MouseButton.Right);
Assert.Equal(1, target.Selection.SelectedItems.Count);
Assert.Equal(1, target.Selection.SelectedItems.Count);
}
}
[Fact]
public void Shift_Right_Click_Should_Not_Select_Multiple()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple,
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple,
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
var rootNode = tree[0];
var from = rootNode.Children[0];
var to = rootNode.Children[1];
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
var rootNode = tree[0];
var from = rootNode.Children[0];
var to = rootNode.Children[1];
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
_mouse.Click(fromContainer);
_mouse.Click(toContainer, MouseButton.Right, modifiers: KeyModifiers.Shift);
_mouse.Click(fromContainer);
_mouse.Click(toContainer, MouseButton.Right, modifiers: KeyModifiers.Shift);
Assert.Equal(1, target.Selection.SelectedItems.Count);
Assert.Equal(1, target.Selection.SelectedItems.Count);
}
}
[Fact]
public void Ctrl_Right_Click_Should_Not_Select_Multiple()
{
var tree = CreateTestTreeData();
var target = new TreeView
using (Application())
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple,
};
var tree = CreateTestTreeData();
var target = new TreeView
{
Template = CreateTreeViewTemplate(),
Items = tree,
SelectionMode = SelectionMode.Multiple,
};
var visualRoot = new TestRoot();
visualRoot.Child = target;
var visualRoot = new TestRoot();
visualRoot.Child = target;
CreateNodeDataTemplate(target);
ApplyTemplates(target);
target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
CreateNodeDataTemplate(target);
ApplyTemplates(target);
target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
var rootNode = tree[0];
var from = rootNode.Children[0];
var to = rootNode.Children[1];
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
var rootNode = tree[0];
var from = rootNode.Children[0];
var to = rootNode.Children[1];
var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
_mouse.Click(fromContainer);
_mouse.Click(toContainer, MouseButton.Right, modifiers: KeyModifiers.Control);
_mouse.Click(fromContainer);
_mouse.Click(toContainer, MouseButton.Right, modifiers: KeyModifiers.Control);
Assert.Equal(1, target.Selection.SelectedItems.Count);
Assert.Equal(1, target.Selection.SelectedItems.Count);
}
}
[Fact]
@ -944,7 +980,7 @@ namespace Avalonia.Controls.UnitTests
public void Auto_Expanding_In_Style_Should_Not_Break_Range_Selection()
{
/// Issue #2980.
using (UnitTestApplication.Start(TestServices.RealStyler))
using (Application())
{
var target = new DerivedTreeView
{
@ -1183,12 +1219,12 @@ namespace Avalonia.Controls.UnitTests
}
}
void ClickContainer(IControl container, KeyModifiers modifiers)
private void ClickContainer(IControl container, KeyModifiers modifiers)
{
_mouse.Click(container, modifiers: modifiers);
}
void AssertChildrenSelected(TreeView treeView, Node rootNode)
private void AssertChildrenSelected(TreeView treeView, Node rootNode)
{
foreach (var child in rootNode.Children)
{
@ -1198,6 +1234,16 @@ namespace Avalonia.Controls.UnitTests
}
}
private IDisposable Application()
{
return UnitTestApplication.Start(
TestServices.MockThreadingInterface.With(
focusManager: new FocusManager(),
keyboardDevice: () => new KeyboardDevice(),
keyboardNavigation: new KeyboardNavigationHandler(),
inputManager: new InputManager()));
}
private class Node : NotifyingBase
{
private IAvaloniaList<Node> _children;

44
tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs

@ -113,6 +113,50 @@ namespace Avalonia.Markup.UnitTests.Data
Assert.Equal("(null)", target.Text);
}
[Fact]
public void Should_Pass_UnsetValue_To_Converter_For_Broken_Binding()
{
var source = new { A = 1, B = 2, C = 3 };
var target = new TextBlock { DataContext = source };
var binding = new MultiBinding
{
Converter = new ConcatConverter(),
Bindings = new[]
{
new Binding { Path = "A" },
new Binding { Path = "B" },
new Binding { Path = "Missing" },
},
};
target.Bind(TextBlock.TextProperty, binding);
Assert.Equal("1,2,(unset)", target.Text);
}
[Fact]
public void Should_Pass_FallbackValue_To_Converter_For_Broken_Binding()
{
var source = new { A = 1, B = 2, C = 3 };
var target = new TextBlock { DataContext = source };
var binding = new MultiBinding
{
Converter = new ConcatConverter(),
Bindings = new[]
{
new Binding { Path = "A" },
new Binding { Path = "B" },
new Binding { Path = "Missing", FallbackValue = "Fallback" },
},
};
target.Bind(TextBlock.TextProperty, binding);
Assert.Equal("1,2,Fallback", target.Text);
}
private class ConcatConverter : IMultiValueConverter
{
public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)

2
tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Property.cs

@ -22,7 +22,7 @@ namespace Avalonia.Markup.UnitTests.Parsers
Assert.Equal(
new BindingNotification(
new MissingMemberException("Could not find CLR property 'Baz' on '1'"), BindingErrorType.Error),
new MissingMemberException("Could not find a matching property accessor for 'Baz' on '1'"), BindingErrorType.Error),
result);
GC.KeepAlive(data);

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save