Browse Source

Merge branch 'master' into fixes/3991-textbox-caret-tab-focus

pull/4076/head
Benedikt Stebner 6 years ago
committed by GitHub
parent
commit
0b1b07ea4d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  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. 24
      readme.md
  7. 6
      samples/ControlCatalog/App.xaml
  8. 53
      samples/ControlCatalog/App.xaml.cs
  9. 9
      samples/ControlCatalog/MainView.xaml
  10. 23
      samples/ControlCatalog/MainView.xaml.cs
  11. 2
      samples/ControlCatalog/MainWindow.xaml
  12. 6
      samples/ControlCatalog/Pages/ButtonPage.xaml
  13. 20
      samples/ControlCatalog/Pages/ButtonPage.xaml.cs
  14. 18
      samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml
  15. 14
      samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs
  16. 12
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml
  17. 2
      samples/ControlCatalog/Pages/SliderPage.xaml
  18. 1
      samples/ControlCatalog/Pages/TreeViewPage.xaml
  19. 11
      samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs
  20. 6
      src/Android/Avalonia.Android/Platform/ClipboardImpl.cs
  21. 15
      src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
  22. 93
      src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs
  23. 9
      src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
  24. 2
      src/Avalonia.Base/Properties/AssemblyInfo.cs
  25. 94
      src/Avalonia.Base/Utilities/MathUtilities.cs
  26. 21
      src/Avalonia.Controls/AutoCompleteBox.cs
  27. 4
      src/Avalonia.Controls/Calendar/Calendar.cs
  28. 134
      src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
  29. 4
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  30. 167
      src/Avalonia.Controls/ContextMenu.cs
  31. 22
      src/Avalonia.Controls/Converters/MarginMultiplierConverter.cs
  32. 35
      src/Avalonia.Controls/Grid.cs
  33. 20
      src/Avalonia.Controls/IndexPath.cs
  34. 47
      src/Avalonia.Controls/IndexRange.cs
  35. 5
      src/Avalonia.Controls/MenuItem.cs
  36. 55
      src/Avalonia.Controls/Primitives/IPopupHost.cs
  37. 12
      src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
  38. 117
      src/Avalonia.Controls/Primitives/Popup.cs
  39. 424
      src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
  40. 117
      src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs
  41. 6
      src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs
  42. 8
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  43. 16
      src/Avalonia.Controls/Primitives/Track.cs
  44. 76
      src/Avalonia.Controls/SelectionModel.cs
  45. 2
      src/Avalonia.Controls/SelectionModelChangeSet.cs
  46. 22
      src/Avalonia.Controls/SelectionModelChildrenRequestedEventArgs.cs
  47. 27
      src/Avalonia.Controls/SelectionNode.cs
  48. 161
      src/Avalonia.Controls/Slider.cs
  49. 416
      src/Avalonia.Controls/TickBar.cs
  50. 26
      src/Avalonia.Controls/ToolTip.cs
  51. 18
      src/Avalonia.Controls/TreeView.cs
  52. 3
      src/Avalonia.Controls/Utils/BorderRenderHelper.cs
  53. 8
      src/Avalonia.Controls/Utils/SelectionTreeHelper.cs
  54. 4
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  55. 17
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
  56. 38
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs
  57. 24
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs
  58. 2
      src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml
  59. 6
      src/Avalonia.Input/Platform/IClipboard.cs
  60. 15
      src/Avalonia.Native/AvnString.cs
  61. 32
      src/Avalonia.Native/ClipboardImpl.cs
  62. 3
      src/Avalonia.Native/OsxManagedPopupPositionerPopupImplHelper.cs
  63. 4
      src/Avalonia.Themes.Default/CalendarDatePicker.xaml
  64. 2
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  65. 2
      src/Avalonia.Themes.Default/Slider.xaml
  66. 3
      src/Avalonia.Themes.Fluent/Accents/BaseDark.xaml
  67. 3
      src/Avalonia.Themes.Fluent/Accents/BaseLight.xaml
  68. 92
      src/Avalonia.Themes.Fluent/Accents/FluentBaseDark.xaml
  69. 93
      src/Avalonia.Themes.Fluent/Accents/FluentBaseLight.xaml
  70. 260
      src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml
  71. 261
      src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml
  72. 1
      src/Avalonia.Themes.Fluent/Accents/FluentDark.xaml
  73. 1
      src/Avalonia.Themes.Fluent/Accents/FluentLight.xaml
  74. 44
      src/Avalonia.Themes.Fluent/Button.xaml
  75. 200
      src/Avalonia.Themes.Fluent/ButtonSpinner.xaml
  76. 15
      src/Avalonia.Themes.Fluent/Calendar.xaml
  77. 138
      src/Avalonia.Themes.Fluent/CalendarButton.xaml
  78. 4
      src/Avalonia.Themes.Fluent/CalendarDatePicker.xaml
  79. 164
      src/Avalonia.Themes.Fluent/CalendarDayButton.xaml
  80. 275
      src/Avalonia.Themes.Fluent/CalendarItem.xaml
  81. 6
      src/Avalonia.Themes.Fluent/Common.xaml
  82. 69
      src/Avalonia.Themes.Fluent/ContextMenu.xaml
  83. 2
      src/Avalonia.Themes.Fluent/FluentTheme.xaml
  84. 28
      src/Avalonia.Themes.Fluent/Menu.xaml
  85. 244
      src/Avalonia.Themes.Fluent/MenuItem.xaml
  86. 52
      src/Avalonia.Themes.Fluent/NumericUpDown.xaml
  87. 100
      src/Avalonia.Themes.Fluent/RepeatButton.xaml
  88. 12
      src/Avalonia.Themes.Fluent/Separator.xaml
  89. 323
      src/Avalonia.Themes.Fluent/Slider.xaml
  90. 1
      src/Avalonia.Themes.Fluent/TextBox.xaml
  91. 112
      src/Avalonia.Themes.Fluent/ToggleButton.xaml
  92. 95
      src/Avalonia.Themes.Fluent/ToolTip.xaml
  93. 5
      src/Avalonia.Visuals/Media/DrawingContext.cs
  94. 3
      src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
  95. 35
      src/Avalonia.X11/X11Atoms.cs
  96. 135
      src/Avalonia.X11/X11Clipboard.cs
  97. 18
      src/Avalonia.X11/XI2Manager.cs
  98. 4
      src/Avalonia.X11/XLib.cs
  99. 8
      src/Markup/Avalonia.Markup/Data/MultiBinding.cs
  100. 2
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

2
build.sh

@ -67,6 +67,8 @@ else
fi fi
fi fi
export PATH=$DOTNET_DIRECTORY:$PATH
echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)" echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)"
"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" -- ${BUILD_ARGUMENTS[@]} "$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 SetText (char* type, void* utf8Text) = 0;
virtual HRESULT ObtainFormats(IAvnStringArray**ppv) = 0; virtual HRESULT ObtainFormats(IAvnStringArray**ppv) = 0;
virtual HRESULT GetStrings(char* type, 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; virtual HRESULT Clear() = 0;
}; };

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

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

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

@ -29,6 +29,13 @@ public:
memcpy((void*)_cstring, (void*)cstring, _length); 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() virtual ~AvnStringImpl()
{ {
free((void*)_cstring); free((void*)_cstring);
@ -114,3 +121,8 @@ IAvnStringArray* CreateAvnStringArray(NSString* string)
{ {
return new AvnStringArrayImpl(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; 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 virtual HRESULT Clear() override
{ {

24
readme.md

@ -1,24 +1,20 @@
<img src='https://avatars2.githubusercontent.com/u/14075148?s=200&v=4' width='100' /> [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg)
<br />
[![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) [![downloads](https://img.shields.io/nuget/dt/avalonia)](https://www.nuget.org/packages/Avalonia) [![MyGet](https://img.shields.io/myget/avalonia-ci/vpre/Avalonia.svg?label=myget)](https://www.myget.org/gallery/avalonia-ci) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg)
# Avalonia <img src="https://user-images.githubusercontent.com/6759207/84750966-ac74ad80-afc4-11ea-97a4-067d99c15a7d.png" width="500"/>
| Gitter Chat | Build Status (Win, Linux, OSX) | Open Collective | NuGet | MyGet | ## 📖 About AvaloniaUI
|---|---|---|---|---|
| [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) | [![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) | [![MyGet](https://img.shields.io/myget/avalonia-ci/vpre/Avalonia.svg?label=myget)](https://www.myget.org/gallery/avalonia-ci) |
## About Avalonia is a cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows via .NET Framework and .NET Core, Linux via Xorg, macOS. Avalonia is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and breaking changes as we continue along into this project's development.
**Avalonia** is a cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), macOS. <img src="https://user-images.githubusercontent.com/6759207/84751662-7c79da00-afc5-11ea-8780-dda28db70b76.png" width="700" />
**Avalonia** is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and breaking changes as we continue along into this project's development. > **Note:** The UI theme you see in the picture above is still work-in-progress and will be available in the upcoming Avalonia 0.10.0 release. However, you can connect to our nightly build feed and install latest pre-release versions of Avalonia NuGet packages, if you are willing to help out with the development and testing. See [Using nightly build feed](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) for more info.
To see the status of some of our features, please see our [Roadmap here](https://github.com/AvaloniaUI/Avalonia/issues/2239). To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. [Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. ## 🚀 Getting Started
[Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
## Getting Started
The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starer guide see our [documentation](http://avaloniaui.net/docs/quickstart/create-new-project). The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starer guide see our [documentation](http://avaloniaui.net/docs/quickstart/create-new-project).

6
samples/ControlCatalog/App.xaml

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

53
samples/ControlCatalog/App.xaml.cs

@ -1,14 +1,67 @@
using System;
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Styling;
namespace ControlCatalog namespace ControlCatalog
{ {
public class App : Application 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() public override void Initialize()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
Styles.Insert(0, FluentDark);
} }
public override void OnFrameworkInitializationCompleted() public override void OnFrameworkInitializationCompleted()

9
samples/ControlCatalog/MainView.xaml

@ -29,7 +29,8 @@
ScrollViewer.HorizontalScrollBarVisibility="Disabled"> ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<pages:DataGridPage/> <pages:DataGridPage/>
</TabItem> </TabItem>
<TabItem Header="DatePicker"><pages:DatePickerPage/></TabItem> <TabItem Header="CalendarDatePicker">
<pages:CalendarDatePickerPage/></TabItem>
<TabItem Header="Drag+Drop"><pages:DragAndDropPage/></TabItem> <TabItem Header="Drag+Drop"><pages:DragAndDropPage/></TabItem>
<TabItem Header="Expander"><pages:ExpanderPage/></TabItem> <TabItem Header="Expander"><pages:ExpanderPage/></TabItem>
<TabItem Header="Image" <TabItem Header="Image"
@ -67,8 +68,10 @@
<ComboBoxItem>Full Decorations</ComboBoxItem> <ComboBoxItem>Full Decorations</ComboBoxItem>
</ComboBox> </ComboBox>
<ComboBox x:Name="Themes" SelectedIndex="0"> <ComboBox x:Name="Themes" SelectedIndex="0">
<ComboBoxItem>Light</ComboBoxItem> <ComboBoxItem>Fluent - Dark</ComboBoxItem>
<ComboBoxItem>Dark</ComboBoxItem> <ComboBoxItem>Fluent - Light</ComboBoxItem>
<ComboBoxItem>Simple - Light</ComboBoxItem>
<ComboBoxItem>Simple - Dark</ComboBoxItem>
</ComboBox> </ComboBox>
<ComboBox x:Name="TransparencyLevels" SelectedIndex="0"> <ComboBox x:Name="TransparencyLevels" SelectedIndex="0">
<ComboBoxItem>None</ComboBoxItem> <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"); var themes = this.Find<ComboBox>("Themes");
themes.SelectionChanged += (sender, e) => themes.SelectionChanged += (sender, e) =>
{ {
switch (themes.SelectedIndex) switch (themes.SelectedIndex)
{ {
case 0: case 0:
Styles[0] = light; Application.Current.Styles[0] = App.FluentDark;
break; break;
case 1: 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; break;
} }
}; };
Styles.Add(light);
var decorations = this.Find<ComboBox>("Decorations"); var decorations = this.Find<ComboBox>("Decorations");
decorations.SelectionChanged += (sender, e) => decorations.SelectionChanged += (sender, e) =>

2
samples/ControlCatalog/MainWindow.xaml

@ -7,7 +7,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:ControlCatalog.ViewModels" xmlns:vm="clr-namespace:ControlCatalog.ViewModels"
xmlns:v="clr-namespace:ControlCatalog.Views" 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.Menu>
<NativeMenu> <NativeMenu>
<NativeMenuItem Header="File"> <NativeMenuItem Header="File">

6
samples/ControlCatalog/Pages/ButtonPage.xaml

@ -24,7 +24,11 @@
</Style> </Style>
</Button.Styles> </Button.Styles>
</Button> </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"> <StackPanel Orientation="Vertical" Spacing="8" Width="150">
<Button BorderThickness="0">No Border</Button> <Button BorderThickness="0">No Border</Button>

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

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

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

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

12
samples/ControlCatalog/Pages/NumericUpDownPage.xaml

@ -50,22 +50,22 @@
<TextBlock Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" Margin="2">Text:</TextBlock> <TextBlock Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" Margin="2">Text:</TextBlock>
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding #upDown.Text}" VerticalAlignment="Center" Margin="2" /> <TextBox Grid.Row="4" Grid.Column="1" Text="{Binding #upDown.Text}" VerticalAlignment="Center" Margin="2" />
</Grid> </Grid>
<Grid Grid.Row="0" Grid.Column="2" Margin="10,2,2,2" RowDefinitions="Auto,Auto,Auto,Auto,Auto" ColumnDefinitions="Auto, 120"> <Grid Grid.Row="0" Grid.Column="2" Margin="10,2,2,2" RowDefinitions="Auto,Auto,Auto,Auto,Auto" ColumnDefinitions="Auto, Auto">
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Minimum:</TextBlock> <TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Minimum:</TextBlock>
<NumericUpDown Grid.Row="0" Grid.Column="1" Value="{Binding #upDown.Minimum}" <NumericUpDown Grid.Row="0" Grid.Column="1" Value="{Binding #upDown.Minimum}"
CultureInfo="{Binding #upDown.CultureInfo}" VerticalAlignment="Center" Margin="2" Width="70" HorizontalAlignment="Center"/> CultureInfo="{Binding #upDown.CultureInfo}" VerticalAlignment="Center" Margin="2" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Maximum:</TextBlock> <TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Maximum:</TextBlock>
<NumericUpDown Grid.Row="1" Grid.Column="1" Value="{Binding #upDown.Maximum}" <NumericUpDown Grid.Row="1" Grid.Column="1" Value="{Binding #upDown.Maximum}"
CultureInfo="{Binding #upDown.CultureInfo}" VerticalAlignment="Center" Margin="2" Width="70" HorizontalAlignment="Center"/> CultureInfo="{Binding #upDown.CultureInfo}" VerticalAlignment="Center" Margin="2" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Increment:</TextBlock> <TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Increment:</TextBlock>
<NumericUpDown Grid.Row="2" Grid.Column="1" Value="{Binding #upDown.Increment}" VerticalAlignment="Center" <NumericUpDown Grid.Row="2" Grid.Column="1" Value="{Binding #upDown.Increment}" VerticalAlignment="Center"
Margin="2" Width="70" HorizontalAlignment="Center"/> Margin="2" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Value:</TextBlock> <TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Value:</TextBlock>
<NumericUpDown Grid.Row="3" Grid.Column="1" Value="{Binding #upDown.Value}" VerticalAlignment="Center" <NumericUpDown Grid.Row="3" Grid.Column="1" Value="{Binding #upDown.Value}" VerticalAlignment="Center"
Margin="2" Width="70" HorizontalAlignment="Center"/> Margin="2" HorizontalAlignment="Center"/>
</Grid> </Grid>
</Grid> </Grid>
@ -73,7 +73,7 @@
<StackPanel Margin="2,10,2,2" Orientation="Horizontal" Spacing="10"> <StackPanel Margin="2,10,2,2" Orientation="Horizontal" Spacing="10">
<TextBlock FontSize="14" FontWeight="Bold" VerticalAlignment="Center">Usage of NumericUpDown:</TextBlock> <TextBlock FontSize="14" FontWeight="Bold" VerticalAlignment="Center">Usage of NumericUpDown:</TextBlock>
<NumericUpDown Name="upDown" Minimum="0" Maximum="10" Increment="0.5" <NumericUpDown Name="upDown" Minimum="0" Maximum="10" Increment="0.5"
CultureInfo="en-US" VerticalAlignment="Center" Width="100" CultureInfo="en-US" VerticalAlignment="Center"
Watermark="Enter text" FormatString="{Binding SelectedFormat.Value}"/> Watermark="Enter text" FormatString="{Binding SelectedFormat.Value}"/>
</StackPanel> </StackPanel>

2
samples/ControlCatalog/Pages/SliderPage.xaml

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

1
samples/ControlCatalog/Pages/TreeViewPage.xaml

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

11
samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs

@ -23,12 +23,14 @@ namespace ControlCatalog.ViewModels
AddItemCommand = ReactiveCommand.Create(AddItem); AddItemCommand = ReactiveCommand.Create(AddItem);
RemoveItemCommand = ReactiveCommand.Create(RemoveItem); RemoveItemCommand = ReactiveCommand.Create(RemoveItem);
SelectRandomItemCommand = ReactiveCommand.Create(SelectRandomItem);
} }
public ObservableCollection<Node> Items { get; } public ObservableCollection<Node> Items { get; }
public SelectionModel Selection { get; } public SelectionModel Selection { get; }
public ReactiveCommand<Unit, Unit> AddItemCommand { get; } public ReactiveCommand<Unit, Unit> AddItemCommand { get; }
public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; } public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; }
public ReactiveCommand<Unit, Unit> SelectRandomItemCommand { get; }
public SelectionMode SelectionMode 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) private void SelectionChanged(object sender, SelectionModelSelectionChangedEventArgs e)
{ {
var selected = string.Join(",", e.SelectedIndices); 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); 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();
} }
} }

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

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

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

@ -1,13 +1,16 @@
using System; using System;
using System.Linq; using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
namespace Avalonia.Data.Core.Plugins namespace Avalonia.Data.Core.Plugins
{ {
class MethodAccessorPlugin : IPropertyAccessorPlugin public class MethodAccessorPlugin : IPropertyAccessorPlugin
{ {
public bool Match(object obj, string methodName) private readonly Dictionary<(Type, string), MethodInfo> _methodLookup =
=> obj.GetType().GetRuntimeMethods().Any(x => x.Name == methodName); 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) public IPropertyAccessor Start(WeakReference<object> reference, string methodName)
{ {
@ -15,17 +18,22 @@ namespace Avalonia.Data.Core.Plugins
Contract.Requires<ArgumentNullException>(methodName != null); Contract.Requires<ArgumentNullException>(methodName != null);
reference.TryGetTarget(out object instance); 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 != 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 PropertyError(new BindingNotification(exception, BindingErrorType.Error));
} }
return new Accessor(reference, method); return new Accessor(reference, method, parameters);
} }
else 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 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>(reference != null);
Contract.Requires<ArgumentNullException>(method != null); Contract.Requires<ArgumentNullException>(method != null);
var paramTypes = method.GetParameters().Select(param => param.ParameterType).ToArray();
var returnType = method.ReturnType; var returnType = method.ReturnType;
bool hasReturn = returnType != typeof(void);
if (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) ParameterInfo parameter = parameters[i];
{
PropertyType = typeof(Action); paramTypes[i] = parameter.ParameterType;
} }
else
{ if (hasReturn)
PropertyType = Type.GetType($"System.Action`{paramTypes.Length}").MakeGenericType(paramTypes); {
} paramTypes[paramTypes.Length - 1] = returnType;
PropertyType = Expression.GetFuncType(paramTypes);
} }
else else
{ {
var genericTypeParameters = paramTypes.Concat(new[] { returnType }).ToArray(); PropertyType = Expression.GetActionType(paramTypes);
PropertyType = Type.GetType($"System.Func`{genericTypeParameters.Length}").MakeGenericType(genericTypeParameters);
} }
if (method.IsStatic) if (method.IsStatic)

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

@ -62,8 +62,13 @@ namespace Avalonia.Data.Core
if (accessor == null) if (accessor == null)
{ {
throw new NotSupportedException( reference.TryGetTarget(out object instance);
$"Could not find a matching property accessor for {PropertyName}.");
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; _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: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Data.Converters")]
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.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> /// </summary>
public static class MathUtilities 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> /// <summary>
/// AreClose - Returns whether or not two doubles are "close". That is, whether or /// AreClose - Returns whether or not two doubles are "close". That is, whether or
/// not they are within epsilon of each other. /// 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) //in case they are Infinities (then epsilon check does not work)
if (value1 == value2) return true; 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; double delta = value1 - value2;
return (-eps < delta) && (eps > delta); 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> /// <summary>
/// LessThan - Returns whether or not the first double is less than the second double. /// 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 /// 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); 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> /// <summary>
/// GreaterThan - Returns whether or not the first double is greater than the second double. /// 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 /// 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); 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> /// <summary>
/// LessThanOrClose - Returns whether or not the first double is less than or close to /// 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 /// 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); 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> /// <summary>
/// GreaterThanOrClose - Returns whether or not the first double is greater than or close to /// 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 /// 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); 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> /// <summary>
/// IsOne - Returns whether or not the double is "close" to 1. Same as AreClose(double, 1), /// IsOne - Returns whether or not the double is "close" to 1. Same as AreClose(double, 1),
/// but this is faster. /// but this is faster.
@ -78,7 +146,17 @@ namespace Avalonia.Utilities
/// <param name="value"> The double to compare to 1. </param> /// <param name="value"> The double to compare to 1. </param>
public static bool IsOne(double value) 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> /// <summary>
@ -88,7 +166,17 @@ namespace Avalonia.Utilities
/// <param name="value"> The double to compare to 0. </param> /// <param name="value"> The double to compare to 0. </param>
public static bool IsZero(double value) 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> /// <summary>

21
src/Avalonia.Controls/AutoCompleteBox.cs

@ -468,10 +468,11 @@ namespace Avalonia.Controls
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.Text" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.Text" />
/// dependency property.</value> /// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, string> TextProperty = public static readonly DirectProperty<AutoCompleteBox, string> TextProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, string>( TextBlock.TextProperty.AddOwnerWithDataValidation<AutoCompleteBox>(
nameof(Text),
o => o.Text, o => o.Text,
(o, v) => o.Text = v); (o, v) => o.Text = v,
defaultBindingMode: BindingMode.TwoWay,
enableDataValidation: true);
/// <summary> /// <summary>
/// Identifies the /// Identifies the
@ -1244,6 +1245,20 @@ namespace Avalonia.Controls
base.OnApplyTemplate(e); 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> /// <summary>
/// Provides handling for the /// Provides handling for the

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

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

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

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

167
src/Avalonia.Controls/ContextMenu.cs

@ -1,17 +1,18 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq;
using Avalonia.Controls.Generators; using Avalonia.Controls.Generators;
using Avalonia.Controls.Platform; using Avalonia.Controls.Platform;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.LogicalTree;
using Avalonia.Styling; using Avalonia.Styling;
#nullable enable
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
@ -19,11 +20,59 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public class ContextMenu : MenuBase, ISetterValue public class ContextMenu : MenuBase, ISetterValue
{ {
/// <summary>
/// Defines the <see cref="HorizontalOffset"/> property.
/// </summary>
public static readonly StyledProperty<double> HorizontalOffsetProperty =
Popup.HorizontalOffsetProperty.AddOwner<ContextMenu>();
/// <summary>
/// Defines the <see cref="VerticalOffset"/> property.
/// </summary>
public static readonly StyledProperty<double> VerticalOffsetProperty =
Popup.VerticalOffsetProperty.AddOwner<ContextMenu>();
/// <summary>
/// Defines the <see cref="PlacementAnchor"/> property.
/// </summary>
public static readonly StyledProperty<PopupAnchor> PlacementAnchorProperty =
Popup.PlacementAnchorProperty.AddOwner<ContextMenu>();
/// <summary>
/// Defines the <see cref="PlacementConstraintAdjustment"/> property.
/// </summary>
public static readonly StyledProperty<PopupPositionerConstraintAdjustment> PlacementConstraintAdjustmentProperty =
Popup.PlacementConstraintAdjustmentProperty.AddOwner<ContextMenu>();
/// <summary>
/// Defines the <see cref="PlacementGravity"/> property.
/// </summary>
public static readonly StyledProperty<PopupGravity> PlacementGravityProperty =
Popup.PlacementGravityProperty.AddOwner<ContextMenu>();
/// <summary>
/// Defines the <see cref="PlacementMode"/> property.
/// </summary>
public static readonly StyledProperty<PlacementMode> PlacementModeProperty =
Popup.PlacementModeProperty.AddOwner<ContextMenu>();
/// <summary>
/// Defines the <see cref="PlacementRect"/> property.
/// </summary>
public static readonly StyledProperty<Rect?> PlacementRectProperty =
AvaloniaProperty.Register<Popup, Rect?>(nameof(PlacementRect));
/// <summary>
/// Defines the <see cref="PlacementTarget"/> property.
/// </summary>
public static readonly StyledProperty<Control?> PlacementTargetProperty =
Popup.PlacementTargetProperty.AddOwner<ContextMenu>();
private static readonly ITemplate<IPanel> DefaultPanel = private static readonly ITemplate<IPanel> DefaultPanel =
new FuncTemplate<IPanel>(() => new StackPanel { Orientation = Orientation.Vertical }); new FuncTemplate<IPanel>(() => new StackPanel { Orientation = Orientation.Vertical });
private Popup _popup; private Popup? _popup;
private List<Control> _attachedControls; private List<Control>? _attachedControls;
private IInputElement _previousFocus; private IInputElement? _previousFocus;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContextMenu"/> class. /// Initializes a new instance of the <see cref="ContextMenu"/> class.
@ -47,23 +96,107 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
static ContextMenu() static ContextMenu()
{ {
ItemsPanelProperty.OverrideDefaultValue(typeof(ContextMenu), DefaultPanel); ItemsPanelProperty.OverrideDefaultValue<ContextMenu>(DefaultPanel);
PlacementModeProperty.OverrideDefaultValue<ContextMenu>(PlacementMode.Pointer);
ContextMenuProperty.Changed.Subscribe(ContextMenuChanged); ContextMenuProperty.Changed.Subscribe(ContextMenuChanged);
} }
/// <summary>
/// Gets or sets the Horizontal offset of the context menu in relation to the <see cref="PlacementTarget"/>.
/// </summary>
public double HorizontalOffset
{
get { return GetValue(HorizontalOffsetProperty); }
set { SetValue(HorizontalOffsetProperty, value); }
}
/// <summary>
/// Gets or sets the Vertical offset of the context menu in relation to the <see cref="PlacementTarget"/>.
/// </summary>
public double VerticalOffset
{
get { return GetValue(VerticalOffsetProperty); }
set { SetValue(VerticalOffsetProperty, value); }
}
/// <summary>
/// Gets or sets the anchor point on the <see cref="PlacementRect"/> when <see cref="PlacementMode"/>
/// is <see cref="PlacementMode.AnchorAndGravity"/>.
/// </summary>
public PopupAnchor PlacementAnchor
{
get { return GetValue(PlacementAnchorProperty); }
set { SetValue(PlacementAnchorProperty, value); }
}
/// <summary>
/// Gets or sets a value describing how the context menu position will be adjusted if the
/// unadjusted position would result in the context menu being partly constrained.
/// </summary>
public PopupPositionerConstraintAdjustment PlacementConstraintAdjustment
{
get { return GetValue(PlacementConstraintAdjustmentProperty); }
set { SetValue(PlacementConstraintAdjustmentProperty, value); }
}
/// <summary>
/// Gets or sets a value which defines in what direction the context menu should open
/// when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
/// </summary>
public PopupGravity PlacementGravity
{
get { return GetValue(PlacementGravityProperty); }
set { SetValue(PlacementGravityProperty, value); }
}
/// <summary>
/// Gets or sets the placement mode of the context menu in relation to the<see cref="PlacementTarget"/>.
/// </summary>
public PlacementMode PlacementMode
{
get { return GetValue(PlacementModeProperty); }
set { SetValue(PlacementModeProperty, value); }
}
/// <summary>
/// Gets or sets the the anchor rectangle within the parent that the context menu will be placed
/// relative to when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
/// </summary>
/// <remarks>
/// The placement rect defines a rectangle relative to <see cref="PlacementTarget"/> around
/// which the popup will be opened, with <see cref="PlacementAnchor"/> determining which edge
/// of the placement target is used.
///
/// If unset, the anchor rectangle will be the bounds of the <see cref="PlacementTarget"/>.
/// </remarks>
public Rect? PlacementRect
{
get { return GetValue(PlacementRectProperty); }
set { SetValue(PlacementRectProperty, value); }
}
/// <summary>
/// Gets or sets the control that is used to determine the popup's position.
/// </summary>
public Control? PlacementTarget
{
get { return GetValue(PlacementTargetProperty); }
set { SetValue(PlacementTargetProperty, value); }
}
/// <summary> /// <summary>
/// Occurs when the value of the /// Occurs when the value of the
/// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" /> /// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" />
/// property is changing from false to true. /// property is changing from false to true.
/// </summary> /// </summary>
public event CancelEventHandler ContextMenuOpening; public event CancelEventHandler? ContextMenuOpening;
/// <summary> /// <summary>
/// Occurs when the value of the /// Occurs when the value of the
/// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" /> /// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" />
/// property is changing from true to false. /// property is changing from true to false.
/// </summary> /// </summary>
public event CancelEventHandler ContextMenuClosing; public event CancelEventHandler? ContextMenuClosing;
/// <summary> /// <summary>
/// Called when the <see cref="Control.ContextMenu"/> property changes on a control. /// Called when the <see cref="Control.ContextMenu"/> property changes on a control.
@ -77,7 +210,7 @@ namespace Avalonia.Controls
{ {
control.PointerReleased -= ControlPointerReleased; control.PointerReleased -= ControlPointerReleased;
oldMenu._attachedControls?.Remove(control); oldMenu._attachedControls?.Remove(control);
((ISetLogicalParent)oldMenu._popup)?.SetParent(null); ((ISetLogicalParent?)oldMenu._popup)?.SetParent(null);
} }
if (e.NewValue is ContextMenu newMenu) if (e.NewValue is ContextMenu newMenu)
@ -97,7 +230,7 @@ namespace Avalonia.Controls
/// Opens a context menu on the specified control. /// Opens a context menu on the specified control.
/// </summary> /// </summary>
/// <param name="control">The control.</param> /// <param name="control">The control.</param>
public void Open(Control control) public void Open(Control? control)
{ {
if (control is null && (_attachedControls is null || _attachedControls.Count == 0)) if (control is null && (_attachedControls is null || _attachedControls.Count == 0))
{ {
@ -113,7 +246,7 @@ namespace Avalonia.Controls
nameof(control)); nameof(control));
} }
control ??= _attachedControls[0]; control ??= _attachedControls![0];
if (IsOpen) if (IsOpen)
{ {
@ -124,8 +257,14 @@ namespace Avalonia.Controls
{ {
_popup = new Popup _popup = new Popup
{ {
PlacementMode = PlacementMode.Pointer, HorizontalOffset = HorizontalOffset,
PlacementTarget = control, VerticalOffset = VerticalOffset,
PlacementAnchor = PlacementAnchor,
PlacementConstraintAdjustment = PlacementConstraintAdjustment,
PlacementGravity = PlacementGravity,
PlacementMode = PlacementMode,
PlacementRect = PlacementRect,
PlacementTarget = PlacementTarget ?? control,
StaysOpen = false StaysOpen = false
}; };
@ -204,7 +343,7 @@ namespace Avalonia.Controls
if (_attachedControls is null || _attachedControls.Count == 0) if (_attachedControls is null || _attachedControls.Count == 0)
{ {
((ISetLogicalParent)_popup).SetParent(null); ((ISetLogicalParent)_popup!).SetParent(null);
} }
// HACK: Reset the focus when the popup is closed. We need to fix this so it's automatic. // HACK: Reset the focus when the popup is closed. We need to fix this so it's automatic.

22
src/Avalonia.Controls/Converters/MarginMultiplierConverter.cs

@ -18,10 +18,24 @@ namespace Avalonia.Controls.Converters
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{ {
if (!(value is int depth)) if (value is int scalarDepth)
return new Thickness(0); {
return new Thickness(
return new Thickness(Left ? Indent * depth : 0, Top ? Indent * depth : 0, Right ? Indent * depth : 0, Bottom ? Indent * depth : 0); Left ? Indent * scalarDepth : 0,
Top ? Indent * scalarDepth : 0,
Right ? Indent * scalarDepth : 0,
Bottom ? Indent * scalarDepth : 0);
}
else if (value is Thickness thinknessDepth)
{
return new Thickness(
Left ? Indent * thinknessDepth.Left : 0,
Top ? Indent * thinknessDepth.Top : 0,
Right ? Indent * thinknessDepth.Right : 0,
Bottom ? Indent * thinknessDepth.Bottom : 0);
}
return new Thickness(0);
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

35
src/Avalonia.Controls/Grid.cs

@ -1228,7 +1228,7 @@ namespace Avalonia.Controls
Debug.Assert(1 < count && 0 <= start && (start + count) <= definitions.Count); Debug.Assert(1 < count && 0 <= start && (start + count) <= definitions.Count);
// avoid processing when asked to distribute "0" // 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 DefinitionBase[] tempDefinitions = TempDefinitions; // temp array used to remember definitions for sorting
int end = start + count; int end = start + count;
@ -1306,7 +1306,7 @@ namespace Avalonia.Controls
} }
// sanity check: requested size must all be distributed // sanity check: requested size must all be distributed
Debug.Assert(_IsZero(sizeToDistribute)); Debug.Assert(MathUtilities.IsZero(sizeToDistribute));
} }
else if (requestedSize <= rangeMaxSize) else if (requestedSize <= rangeMaxSize)
{ {
@ -1346,7 +1346,7 @@ namespace Avalonia.Controls
} }
// sanity check: requested size must all be distributed // sanity check: requested size must all be distributed
Debug.Assert(_IsZero(sizeToDistribute)); Debug.Assert(MathUtilities.IsZero(sizeToDistribute));
} }
else else
{ {
@ -1358,7 +1358,7 @@ namespace Avalonia.Controls
double equalSize = requestedSize / count; double equalSize = requestedSize / count;
if (equalSize < maxMaxSize if (equalSize < maxMaxSize
&& !_AreClose(equalSize, maxMaxSize)) && !MathUtilities.AreClose(equalSize, maxMaxSize))
{ {
// equi-size is less than maximum of maxSizes. // equi-size is less than maximum of maxSizes.
// in this case distribute so that smaller definitions grow faster than // 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 // and precision of floating-point computation. (However, the resulting
// display is subject to anti-aliasing problems. TANSTAAFL.) // display is subject to anti-aliasing problems. TANSTAAFL.)
if (!_AreClose(roundedTakenSize, finalSize)) if (!MathUtilities.AreClose(roundedTakenSize, finalSize))
{ {
// Compute deltas // Compute deltas
for (int i = 0; i < definitions.Count; ++i) for (int i = 0; i < definitions.Count; ++i)
@ -2168,7 +2168,7 @@ namespace Avalonia.Controls
if (roundedTakenSize > finalSize) if (roundedTakenSize > finalSize)
{ {
int i = definitions.Count - 1; 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]]; DefinitionBase definition = definitions[definitionIndices[i]];
double final = definition.SizeCache - dpiIncrement; double final = definition.SizeCache - dpiIncrement;
@ -2184,7 +2184,7 @@ namespace Avalonia.Controls
else if (roundedTakenSize < finalSize) else if (roundedTakenSize < finalSize)
{ {
int i = 0; 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]]; DefinitionBase definition = definitions[definitionIndices[i]];
double final = definition.SizeCache + dpiIncrement; double final = definition.SizeCache + dpiIncrement;
@ -2595,27 +2595,6 @@ namespace Avalonia.Controls
set { SetFlags(value, Flags.HasGroup3CellsInAutoRows); } 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> /// <summary>
/// Returns reference to extended data bag. /// Returns reference to extended data bag.
/// </summary> /// </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() public override string ToString()
{ {
if (_path != null) if (_path != null)

47
src/Avalonia.Controls/IndexRange.cs

@ -132,6 +132,53 @@ namespace Avalonia.Controls
return result; 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( public static int Remove(
IList<IndexRange> ranges, IList<IndexRange> ranges,
IndexRange range, IndexRange range,

5
src/Avalonia.Controls/MenuItem.cs

@ -105,6 +105,7 @@ namespace Avalonia.Controls
static MenuItem() static MenuItem()
{ {
SelectableMixin.Attach<MenuItem>(IsSelectedProperty); SelectableMixin.Attach<MenuItem>(IsSelectedProperty);
PressedMixin.Attach<MenuItem>();
CommandProperty.Changed.Subscribe(CommandChanged); CommandProperty.Changed.Subscribe(CommandChanged);
FocusableProperty.OverrideDefaultValue<MenuItem>(true); FocusableProperty.OverrideDefaultValue<MenuItem>(true);
HeaderProperty.Changed.AddClassHandler<MenuItem>((x, e) => x.HeaderChanged(e)); HeaderProperty.Changed.AddClassHandler<MenuItem>((x, e) => x.HeaderChanged(e));
@ -534,11 +535,13 @@ namespace Avalonia.Controls
if (oldValue != null) if (oldValue != null)
{ {
LogicalChildren.Remove(oldValue); LogicalChildren.Remove(oldValue);
PseudoClasses.Remove(":icon");
} }
if (newValue != null) if (newValue != null)
{ {
LogicalChildren.Add(newValue); LogicalChildren.Add(newValue);
PseudoClasses.Add(":icon");
} }
} }
@ -566,11 +569,13 @@ namespace Avalonia.Controls
{ {
RaiseEvent(new RoutedEventArgs(SubmenuOpenedEvent)); RaiseEvent(new RoutedEventArgs(SubmenuOpenedEvent));
IsSelected = true; IsSelected = true;
PseudoClasses.Add(":open");
} }
else else
{ {
CloseSubmenus(); CloseSubmenus();
SelectedIndex = -1; SelectedIndex = -1;
PseudoClasses.Remove(":open");
} }
} }

55
src/Avalonia.Controls/Primitives/IPopupHost.cs

@ -5,19 +5,70 @@ using Avalonia.VisualTree;
namespace Avalonia.Controls.Primitives namespace Avalonia.Controls.Primitives
{ {
/// <summary>
/// Represents the top-level control opened by a <see cref="Popup"/>.
/// </summary>
/// <remarks>
/// A popup host can be either be a popup window created by the operating system
/// (<see cref="PopupRoot"/>) or an <see cref="OverlayPopupHost"/> which is created
/// on an <see cref="OverlayLayer"/>.
/// </remarks>
public interface IPopupHost : IDisposable public interface IPopupHost : IDisposable
{ {
/// <summary>
/// Sets the control to display in the popup.
/// </summary>
/// <param name="control"></param>
void SetChild(IControl control); void SetChild(IControl control);
/// <summary>
/// Gets the presenter from the control's template.
/// </summary>
IContentPresenter Presenter { get; } IContentPresenter Presenter { get; }
/// <summary>
/// Gets the root of the visual tree in the case where the popup is presented using a
/// separate visual tree.
/// </summary>
IVisual HostedVisualTreeRoot { get; } IVisual HostedVisualTreeRoot { get; }
/// <summary>
/// Raised when the control's template is applied.
/// </summary>
event EventHandler<TemplateAppliedEventArgs> TemplateApplied; event EventHandler<TemplateAppliedEventArgs> TemplateApplied;
/// <summary>
/// Configures the position of the popup according to a target control and a set of
/// placement parameters.
/// </summary>
/// <param name="target">The placement target.</param>
/// <param name="placement">The placement mode.</param>
/// <param name="offset">The offset, in device-independent pixels.</param>
/// <param name="anchor">The anchor point.</param>
/// <param name="gravity">The popup gravity.</param>
/// <param name="rect">
/// The anchor rect. If null, the bounds of <paramref name="target"/> will be used.
/// </param>
void ConfigurePosition(IVisual target, PlacementMode placement, Point offset, void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
PopupPositioningEdge anchor = PopupPositioningEdge.None, PopupAnchor anchor = PopupAnchor.None,
PopupPositioningEdge gravity = PopupPositioningEdge.None); PopupGravity gravity = PopupGravity.None,
PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
Rect? rect = null);
/// <summary>
/// Shows the popup.
/// </summary>
void Show(); void Show();
/// <summary>
/// Hides the popup.
/// </summary>
void Hide(); void Hide();
/// <summary>
/// Binds the constraints of the popup host to a set of properties, usally those present on
/// <see cref="Popup"/>.
/// </summary>
IDisposable BindConstraints(AvaloniaObject popup, StyledProperty<double> widthProperty, IDisposable BindConstraints(AvaloniaObject popup, StyledProperty<double> widthProperty,
StyledProperty<double> minWidthProperty, StyledProperty<double> maxWidthProperty, StyledProperty<double> minWidthProperty, StyledProperty<double> maxWidthProperty,
StyledProperty<double> heightProperty, StyledProperty<double> minHeightProperty, StyledProperty<double> heightProperty, StyledProperty<double> minHeightProperty,

12
src/Avalonia.Controls/Primitives/OverlayPopupHost.cs

@ -71,10 +71,12 @@ namespace Avalonia.Controls.Primitives
} }
public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset, public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
PopupPositioningEdge anchor = PopupPositioningEdge.None, PopupPositioningEdge gravity = PopupPositioningEdge.None) PopupAnchor anchor = PopupAnchor.None, PopupGravity gravity = PopupGravity.None,
PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
Rect? rect = null)
{ {
_positionerParameters.ConfigurePosition((TopLevel)_overlayLayer.GetVisualRoot(), target, placement, offset, anchor, _positionerParameters.ConfigurePosition((TopLevel)_overlayLayer.GetVisualRoot(), target, placement, offset, anchor,
gravity); gravity, constraintAdjustment, rect);
UpdatePosition(); UpdatePosition();
} }
@ -122,10 +124,8 @@ namespace Avalonia.Controls.Primitives
}, DispatcherPriority.Layout); }, DispatcherPriority.Layout);
} }
Point IManagedPopupPositionerPopup.TranslatePoint(Point pt) => pt; double IManagedPopupPositionerPopup.Scaling => 1;
Size IManagedPopupPositionerPopup.TranslateSize(Size size) => size;
public static IPopupHost CreatePopupHost(IVisual target, IAvaloniaDependencyResolver dependencyResolver) public static IPopupHost CreatePopupHost(IVisual target, IAvaloniaDependencyResolver dependencyResolver)
{ {
var platform = (target.GetVisualRoot() as TopLevel)?.PlatformImpl?.CreatePopup(); var platform = (target.GetVisualRoot() as TopLevel)?.PlatformImpl?.CreatePopup();

117
src/Avalonia.Controls/Primitives/Popup.cs

@ -3,6 +3,7 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Avalonia.Controls.Presenters; using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@ -37,12 +38,45 @@ namespace Avalonia.Controls.Primitives
o => o.IsOpen, o => o.IsOpen,
(o, v) => o.IsOpen = v); (o, v) => o.IsOpen = v);
/// <summary>
/// Defines the <see cref="PlacementAnchor"/> property.
/// </summary>
public static readonly StyledProperty<PopupAnchor> PlacementAnchorProperty =
AvaloniaProperty.Register<Popup, PopupAnchor>(nameof(PlacementAnchor));
/// <summary>
/// Defines the <see cref="PlacementConstraintAdjustment"/> property.
/// </summary>
public static readonly StyledProperty<PopupPositionerConstraintAdjustment> PlacementConstraintAdjustmentProperty =
AvaloniaProperty.Register<Popup, PopupPositionerConstraintAdjustment>(
nameof(PlacementConstraintAdjustment),
PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY |
PopupPositionerConstraintAdjustment.ResizeX | PopupPositionerConstraintAdjustment.ResizeY);
/// <summary>
/// Defines the <see cref="PlacementGravity"/> property.
/// </summary>
public static readonly StyledProperty<PopupGravity> PlacementGravityProperty =
AvaloniaProperty.Register<Popup, PopupGravity>(nameof(PlacementGravity));
/// <summary> /// <summary>
/// Defines the <see cref="PlacementMode"/> property. /// Defines the <see cref="PlacementMode"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<PlacementMode> PlacementModeProperty = public static readonly StyledProperty<PlacementMode> PlacementModeProperty =
AvaloniaProperty.Register<Popup, PlacementMode>(nameof(PlacementMode), defaultValue: PlacementMode.Bottom); AvaloniaProperty.Register<Popup, PlacementMode>(nameof(PlacementMode), defaultValue: PlacementMode.Bottom);
/// <summary>
/// Defines the <see cref="PlacementRect"/> property.
/// </summary>
public static readonly StyledProperty<Rect?> PlacementRectProperty =
AvaloniaProperty.Register<Popup, Rect?>(nameof(PlacementRect));
/// <summary>
/// Defines the <see cref="PlacementTarget"/> property.
/// </summary>
public static readonly StyledProperty<Control?> PlacementTargetProperty =
AvaloniaProperty.Register<Popup, Control?>(nameof(PlacementTarget));
#pragma warning disable 618 #pragma warning disable 618
/// <summary> /// <summary>
/// Defines the <see cref="ObeyScreenEdges"/> property. /// Defines the <see cref="ObeyScreenEdges"/> property.
@ -63,12 +97,6 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<double> VerticalOffsetProperty = public static readonly StyledProperty<double> VerticalOffsetProperty =
AvaloniaProperty.Register<Popup, double>(nameof(VerticalOffset)); AvaloniaProperty.Register<Popup, double>(nameof(VerticalOffset));
/// <summary>
/// Defines the <see cref="PlacementTarget"/> property.
/// </summary>
public static readonly StyledProperty<Control?> PlacementTargetProperty =
AvaloniaProperty.Register<Popup, Control?>(nameof(PlacementTarget));
/// <summary> /// <summary>
/// Defines the <see cref="StaysOpen"/> property. /// Defines the <see cref="StaysOpen"/> property.
/// </summary> /// </summary>
@ -145,6 +173,36 @@ namespace Avalonia.Controls.Primitives
set { SetAndRaise(IsOpenProperty, ref _isOpen, value); } set { SetAndRaise(IsOpenProperty, ref _isOpen, value); }
} }
/// <summary>
/// Gets or sets the anchor point on the <see cref="PlacementRect"/> when <see cref="PlacementMode"/>
/// is <see cref="PlacementMode.AnchorAndGravity"/>.
/// </summary>
public PopupAnchor PlacementAnchor
{
get { return GetValue(PlacementAnchorProperty); }
set { SetValue(PlacementAnchorProperty, value); }
}
/// <summary>
/// Gets or sets a value describing how the popup position will be adjusted if the
/// unadjusted position would result in the popup being partly constrained.
/// </summary>
public PopupPositionerConstraintAdjustment PlacementConstraintAdjustment
{
get { return GetValue(PlacementConstraintAdjustmentProperty); }
set { SetValue(PlacementConstraintAdjustmentProperty, value); }
}
/// <summary>
/// Gets or sets a value which defines in what direction the popup should open
/// when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
/// </summary>
public PopupGravity PlacementGravity
{
get { return GetValue(PlacementGravityProperty); }
set { SetValue(PlacementGravityProperty, value); }
}
/// <summary> /// <summary>
/// Gets or sets the placement mode of the popup in relation to the <see cref="PlacementTarget"/>. /// Gets or sets the placement mode of the popup in relation to the <see cref="PlacementTarget"/>.
/// </summary> /// </summary>
@ -154,6 +212,32 @@ namespace Avalonia.Controls.Primitives
set { SetValue(PlacementModeProperty, value); } set { SetValue(PlacementModeProperty, value); }
} }
/// <summary>
/// Gets or sets the the anchor rectangle within the parent that the popup will be placed
/// relative to when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
/// </summary>
/// <remarks>
/// The placement rect defines a rectangle relative to <see cref="PlacementTarget"/> around
/// which the popup will be opened, with <see cref="PlacementAnchor"/> determining which edge
/// of the placement target is used.
///
/// If unset, the anchor rectangle will be the bounds of the <see cref="PlacementTarget"/>.
/// </remarks>
public Rect? PlacementRect
{
get { return GetValue(PlacementRectProperty); }
set { SetValue(PlacementRectProperty, value); }
}
/// <summary>
/// Gets or sets the control that is used to determine the popup's position.
/// </summary>
public Control? PlacementTarget
{
get { return GetValue(PlacementTargetProperty); }
set { SetValue(PlacementTargetProperty, value); }
}
[Obsolete("This property has no effect")] [Obsolete("This property has no effect")]
public bool ObeyScreenEdges public bool ObeyScreenEdges
{ {
@ -162,7 +246,7 @@ namespace Avalonia.Controls.Primitives
} }
/// <summary> /// <summary>
/// Gets or sets the Horizontal offset of the popup in relation to the <see cref="PlacementTarget"/> /// Gets or sets the Horizontal offset of the popup in relation to the <see cref="PlacementTarget"/>.
/// </summary> /// </summary>
public double HorizontalOffset public double HorizontalOffset
{ {
@ -171,7 +255,7 @@ namespace Avalonia.Controls.Primitives
} }
/// <summary> /// <summary>
/// Gets or sets the Vertical offset of the popup in relation to the <see cref="PlacementTarget"/> /// Gets or sets the Vertical offset of the popup in relation to the <see cref="PlacementTarget"/>.
/// </summary> /// </summary>
public double VerticalOffset public double VerticalOffset
{ {
@ -179,15 +263,6 @@ namespace Avalonia.Controls.Primitives
set { SetValue(VerticalOffsetProperty, value); } set { SetValue(VerticalOffsetProperty, value); }
} }
/// <summary>
/// Gets or sets the control that is used to determine the popup's position.
/// </summary>
public Control? PlacementTarget
{
get { return GetValue(PlacementTargetProperty); }
set { SetValue(PlacementTargetProperty, value); }
}
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the popup should stay open when the popup is /// Gets or sets a value indicating whether the popup should stay open when the popup is
/// pressed or loses focus. /// pressed or loses focus.
@ -260,8 +335,12 @@ namespace Avalonia.Controls.Primitives
popupHost.ConfigurePosition( popupHost.ConfigurePosition(
placementTarget, placementTarget,
PlacementMode, PlacementMode,
new Point(HorizontalOffset, VerticalOffset)); new Point(HorizontalOffset, VerticalOffset),
PlacementAnchor,
PlacementGravity,
PlacementConstraintAdjustment,
PlacementRect);
DeferCleanup(SubscribeToEventHandler<IPopupHost, EventHandler<TemplateAppliedEventArgs>>(popupHost, RootTemplateApplied, DeferCleanup(SubscribeToEventHandler<IPopupHost, EventHandler<TemplateAppliedEventArgs>>(popupHost, RootTemplateApplied,
(x, handler) => x.TemplateApplied += handler, (x, handler) => x.TemplateApplied += handler,

424
src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs

@ -50,46 +50,48 @@ using Avalonia.VisualTree;
namespace Avalonia.Controls.Primitives.PopupPositioning namespace Avalonia.Controls.Primitives.PopupPositioning
{ {
/// <summary> /// <summary>
/// /// Provides positioning parameters to <see cref="IPopupPositioner"/>.
/// The IPopupPositioner provides a collection of rules for the placement of a
/// a popup relative to its parent. Rules can be defined to ensure
/// the popup remains within the visible area's borders, and to
/// specify how the popup changes its position, such as sliding along
/// an axis, or flipping around a rectangle. These positioner-created rules are
/// constrained by the requirement that a popup must intersect with or
/// be at least partially adjacent to its parent surface.
/// </summary> /// </summary>
/// <remarks>
/// The IPopupPositioner provides a collection of rules for the placement of a a popup relative
/// to its parent. Rules can be defined to ensure the popup remains within the visible area's
/// borders, and to specify how the popup changes its position, such as sliding along an axis,
/// or flipping around a rectangle. These positioner-created rules are constrained by the
/// requirement that a popup must intersect with or be at least partially adjacent to its parent
/// surface.
/// </remarks>
public struct PopupPositionerParameters public struct PopupPositionerParameters
{ {
private PopupPositioningEdge _gravity; private PopupGravity _gravity;
private PopupPositioningEdge _anchor; private PopupAnchor _anchor;
/// <summary> /// <summary>
/// Set the size of the popup that is to be positioned with the positioner /// Set the size of the popup that is to be positioned with the positioner object, in device-
/// object. The size is in scaled coordinates. /// independent pixels.
/// </summary> /// </summary>
public Size Size { get; set; } public Size Size { get; set; }
/// <summary> /// <summary>
/// Specify the anchor rectangle within the parent that the popup /// Specifies the anchor rectangle within the parent that the popup will be placed relative
/// will be placed relative to. The rectangle is relative to the /// to, in device-independent pixels.
/// parent geometry
///
/// The anchor rectangle may not extend outside the window geometry of the
/// popup's parent. The anchor rectangle is in scaled coordinates
/// </summary> /// </summary>
/// <remarks>
/// The rectangle is relative to the parent geometry and may not extend outside the window
/// geometry of the popup's parent.
/// </remarks>
public Rect AnchorRectangle { get; set; } public Rect AnchorRectangle { get; set; }
/// <summary> /// <summary>
/// Defines the anchor point for the anchor rectangle. The specified anchor /// Defines the anchor point for the anchor rectangle.
/// is used derive an anchor point that the popup will be
/// positioned relative to. If a corner anchor is set (e.g. 'TopLeft' or
/// 'BottomRight'), the anchor point will be at the specified corner;
/// otherwise, the derived anchor point will be centered on the specified
/// edge, or in the center of the anchor rectangle if no edge is specified.
/// </summary> /// </summary>
public PopupPositioningEdge Anchor /// <remarks>
/// The specified anchor is used derive an anchor point that the popup will be positioned
/// relative to. If a corner anchor is set (e.g. 'TopLeft' or 'BottomRight'), the anchor
/// point will be at the specified corner; otherwise, the derived anchor point will be
/// centered on the specified edge, or in the center of the anchor rectangle if no edge is
/// specified.
/// </remarks>
public PopupAnchor Anchor
{ {
get => _anchor; get => _anchor;
set set
@ -100,66 +102,70 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
} }
/// <summary> /// <summary>
/// Defines in what direction a popup should be positioned, relative to /// Defines in what direction a popup should be positioned, relative to the anchor point of
/// the anchor point of the parent. If a corner gravity is /// the parent.
/// specified (e.g. 'BottomRight' or 'TopLeft'), then the popup
/// will be placed towards the specified gravity; otherwise, the popup
/// will be centered over the anchor point on any axis that had no
/// gravity specified.
/// </summary> /// </summary>
public PopupPositioningEdge Gravity /// <remarks>
/// If a corner gravity is specified (e.g. 'BottomRight' or 'TopLeft'), then the popup will
/// be placed towards the specified gravity; otherwise, the popup will be centered over the
/// anchor point on any axis that had no gravity specified.
/// </remarks>
public PopupGravity Gravity
{ {
get => _gravity; get => _gravity;
set set
{ {
PopupPositioningEdgeHelper.ValidateEdge(value); PopupPositioningEdgeHelper.ValidateGravity(value);
_gravity = value; _gravity = value;
} }
} }
/// <summary> /// <summary>
/// Specify how the popup should be positioned if the originally intended /// Specify how the popup should be positioned if the originally intended position caused
/// position caused the popup to be constrained, meaning at least /// the popup to be constrained.
/// partially outside positioning boundaries set by the positioner. The /// </summary>
/// adjustment is set by constructing a bitmask describing the adjustment to /// <remarks>
/// be made when the popup is constrained on that axis. /// Adjusts the popup position if the intended position caused the popup to be constrained;
/// meaning at least partially outside positioning boundaries set by the positioner. The
/// adjustment is set by constructing a bitmask describing the adjustment to be made when
/// the popup is constrained on that axis.
/// ///
/// If no bit for one axis is set, the positioner will assume that the child /// If no bit for one axis is set, the positioner will assume that the child surface should
/// surface should not change its position on that axis when constrained. /// not change its position on that axis when constrained.
/// ///
/// If more than one bit for one axis is set, the order of how adjustments /// If more than one bit for one axis is set, the order of how adjustments are applied is
/// are applied is specified in the corresponding adjustment descriptions. /// specified in the corresponding adjustment descriptions.
/// ///
/// The default adjustment is none. /// The default adjustment is none.
/// </summary> /// </remarks>
public PopupPositionerConstraintAdjustment ConstraintAdjustment { get; set; } public PopupPositionerConstraintAdjustment ConstraintAdjustment { get; set; }
/// <summary> /// <summary>
/// Specify the popup position offset relative to the position of the /// Specify the popup position offset relative to the position of the
/// anchor on the anchor rectangle and the anchor on the popup. For /// anchor on the anchor rectangle and the anchor on the popup.
/// example if the anchor of the anchor rectangle is at (x, y), the popup
/// has the gravity bottom|right, and the offset is (ox, oy), the calculated
/// surface position will be (x + ox, y + oy). The offset position of the
/// surface is the one used for constraint testing. See
/// set_constraint_adjustment.
///
/// An example use case is placing a popup menu on top of a user interface
/// element, while aligning the user interface element of the parent surface
/// with some user interface element placed somewhere in the popup.
/// </summary> /// </summary>
/// <remarks>
/// For example if the anchor of the anchor rectangle is at (x, y), the popup has the
/// gravity bottom|right, and the offset is (ox, oy), the calculated surface position will
/// be (x + ox, y + oy). The offset position of the surface is the one used for constraint
/// testing. See set_constraint_adjustment.
///
/// An example use case is placing a popup menu on top of a user interface element, while
/// aligning the user interface element of the parent surface with some user interface
/// element placed somewhere in the popup.
/// </remarks>
public Point Offset { get; set; } public Point Offset { get; set; }
} }
/// <summary> /// <summary>
/// The constraint adjustment value define ways how popup position will /// Defines how a popup position will be adjusted if the unadjusted position would result in
/// be adjusted if the unadjusted position would result in the popup /// the popup being partly constrained.
/// being partly constrained.
///
/// Whether a popup is considered 'constrained' is left to the positioner
/// to determine. For example, the popup may be partly outside the
/// target platform defined 'work area', thus necessitating the popup's
/// position be adjusted until it is entirely inside the work area.
/// </summary> /// </summary>
/// <remarks>
/// Whether a popup is considered 'constrained' is left to the positioner to determine. For
/// example, the popup may be partly outside the target platform defined 'work area', thus
/// necessitating the popup's position be adjusted until it is entirely inside the work area.
/// </remarks>
[Flags] [Flags]
public enum PopupPositionerConstraintAdjustment public enum PopupPositionerConstraintAdjustment
{ {
@ -171,79 +177,97 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
/// <summary> /// <summary>
/// Slide the surface along the x axis until it is no longer constrained. /// Slide the surface along the x axis until it is no longer constrained.
/// First try to slide towards the direction of the gravity on the x axis
/// until either the edge in the opposite direction of the gravity is
/// unconstrained or the edge in the direction of the gravity is
/// constrained.
///
/// Then try to slide towards the opposite direction of the gravity on the
/// x axis until either the edge in the direction of the gravity is
/// unconstrained or the edge in the opposite direction of the gravity is
/// constrained.
/// </summary> /// </summary>
/// <remarks>
/// First try to slide towards the direction of the gravity on the x axis until either the
/// edge in the opposite direction of the gravity is unconstrained or the edge in the
/// direction of the gravity is constrained.
///
/// Then try to slide towards the opposite direction of the gravity on the x axis until
/// either the edge in the direction of the gravity is unconstrained or the edge in the
/// opposite direction of the gravity is constrained.
/// </remarks>
SlideX = 1, SlideX = 1,
/// <summary> /// <summary>
/// Slide the surface along the y axis until it is no longer constrained. /// Slide the surface along the y axis until it is no longer constrained.
///
/// First try to slide towards the direction of the gravity on the y axis
/// until either the edge in the opposite direction of the gravity is
/// unconstrained or the edge in the direction of the gravity is
/// constrained.
///
/// Then try to slide towards the opposite direction of the gravity on the
/// y axis until either the edge in the direction of the gravity is
/// unconstrained or the edge in the opposite direction of the gravity is
/// constrained.
/// */
/// </summary> /// </summary>
/// <remarks>
/// First try to slide towards the direction of the gravity on the y axis until either the
/// edge in the opposite direction of the gravity is unconstrained or the edge in the
/// direction of the gravity is constrained.
///
/// Then try to slide towards the opposite direction of the gravity on the y axis until
/// either the edge in the direction of the gravity is unconstrained or the edge in the
/// opposite direction of the gravity is constrained.
/// </remarks>
SlideY = 2, SlideY = 2,
/// <summary> /// <summary>
/// Invert the anchor and gravity on the x axis if the surface is /// Invert the anchor and gravity on the x axis if the surface is constrained on the x axis.
/// constrained on the x axis. For example, if the left edge of the
/// surface is constrained, the gravity is 'left' and the anchor is
/// 'left', change the gravity to 'right' and the anchor to 'right'.
///
/// If the adjusted position also ends up being constrained, the resulting
/// position of the flip_x adjustment will be the one before the
/// adjustment.
/// </summary> /// </summary>
/// <remarks>
/// For example, if the left edge of the surface is constrained, the gravity is 'left' and
/// the anchor is 'left', change the gravity to 'right' and the anchor to 'right'.
///
/// If the adjusted position also ends up being constrained, the resulting position of the
/// FlipX adjustment will be the one before the adjustment.
/// /// </remarks>
FlipX = 4, FlipX = 4,
/// <summary> /// <summary>
/// Invert the anchor and gravity on the y axis if the surface is /// Invert the anchor and gravity on the y axis if the surface is constrained on the y axis.
/// constrained on the y axis. For example, if the bottom edge of the /// </summary>
/// surface is constrained, the gravity is 'bottom' and the anchor is /// <remarks>
/// 'bottom', change the gravity to 'top' and the anchor to 'top'. /// For example, if the bottom edge of the surface is constrained, the gravity is 'bottom'
/// and the anchor is 'bottom', change the gravity to 'top' and the anchor to 'top'.
/// ///
/// The adjusted position is calculated given the original anchor /// The adjusted position is calculated given the original anchor rectangle and offset, but
/// rectangle and offset, but with the new flipped anchor and gravity /// with the new flipped anchor and gravity values.
/// values.
/// ///
/// If the adjusted position also ends up being constrained, the resulting /// If the adjusted position also ends up being constrained, the resulting position of the
/// position of the flip_y adjustment will be the one before the /// FlipY adjustment will be the one before the adjustment.
/// adjustment. /// </remarks>
/// </summary>
FlipY = 8, FlipY = 8,
All = SlideX|SlideY|FlipX|FlipY
/// <summary>
/// Horizontally resize the surface
/// </summary>
/// <remarks>
/// Resize the surface horizontally so that it is completely unconstrained.
/// </remarks>
ResizeX = 16,
/// <summary>
/// Vertically resize the surface
/// </summary>
/// <remarks>
/// Resize the surface vertically so that it is completely unconstrained.
/// </remarks>
ResizeY = 16,
All = SlideX|SlideY|FlipX|FlipY|ResizeX|ResizeY
} }
static class PopupPositioningEdgeHelper static class PopupPositioningEdgeHelper
{ {
public static void ValidateEdge(this PopupPositioningEdge edge) public static void ValidateEdge(this PopupAnchor edge)
{ {
if (((edge & PopupPositioningEdge.Left) != 0 && (edge & PopupPositioningEdge.Right) != 0) if (((edge & PopupAnchor.Left) != 0 && (edge & PopupAnchor.Right) != 0)
|| ||
((edge & PopupPositioningEdge.Top) != 0 && (edge & PopupPositioningEdge.Bottom) != 0)) ((edge & PopupAnchor.Top) != 0 && (edge & PopupAnchor.Bottom) != 0))
throw new ArgumentException("Opposite edges specified"); throw new ArgumentException("Opposite edges specified");
} }
public static PopupPositioningEdge Flip(this PopupPositioningEdge edge) public static void ValidateGravity(this PopupGravity gravity)
{
ValidateEdge((PopupAnchor)gravity);
}
public static PopupAnchor Flip(this PopupAnchor edge)
{ {
var hmask = PopupPositioningEdge.Left | PopupPositioningEdge.Right; var hmask = PopupAnchor.Left | PopupAnchor.Right;
var vmask = PopupPositioningEdge.Top | PopupPositioningEdge.Bottom; var vmask = PopupAnchor.Top | PopupAnchor.Bottom;
if ((edge & hmask) != 0) if ((edge & hmask) != 0)
edge ^= hmask; edge ^= hmask;
if ((edge & vmask) != 0) if ((edge & vmask) != 0)
@ -251,43 +275,167 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
return edge; return edge;
} }
public static PopupPositioningEdge FlipX(this PopupPositioningEdge edge) public static PopupAnchor FlipX(this PopupAnchor edge)
{ {
if ((edge & PopupPositioningEdge.HorizontalMask) != 0) if ((edge & PopupAnchor.HorizontalMask) != 0)
edge ^= PopupPositioningEdge.HorizontalMask; edge ^= PopupAnchor.HorizontalMask;
return edge; return edge;
} }
public static PopupPositioningEdge FlipY(this PopupPositioningEdge edge) public static PopupAnchor FlipY(this PopupAnchor edge)
{ {
if ((edge & PopupPositioningEdge.VerticalMask) != 0) if ((edge & PopupAnchor.VerticalMask) != 0)
edge ^= PopupPositioningEdge.VerticalMask; edge ^= PopupAnchor.VerticalMask;
return edge; return edge;
} }
public static PopupGravity FlipX(this PopupGravity gravity)
{
return (PopupGravity)FlipX((PopupAnchor)gravity);
}
public static PopupGravity FlipY(this PopupGravity gravity)
{
return (PopupGravity)FlipY((PopupAnchor)gravity);
}
} }
/// <summary>
/// Defines the edges around an anchor rectangle on which a popup will open.
/// </summary>
[Flags] [Flags]
public enum PopupPositioningEdge public enum PopupAnchor
{ {
/// <summary>
/// The center of the anchor rectangle.
/// </summary>
None, None,
/// <summary>
/// The top edge of the anchor rectangle.
/// </summary>
Top = 1, Top = 1,
/// <summary>
/// The bottom edge of the anchor rectangle.
/// </summary>
Bottom = 2, Bottom = 2,
/// <summary>
/// The left edge of the anchor rectangle.
/// </summary>
Left = 4, Left = 4,
/// <summary>
/// The right edge of the anchor rectangle.
/// </summary>
Right = 8, Right = 8,
/// <summary>
/// The top-left corner of the anchor rectangle.
/// </summary>
TopLeft = Top | Left, TopLeft = Top | Left,
/// <summary>
/// The top-right corner of the anchor rectangle.
/// </summary>
TopRight = Top | Right, TopRight = Top | Right,
/// <summary>
/// The bottom-left corner of the anchor rectangle.
/// </summary>
BottomLeft = Bottom | Left, BottomLeft = Bottom | Left,
/// <summary>
/// The bottom-right corner of the anchor rectangle.
/// </summary>
BottomRight = Bottom | Right, BottomRight = Bottom | Right,
/// <summary>
/// A mask for the vertical component flags.
/// </summary>
VerticalMask = Top | Bottom, VerticalMask = Top | Bottom,
/// <summary>
/// A mask for the horizontal component flags.
/// </summary>
HorizontalMask = Left | Right, HorizontalMask = Left | Right,
/// <summary>
/// A mask for all flags.
/// </summary>
AllMask = VerticalMask|HorizontalMask AllMask = VerticalMask|HorizontalMask
} }
/// <summary>
/// Defines the direction in which a popup will open.
/// </summary>
[Flags]
public enum PopupGravity
{
/// <summary>
/// The popup will be centered over the anchor edge.
/// </summary>
None,
/// <summary>
/// The popup will be positioned above the anchor edge
/// </summary>
Top = 1,
/// <summary>
/// The popup will be positioned below the anchor edge
/// </summary>
Bottom = 2,
/// <summary>
/// The popup will be positioned to the left of the anchor edge
/// </summary>
Left = 4,
/// <summary>
/// The popup will be positioned to the right of the anchor edge
/// </summary>
Right = 8,
/// <summary>
/// The popup will be positioned to the top-left of the anchor edge
/// </summary>
TopLeft = Top | Left,
/// <summary>
/// The popup will be positioned to the top-right of the anchor edge
/// </summary>
TopRight = Top | Right,
/// <summary>
/// The popup will be positioned to the bottom-left of the anchor edge
/// </summary>
BottomLeft = Bottom | Left,
/// <summary>
/// The popup will be positioned to the bottom-right of the anchor edge
/// </summary>
BottomRight = Bottom | Right,
}
/// <summary>
/// Positions an <see cref="IPopupHost"/>.
/// </summary>
/// <remarks>
/// <see cref="IPopupPositioner"/> is an abstraction of the wayland xdg_positioner spec.
///
/// The popup positioner implementation is determined by the platform implementation. A default
/// managed implementation is provided in <see cref="ManagedPopupPositioner"/> for platforms
/// on which popups can be arbitrarily positioned.
/// </remarks>
public interface IPopupPositioner public interface IPopupPositioner
{ {
/// <summary>
/// Updates the position of the associated <see cref="IPopupHost"/> according to the
/// specified parameters.
/// </summary>
/// <param name="parameters">The positioning parameters.</param>
void Update(PopupPositionerParameters parameters); void Update(PopupPositionerParameters parameters);
} }
@ -296,18 +444,19 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
public static void ConfigurePosition(ref this PopupPositionerParameters positionerParameters, public static void ConfigurePosition(ref this PopupPositionerParameters positionerParameters,
TopLevel topLevel, TopLevel topLevel,
IVisual target, PlacementMode placement, Point offset, IVisual target, PlacementMode placement, Point offset,
PopupPositioningEdge anchor, PopupPositioningEdge gravity) PopupAnchor anchor, PopupGravity gravity,
PopupPositionerConstraintAdjustment constraintAdjustment, Rect? rect)
{ {
// We need a better way for tracking the last pointer position // We need a better way for tracking the last pointer position
var pointer = topLevel.PointToClient(topLevel.PlatformImpl.MouseDevice.Position); var pointer = topLevel.PointToClient(topLevel.PlatformImpl.MouseDevice.Position);
positionerParameters.Offset = offset; positionerParameters.Offset = offset;
positionerParameters.ConstraintAdjustment = PopupPositionerConstraintAdjustment.All; positionerParameters.ConstraintAdjustment = constraintAdjustment;
if (placement == PlacementMode.Pointer) if (placement == PlacementMode.Pointer)
{ {
positionerParameters.AnchorRectangle = new Rect(pointer, new Size(1, 1)); positionerParameters.AnchorRectangle = new Rect(pointer, new Size(1, 1));
positionerParameters.Anchor = PopupPositioningEdge.TopLeft; positionerParameters.Anchor = PopupAnchor.TopLeft;
positionerParameters.Gravity = PopupPositioningEdge.BottomRight; positionerParameters.Gravity = PopupGravity.BottomRight;
} }
else else
{ {
@ -317,32 +466,33 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
if (matrix == null) if (matrix == null)
{ {
if (target.GetVisualRoot() == null) if (target.GetVisualRoot() == null)
throw new InvalidCastException("Target control is not attached to the visual tree"); throw new InvalidOperationException("Target control is not attached to the visual tree");
throw new InvalidCastException("Target control is not in the same tree as the popup parent"); throw new InvalidOperationException("Target control is not in the same tree as the popup parent");
} }
positionerParameters.AnchorRectangle = new Rect(default, target.Bounds.Size) var bounds = new Rect(default, target.Bounds.Size);
.TransformToAABB(matrix.Value); var anchorRect = rect ?? bounds;
positionerParameters.AnchorRectangle = anchorRect.Intersect(bounds).TransformToAABB(matrix.Value);
if (placement == PlacementMode.Right) if (placement == PlacementMode.Right)
{ {
positionerParameters.Anchor = PopupPositioningEdge.TopRight; positionerParameters.Anchor = PopupAnchor.TopRight;
positionerParameters.Gravity = PopupPositioningEdge.BottomRight; positionerParameters.Gravity = PopupGravity.BottomRight;
} }
else if (placement == PlacementMode.Bottom) else if (placement == PlacementMode.Bottom)
{ {
positionerParameters.Anchor = PopupPositioningEdge.BottomLeft; positionerParameters.Anchor = PopupAnchor.BottomLeft;
positionerParameters.Gravity = PopupPositioningEdge.BottomRight; positionerParameters.Gravity = PopupGravity.BottomRight;
} }
else if (placement == PlacementMode.Left) else if (placement == PlacementMode.Left)
{ {
positionerParameters.Anchor = PopupPositioningEdge.TopLeft; positionerParameters.Anchor = PopupAnchor.TopLeft;
positionerParameters.Gravity = PopupPositioningEdge.BottomLeft; positionerParameters.Gravity = PopupGravity.BottomLeft;
} }
else if (placement == PlacementMode.Top) else if (placement == PlacementMode.Top)
{ {
positionerParameters.Anchor = PopupPositioningEdge.TopLeft; positionerParameters.Anchor = PopupAnchor.TopLeft;
positionerParameters.Gravity = PopupPositioningEdge.TopRight; positionerParameters.Gravity = PopupGravity.TopRight;
} }
else if (placement == PlacementMode.AnchorAndGravity) else if (placement == PlacementMode.AnchorAndGravity)
{ {

117
src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Transactions;
namespace Avalonia.Controls.Primitives.PopupPositioning namespace Avalonia.Controls.Primitives.PopupPositioning
{ {
@ -8,9 +9,8 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
{ {
IReadOnlyList<ManagedPopupPositionerScreenInfo> Screens { get; } IReadOnlyList<ManagedPopupPositionerScreenInfo> Screens { get; }
Rect ParentClientAreaScreenGeometry { get; } Rect ParentClientAreaScreenGeometry { get; }
double Scaling { get; }
void MoveAndResize(Point devicePoint, Size virtualSize); void MoveAndResize(Point devicePoint, Size virtualSize);
Point TranslatePoint(Point pt);
Size TranslateSize(Size size);
} }
public class ManagedPopupPositionerScreenInfo public class ManagedPopupPositionerScreenInfo
@ -25,6 +25,10 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
} }
} }
/// <summary>
/// An <see cref="IPopupPositioner"/> implementation for platforms on which a popup can be
/// aritrarily positioned.
/// </summary>
public class ManagedPopupPositioner : IPopupPositioner public class ManagedPopupPositioner : IPopupPositioner
{ {
private readonly IManagedPopupPositionerPopup _popup; private readonly IManagedPopupPositionerPopup _popup;
@ -35,38 +39,38 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
} }
private static Point GetAnchorPoint(Rect anchorRect, PopupPositioningEdge edge) private static Point GetAnchorPoint(Rect anchorRect, PopupAnchor edge)
{ {
double x, y; double x, y;
if ((edge & PopupPositioningEdge.Left) != 0) if ((edge & PopupAnchor.Left) != 0)
x = anchorRect.X; x = anchorRect.X;
else if ((edge & PopupPositioningEdge.Right) != 0) else if ((edge & PopupAnchor.Right) != 0)
x = anchorRect.Right; x = anchorRect.Right;
else else
x = anchorRect.X + anchorRect.Width / 2; x = anchorRect.X + anchorRect.Width / 2;
if ((edge & PopupPositioningEdge.Top) != 0) if ((edge & PopupAnchor.Top) != 0)
y = anchorRect.Y; y = anchorRect.Y;
else if ((edge & PopupPositioningEdge.Bottom) != 0) else if ((edge & PopupAnchor.Bottom) != 0)
y = anchorRect.Bottom; y = anchorRect.Bottom;
else else
y = anchorRect.Y + anchorRect.Height / 2; y = anchorRect.Y + anchorRect.Height / 2;
return new Point(x, y); return new Point(x, y);
} }
private static Point Gravitate(Point anchorPoint, Size size, PopupPositioningEdge gravity) private static Point Gravitate(Point anchorPoint, Size size, PopupGravity gravity)
{ {
double x, y; double x, y;
if ((gravity & PopupPositioningEdge.Left) != 0) if ((gravity & PopupGravity.Left) != 0)
x = -size.Width; x = -size.Width;
else if ((gravity & PopupPositioningEdge.Right) != 0) else if ((gravity & PopupGravity.Right) != 0)
x = 0; x = 0;
else else
x = -size.Width / 2; x = -size.Width / 2;
if ((gravity & PopupPositioningEdge.Top) != 0) if ((gravity & PopupGravity.Top) != 0)
y = -size.Height; y = -size.Height;
else if ((gravity & PopupPositioningEdge.Bottom) != 0) else if ((gravity & PopupGravity.Bottom) != 0)
y = 0; y = 0;
else else
y = -size.Height / 2; y = -size.Height / 2;
@ -75,17 +79,24 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
public void Update(PopupPositionerParameters parameters) public void Update(PopupPositionerParameters parameters)
{ {
var rect = Calculate(
Update(_popup.TranslateSize(parameters.Size), parameters.Size, parameters.Size * _popup.Scaling,
new Rect(_popup.TranslatePoint(parameters.AnchorRectangle.TopLeft), new Rect(
_popup.TranslateSize(parameters.AnchorRectangle.Size)), parameters.AnchorRectangle.TopLeft * _popup.Scaling,
parameters.Anchor, parameters.Gravity, parameters.ConstraintAdjustment, parameters.AnchorRectangle.Size * _popup.Scaling),
_popup.TranslatePoint(parameters.Offset)); parameters.Anchor,
parameters.Gravity,
parameters.ConstraintAdjustment,
parameters.Offset * _popup.Scaling);
_popup.MoveAndResize(
rect.Position,
rect.Size / _popup.Scaling);
} }
private void Update(Size translatedSize, Size originalSize, private Rect Calculate(Size translatedSize,
Rect anchorRect, PopupPositioningEdge anchor, PopupPositioningEdge gravity, Rect anchorRect, PopupAnchor anchor, PopupGravity gravity,
PopupPositionerConstraintAdjustment constraintAdjustment, Point offset) PopupPositionerConstraintAdjustment constraintAdjustment, Point offset)
{ {
var parentGeometry = _popup.ParentClientAreaScreenGeometry; var parentGeometry = _popup.ParentClientAreaScreenGeometry;
@ -112,28 +123,30 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
var bounds = GetBounds(); var bounds = GetBounds();
bool FitsInBounds(Rect rc, PopupPositioningEdge edge = PopupPositioningEdge.AllMask) bool FitsInBounds(Rect rc, PopupAnchor edge = PopupAnchor.AllMask)
{ {
if ((edge & PopupPositioningEdge.Left) != 0 if ((edge & PopupAnchor.Left) != 0
&& rc.X < bounds.X) && rc.X < bounds.X)
return false; return false;
if ((edge & PopupPositioningEdge.Top) != 0 if ((edge & PopupAnchor.Top) != 0
&& rc.Y < bounds.Y) && rc.Y < bounds.Y)
return false; return false;
if ((edge & PopupPositioningEdge.Right) != 0 if ((edge & PopupAnchor.Right) != 0
&& rc.Right > bounds.Right) && rc.Right > bounds.Right)
return false; return false;
if ((edge & PopupPositioningEdge.Bottom) != 0 if ((edge & PopupAnchor.Bottom) != 0
&& rc.Bottom > bounds.Bottom) && rc.Bottom > bounds.Bottom)
return false; return false;
return true; return true;
} }
Rect GetUnconstrained(PopupPositioningEdge a, PopupPositioningEdge g) => static bool IsValid(in Rect rc) => rc.Width > 0 && rc.Height > 0;
Rect GetUnconstrained(PopupAnchor a, PopupGravity g) =>
new Rect(Gravitate(GetAnchorPoint(anchorRect, a), translatedSize, g) + offset, translatedSize); new Rect(Gravitate(GetAnchorPoint(anchorRect, a), translatedSize, g) + offset, translatedSize);
@ -141,11 +154,11 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
// If flipping geometry and anchor is allowed and helps, use the flipped one, // If flipping geometry and anchor is allowed and helps, use the flipped one,
// otherwise leave it as is // otherwise leave it as is
if (!FitsInBounds(geo, PopupPositioningEdge.HorizontalMask) if (!FitsInBounds(geo, PopupAnchor.HorizontalMask)
&& (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipX) != 0) && (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipX) != 0)
{ {
var flipped = GetUnconstrained(anchor.FlipX(), gravity.FlipX()); var flipped = GetUnconstrained(anchor.FlipX(), gravity.FlipX());
if (FitsInBounds(flipped, PopupPositioningEdge.HorizontalMask)) if (FitsInBounds(flipped, PopupAnchor.HorizontalMask))
geo = geo.WithX(flipped.X); geo = geo.WithX(flipped.X);
} }
@ -157,13 +170,34 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
geo = geo.WithX(bounds.Right - geo.Width); geo = geo.WithX(bounds.Right - geo.Width);
} }
// Resize the rect horizontally if allowed.
if ((constraintAdjustment & PopupPositionerConstraintAdjustment.ResizeX) != 0)
{
var unconstrainedRect = geo;
if (!FitsInBounds(unconstrainedRect, PopupAnchor.Left))
{
unconstrainedRect = unconstrainedRect.WithX(bounds.X);
}
if (!FitsInBounds(unconstrainedRect, PopupAnchor.Right))
{
unconstrainedRect = unconstrainedRect.WithWidth(bounds.Width - unconstrainedRect.X);
}
if (IsValid(unconstrainedRect))
{
geo = unconstrainedRect;
}
}
// If flipping geometry and anchor is allowed and helps, use the flipped one, // If flipping geometry and anchor is allowed and helps, use the flipped one,
// otherwise leave it as is // otherwise leave it as is
if (!FitsInBounds(geo, PopupPositioningEdge.VerticalMask) if (!FitsInBounds(geo, PopupAnchor.VerticalMask)
&& (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipY) != 0) && (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipY) != 0)
{ {
var flipped = GetUnconstrained(anchor.FlipY(), gravity.FlipY()); var flipped = GetUnconstrained(anchor.FlipY(), gravity.FlipY());
if (FitsInBounds(flipped, PopupPositioningEdge.VerticalMask)) if (FitsInBounds(flipped, PopupAnchor.VerticalMask))
geo = geo.WithY(flipped.Y); geo = geo.WithY(flipped.Y);
} }
@ -175,7 +209,28 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
geo = geo.WithY(bounds.Bottom - geo.Height); geo = geo.WithY(bounds.Bottom - geo.Height);
} }
_popup.MoveAndResize(geo.TopLeft, originalSize); // Resize the rect vertically if allowed.
if ((constraintAdjustment & PopupPositionerConstraintAdjustment.ResizeY) != 0)
{
var unconstrainedRect = geo;
if (!FitsInBounds(unconstrainedRect, PopupAnchor.Top))
{
unconstrainedRect = unconstrainedRect.WithY(bounds.Y);
}
if (!FitsInBounds(unconstrainedRect, PopupAnchor.Bottom))
{
unconstrainedRect = unconstrainedRect.WithHeight(bounds.Height - unconstrainedRect.Y);
}
if (IsValid(unconstrainedRect))
{
geo = unconstrainedRect;
}
}
return geo;
} }
} }
} }

6
src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs

@ -32,7 +32,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
{ {
// Popup positioner operates with abstract coordinates, but in our case they are pixel ones // Popup positioner operates with abstract coordinates, but in our case they are pixel ones
var point = _parent.PointToScreen(default); var point = _parent.PointToScreen(default);
var size = TranslateSize(_parent.ClientSize); var size = _parent.ClientSize * Scaling;
return new Rect(point.X, point.Y, size.Width, size.Height); return new Rect(point.X, point.Y, size.Width, size.Height);
} }
@ -43,8 +43,6 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
_moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _parent.Scaling); _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _parent.Scaling);
} }
public virtual Point TranslatePoint(Point pt) => pt * _parent.Scaling; public virtual double Scaling => _parent.Scaling;
public virtual Size TranslateSize(Size size) => size * _parent.Scaling;
} }
} }

8
src/Avalonia.Controls/Primitives/PopupRoot.cs

@ -82,11 +82,13 @@ namespace Avalonia.Controls.Primitives
} }
public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset, public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
PopupPositioningEdge anchor = PopupPositioningEdge.None, PopupAnchor anchor = PopupAnchor.None,
PopupPositioningEdge gravity = PopupPositioningEdge.None) PopupGravity gravity = PopupGravity.None,
PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
Rect? rect = null)
{ {
_positionerParameters.ConfigurePosition(_parent, target, _positionerParameters.ConfigurePosition(_parent, target,
placement, offset, anchor, gravity); placement, offset, anchor, gravity, constraintAdjustment, rect);
if (_positionerParameters.Size != default) if (_positionerParameters.Size != default)
UpdatePosition(); UpdatePosition();

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

@ -41,13 +41,16 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<bool> IsDirectionReversedProperty = public static readonly StyledProperty<bool> IsDirectionReversedProperty =
AvaloniaProperty.Register<Track, bool>(nameof(IsDirectionReversed)); AvaloniaProperty.Register<Track, bool>(nameof(IsDirectionReversed));
public static readonly StyledProperty<bool> IgnoreThumbDragProperty =
AvaloniaProperty.Register<Track, bool>(nameof(IsThumbDragHandled));
private double _minimum; private double _minimum;
private double _maximum = 100.0; private double _maximum = 100.0;
private double _value; private double _value;
static Track() 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)); IncreaseButtonProperty.Changed.AddClassHandler<Track>((x, e) => x.ButtonChanged(e));
DecreaseButtonProperty.Changed.AddClassHandler<Track>((x, e) => x.ButtonChanged(e)); DecreaseButtonProperty.Changed.AddClassHandler<Track>((x, e) => x.ButtonChanged(e));
AffectsArrange<Track>(MinimumProperty, MaximumProperty, ValueProperty, OrientationProperty); AffectsArrange<Track>(MinimumProperty, MaximumProperty, ValueProperty, OrientationProperty);
@ -113,6 +116,12 @@ namespace Avalonia.Controls.Primitives
set { SetValue(IsDirectionReversedProperty, value); } set { SetValue(IsDirectionReversedProperty, value); }
} }
public bool IsThumbDragHandled
{
get { return GetValue(IgnoreThumbDragProperty); }
set { SetValue(IgnoreThumbDragProperty, value); }
}
private double ThumbCenterOffset { get; set; } private double ThumbCenterOffset { get; set; }
private double Density { get; set; } private double Density { get; set; }
@ -250,7 +259,7 @@ namespace Avalonia.Controls.Primitives
CoerceLength(ref increaseButtonLength, arrangeSize.Width); CoerceLength(ref increaseButtonLength, arrangeSize.Width);
CoerceLength(ref thumbLength, arrangeSize.Width); CoerceLength(ref thumbLength, arrangeSize.Width);
offset = offset.WithY(isDirectionReversed ? increaseButtonLength + thumbLength : 0.0); offset = offset.WithX(isDirectionReversed ? increaseButtonLength + thumbLength : 0.0);
pieceSize = pieceSize.WithWidth(decreaseButtonLength); pieceSize = pieceSize.WithWidth(decreaseButtonLength);
if (DecreaseButton != null) if (DecreaseButton != null)
@ -422,6 +431,9 @@ namespace Avalonia.Controls.Primitives
private void ThumbDragged(object sender, VectorEventArgs e) private void ThumbDragged(object sender, VectorEventArgs e)
{ {
if (IsThumbDragHandled)
return;
Value = MathUtilities.Clamp( Value = MathUtilities.Clamp(
Value + ValueFromDistance(e.Vector.X, e.Vector.Y), Value + ValueFromDistance(e.Vector.X, e.Vector.Y),
Minimum, Minimum,

76
src/Avalonia.Controls/SelectionModel.cs

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

22
src/Avalonia.Controls/SelectionModelChildrenRequestedEventArgs.cs

@ -16,15 +16,17 @@ namespace Avalonia.Controls
{ {
private object? _source; private object? _source;
private IndexPath _sourceIndexPath; private IndexPath _sourceIndexPath;
private IndexPath _finalIndexPath;
private bool _throwOnAccess; private bool _throwOnAccess;
internal SelectionModelChildrenRequestedEventArgs( internal SelectionModelChildrenRequestedEventArgs(
object source, object source,
IndexPath sourceIndexPath, IndexPath sourceIndexPath,
IndexPath finalIndexPath,
bool throwOnAccess) bool throwOnAccess)
{ {
source = source ?? throw new ArgumentNullException(nameof(source)); source = source ?? throw new ArgumentNullException(nameof(source));
Initialize(source, sourceIndexPath, throwOnAccess); Initialize(source, sourceIndexPath, finalIndexPath, throwOnAccess);
} }
/// <summary> /// <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( internal void Initialize(
object? source, object? source,
IndexPath sourceIndexPath, IndexPath sourceIndexPath,
IndexPath finalIndexPath,
bool throwOnAccess) bool throwOnAccess)
{ {
if (!throwOnAccess && source == null) if (!throwOnAccess && source == null)
@ -77,6 +96,7 @@ namespace Avalonia.Controls
_source = source; _source = source;
_sourceIndexPath = sourceIndexPath; _sourceIndexPath = sourceIndexPath;
_finalIndexPath = finalIndexPath;
_throwOnAccess = throwOnAccess; _throwOnAccess = throwOnAccess;
} }
} }

27
src/Avalonia.Controls/SelectionNode.cs

@ -101,6 +101,7 @@ namespace Avalonia.Controls
ItemsSourceView = newDataSource; ItemsSourceView = newDataSource;
TrimInvalidSelections();
PopulateSelectedItemsFromSelectedIndices(); PopulateSelectedItemsFromSelectedIndices();
HookupCollectionChangedHandler(); HookupCollectionChangedHandler();
OnSelectionChanged(); 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 ItemsSourceView? ItemsSourceView { get; private set; }
public int DataCount => ItemsSourceView?.Count ?? 0; public int DataCount => ItemsSourceView?.Count ?? 0;
public int ChildrenNodeCount => _childrenNodes.Count; 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 // 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 // an explosion of node objects. However, I'm still creating the m_childrenNodes
// collection unfortunately. // collection unfortunately.
public SelectionNode? GetAt(int index, bool realizeChild) public SelectionNode? GetAt(int index, bool realizeChild, IndexPath finalIndexPath)
{ {
SelectionNode? child = null; SelectionNode? child = null;
@ -171,7 +192,7 @@ namespace Avalonia.Controls
if (childData != null) if (childData != null)
{ {
var childDataIndexPath = IndexPath.CloneWithChildIndex(index); var childDataIndexPath = IndexPath.CloneWithChildIndex(index);
resolver = _manager.ResolvePath(childData, childDataIndexPath); resolver = _manager.ResolvePath(childData, childDataIndexPath, finalIndexPath);
} }
if (resolver != null) if (resolver != null)
@ -843,7 +864,7 @@ namespace Avalonia.Controls
int notSelectedCount = 0; int notSelectedCount = 0;
for (int i = 0; i < ChildrenNodeCount; i++) for (int i = 0; i < ChildrenNodeCount; i++)
{ {
var child = GetAt(i, realizeChild: false); var child = GetAt(i, false, default);
if (child != null) if (child != null)
{ {

161
src/Avalonia.Controls/Slider.cs

@ -1,12 +1,40 @@
using System; using System;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Utilities;
namespace Avalonia.Controls 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> /// <summary>
/// A control that lets the user select from a range of values by moving a Thumb control along a Track. /// A control that lets the user select from a range of values by moving a Thumb control along a Track.
/// </summary> /// </summary>
@ -30,19 +58,31 @@ namespace Avalonia.Controls
public static readonly StyledProperty<double> TickFrequencyProperty = public static readonly StyledProperty<double> TickFrequencyProperty =
AvaloniaProperty.Register<Slider, double>(nameof(TickFrequency), 0.0); 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 // Slider required parts
private bool _isDragging = false;
private Track _track; private Track _track;
private Button _decreaseButton; private Button _decreaseButton;
private Button _increaseButton; private Button _increaseButton;
private IDisposable _decreaseButtonPressDispose;
private IDisposable _decreaseButtonReleaseDispose;
private IDisposable _increaseButtonSubscription;
private IDisposable _increaseButtonReleaseDispose;
private IDisposable _pointerMovedDispose;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="Slider"/> class. /// Initializes static members of the <see cref="Slider"/> class.
/// </summary> /// </summary>
static Slider() static Slider()
{ {
PressedMixin.Attach<Slider>();
OrientationProperty.OverrideDefaultValue(typeof(Slider), Orientation.Horizontal); OrientationProperty.OverrideDefaultValue(typeof(Slider), Orientation.Horizontal);
Thumb.DragStartedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble); 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); Thumb.DragCompletedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragCompleted(e), RoutingStrategies.Bubble);
} }
@ -81,57 +121,89 @@ namespace Avalonia.Controls
set { SetValue(TickFrequencyProperty, value); } 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/> /// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{ {
if (_decreaseButton != null) base.OnApplyTemplate(e);
{
_decreaseButton.Click -= DecreaseClick; _decreaseButtonPressDispose?.Dispose();
} _decreaseButtonReleaseDispose?.Dispose();
_increaseButtonSubscription?.Dispose();
if (_increaseButton != null) _increaseButtonReleaseDispose?.Dispose();
{ _pointerMovedDispose?.Dispose();
_increaseButton.Click -= IncreaseClick;
}
_decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton"); _decreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
_track = e.NameScope.Find<Track>("PART_Track"); _track = e.NameScope.Find<Track>("PART_Track");
_increaseButton = e.NameScope.Find<Button>("PART_IncreaseButton"); _increaseButton = e.NameScope.Find<Button>("PART_IncreaseButton");
if (_track != null)
{
_track.IsThumbDragHandled = true;
}
if (_decreaseButton != null) if (_decreaseButton != null)
{ {
_decreaseButton.Click += DecreaseClick; _decreaseButtonPressDispose = _decreaseButton.AddDisposableHandler(PointerPressedEvent, TrackPressed, RoutingStrategies.Tunnel);
_decreaseButtonReleaseDispose = _decreaseButton.AddDisposableHandler(PointerReleasedEvent, TrackReleased, RoutingStrategies.Tunnel);
} }
if (_increaseButton != null) 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; private void MoveToPoint(PointerPoint x)
var next = SnapToTick(Math.Max(Math.Min(value + by, Maximum), Minimum)); {
if (next != value) var orient = Orientation == Orientation.Horizontal;
{
Value = next; 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 + Minimum;
Value = IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue;
} }
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
@ -150,19 +222,7 @@ namespace Avalonia.Controls
/// <param name="e"></param> /// <param name="e"></param>
protected virtual void OnThumbDragStarted(VectorEventArgs e) protected virtual void OnThumbDragStarted(VectorEventArgs e)
{ {
} _isDragging = true;
/// <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);
}
} }
/// <summary> /// <summary>
@ -171,15 +231,7 @@ namespace Avalonia.Controls
/// <param name="e"></param> /// <param name="e"></param>
protected virtual void OnThumbDragCompleted(VectorEventArgs e) protected virtual void OnThumbDragCompleted(VectorEventArgs e)
{ {
} _isDragging = false;
/// <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)));
} }
/// <summary> /// <summary>
@ -188,14 +240,17 @@ namespace Avalonia.Controls
/// <param name="value">Value that want to snap to closest Tick.</param> /// <param name="value">Value that want to snap to closest Tick.</param>
private double SnapToTick(double value) 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); previous = Minimum + (Math.Round((value - Minimum) / TickFrequency) * TickFrequency);
double next = Math.Min(Maximum, previous + TickFrequency); next = Math.Min(Maximum, previous + TickFrequency);
value = value > (previous + next) * 0.5 ? next : previous;
} }
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) private void UpdatePseudoClasses(Orientation o)

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) private static void IsOpenChanged(AvaloniaPropertyChangedEventArgs e)
{ {
var control = (Control)e.Sender; var control = (Control)e.Sender;
var newValue = (bool)e.NewValue;
ToolTip toolTip;
if ((bool)e.NewValue) if (newValue)
{ {
var tip = GetTip(control); var tip = GetTip(control);
if (tip == null) return; if (tip == null) return;
var toolTip = control.GetValue(ToolTipProperty); toolTip = control.GetValue(ToolTipProperty);
if (toolTip == null || (tip != toolTip && tip != toolTip.Content)) if (toolTip == null || (tip != toolTip && tip != toolTip.Content))
{ {
toolTip?.Close(); toolTip?.Close();
@ -223,9 +225,11 @@ namespace Avalonia.Controls
} }
else else
{ {
var toolTip = control.GetValue(ToolTipProperty); toolTip = control.GetValue(ToolTipProperty);
toolTip?.Close(); toolTip?.Close();
} }
toolTip?.UpdatePseudoClasses(newValue);
} }
private void Open(Control control) private void Open(Control control)
@ -238,6 +242,9 @@ namespace Avalonia.Controls
_popup.ConfigurePosition(control, GetPlacement(control), _popup.ConfigurePosition(control, GetPlacement(control),
new Point(GetHorizontalOffset(control), GetVerticalOffset(control))); new Point(GetHorizontalOffset(control), GetVerticalOffset(control)));
WindowManagerAddShadowHintChanged(_popup, false);
_popup.Show(); _popup.Show();
} }
@ -250,5 +257,18 @@ namespace Avalonia.Controls
_popup = null; _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> /// <summary>
/// Gets or sets the selected item. /// Gets or sets the selected item.
/// </summary> /// </summary>
/// <summary> /// <remarks>
/// Gets or sets the selected item. /// Note that setting this property only currently works if the item is expanded to be visible.
/// </summary> /// To select non-expanded nodes use `Selection.SelectedIndex`.
/// </remarks>
public object SelectedItem public object SelectedItem
{ {
get => Selection.SelectedItem; get => Selection.SelectedItem;
@ -346,7 +347,7 @@ namespace Avalonia.Controls
if (container != null) 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) 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 (container is object)
{ {
if (e.SourceIndex.IsAncestorOf(e.FinalIndex))
{
container.IsExpanded = true;
container.ApplyTemplate();
container.Presenter?.ApplyTemplate();
}
e.Children = Observable.CombineLatest( e.Children = Observable.CombineLatest(
container.GetObservable(TreeViewItem.IsExpandedProperty), container.GetObservable(TreeViewItem.IsExpandedProperty),
container.GetObservable(ItemsProperty), container.GetObservable(ItemsProperty),

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

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

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

@ -28,7 +28,7 @@ namespace Avalonia.Controls.Utils
if (depth < path.GetSize() - 1) 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; int count = realizeChildren ? nextNode.Node.DataCount : nextNode.Node.ChildrenNodeCount;
for (int i = count - 1; i >= 0; i--) 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); var childPath = nextNode.Path.CloneWithChildIndex(i);
if (child != null) if (child != null)
{ {
@ -90,7 +90,7 @@ namespace Avalonia.Controls.Utils
for (int i = endIndex; i >= startIndex; i--) for (int i = endIndex; i >= startIndex; i--)
{ {
var child = node.GetAt(i, realizeChild: true); var child = node.GetAt(i, true, end);
if (child != null) if (child != null)
{ {
var childPath = currentPath.CloneWithChildIndex(i); 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; int endIndex = depth < end.GetSize() && isEndPath ? end.GetAt(depth) : info.Node.DataCount - 1;
for (int i = endIndex; i >= startIndex; i--) 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) if (child != null)
{ {
var childPath = info.Path.CloneWithChildIndex(i); 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 SetTextAsync(string text) => Task.CompletedTask;
public Task ClearAsync() => 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 class CursorFactoryStub : IStandardCursorFactory

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

@ -2,6 +2,7 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Diagnostics.Models; using Avalonia.Diagnostics.Models;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Threading;
namespace Avalonia.Diagnostics.ViewModels namespace Avalonia.Diagnostics.ViewModels
{ {
@ -49,7 +50,21 @@ namespace Avalonia.Diagnostics.ViewModels
value is TreePageViewModel newTree && value is TreePageViewModel newTree &&
oldTree?.SelectedNode?.Visual is IControl control) 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); RaiseAndSetIfChanged(ref _content, value);

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

@ -1,11 +1,11 @@
using System; using System;
using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Reactive; using System.Reactive;
using System.Reactive.Linq; using System.Reactive.Linq;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Styling;
using Avalonia.VisualTree; using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.ViewModels namespace Avalonia.Diagnostics.ViewModels
@ -82,5 +82,41 @@ namespace Avalonia.Diagnostics.ViewModels
get; get;
private set; 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 internal class TreePageViewModel : ViewModelBase, IDisposable
{ {
private TreeNode _selected; private TreeNode _selectedNode;
private ControlDetailsViewModel _details; private ControlDetailsViewModel _details;
private string _propertyFilter; private string _propertyFilter;
public TreePageViewModel(TreeNode[] nodes) public TreePageViewModel(TreeNode[] nodes)
{ {
Nodes = 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 TreeNode[] Nodes { get; protected set; }
public SelectionModel Selection { get; }
public TreeNode SelectedNode public TreeNode SelectedNode
{ {
get => _selected; get => _selectedNode;
set private set
{ {
if (Details != null) if (Details != null)
{ {
_propertyFilter = Details.PropertyFilter; _propertyFilter = Details.PropertyFilter;
} }
if (RaiseAndSetIfChanged(ref _selected, value)) if (RaiseAndSetIfChanged(ref _selectedNode, value))
{ {
Details = value != null ? Details = value != null ?
new ControlDetailsViewModel(value.Visual, _propertyFilter) : new ControlDetailsViewModel(value.Visual, _propertyFilter) :
@ -83,8 +95,8 @@ namespace Avalonia.Diagnostics.ViewModels
if (node != null) if (node != null)
{ {
SelectedNode = node;
ExpandNode(node.Parent); ExpandNode(node.Parent);
Selection.SelectedIndex = node.Index;
} }
} }

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

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

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

@ -9,5 +9,11 @@ namespace Avalonia.Input.Platform
Task SetTextAsync(string text); Task SetTextAsync(string text);
Task ClearAsync(); 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 unsafe partial class IAvnString
{ {
private string _managed; private string _managed;
private byte[] _bytes;
public string String 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; public override string ToString() => String;
} }

32
src/Avalonia.Native/ClipboardImpl.cs

@ -82,6 +82,38 @@ namespace Avalonia.Native
using (var strings = _native.GetStrings(NSFilenamesPboardType)) using (var strings = _native.GetStrings(NSFilenamesPboardType))
return strings.ToStringArray(); 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 class ClipboardDataObject : IDataObject, IDisposable

3
src/Avalonia.Native/OsxManagedPopupPositionerPopupImplHelper.cs

@ -9,8 +9,7 @@ namespace Avalonia.Native
{ {
} }
public override Point TranslatePoint(Point pt) => pt;
public override Size TranslateSize(Size size) => size; public override double Scaling => 1;
} }
} }

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

@ -8,7 +8,7 @@
<Styles xmlns="https://github.com/avaloniaui" <Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"> xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style Selector="DatePicker"> <Style Selector="CalendarDatePicker">
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/> <Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
@ -119,7 +119,7 @@
</Setter> </Setter>
</Style> </Style>
<Style Selector="DatePicker:focus /template/ TextBox#PART_TextBox"> <Style Selector="CalendarDatePicker:focus /template/ TextBox#PART_TextBox">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}"/> <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}"/>
</Style> </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.CalendarDayButton.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.CalendarItem.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.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.ButtonSpinner.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.NumericUpDown.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"/> <StyleInclude Source="resm:Avalonia.Themes.Default.AutoCompleteBox.xaml?assembly=Avalonia.Themes.Default"/>

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

@ -46,7 +46,7 @@
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Border Name="TrackBackground" Grid.Column="1" Width="4" Margin="0,6" HorizontalAlignment="Center"/> <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 Name="PART_Track" Grid.Column="1" Orientation="Vertical">
<Track.DecreaseButton> <Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton" <RepeatButton Name="PART_DecreaseButton"
Classes="repeattrack" /> Classes="repeattrack" />

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

@ -138,6 +138,9 @@
<SolidColorBrush x:Key="SystemControlTransparentBrush" Color="Transparent" /> <SolidColorBrush x:Key="SystemControlTransparentBrush" Color="Transparent" />
<SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="{StaticResource SystemErrorTextColor}" /> <SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="{StaticResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="SystemControlTransientBorderBrush" Color="#000000" Opacity="0.36" /> <SolidColorBrush x:Key="SystemControlTransientBorderBrush" Color="#000000" Opacity="0.36" />
<SolidColorBrush x:Key="SystemControlHighlightListLowRevealBackgroundBrush" Color="{StaticResource SystemListMediumColor}" />
<SolidColorBrush x:Key="SystemControlHighlightListMediumRevealBackgroundBrush" Color="{StaticResource SystemListMediumColor}" />
<SolidColorBrush x:Key="SystemControlHighlightAccentRevealBackgroundBrush" Color="{StaticResource SystemAccentColor}" />
<!-- TODO implement AcrylicBrush --> <!-- TODO implement AcrylicBrush -->
<!--<AcrylicBrush x:Key="SystemControlTransientBackgroundBrush" BackgroundSource="HostBackdrop" TintColor="{StaticResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{StaticResource SystemChromeMediumLowColor}" />--> <!--<AcrylicBrush x:Key="SystemControlTransientBackgroundBrush" BackgroundSource="HostBackdrop" TintColor="{StaticResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{StaticResource SystemChromeMediumLowColor}" />-->
<SolidColorBrush x:Key="SystemControlTransientBackgroundBrush" Color="{StaticResource SystemChromeMediumLowColor}" /> <SolidColorBrush x:Key="SystemControlTransientBackgroundBrush" Color="{StaticResource SystemChromeMediumLowColor}" />

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

@ -138,6 +138,9 @@
<SolidColorBrush x:Key="SystemControlTransparentBrush" Color="Transparent" /> <SolidColorBrush x:Key="SystemControlTransparentBrush" Color="Transparent" />
<SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="{StaticResource SystemErrorTextColor}" /> <SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="{StaticResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="SystemControlTransientBorderBrush" Color="#000000" Opacity="0.14" /> <SolidColorBrush x:Key="SystemControlTransientBorderBrush" Color="#000000" Opacity="0.14" />
<SolidColorBrush x:Key="SystemControlHighlightListLowRevealBackgroundBrush" Color="{StaticResource SystemListMediumColor}" />
<SolidColorBrush x:Key="SystemControlHighlightListMediumRevealBackgroundBrush" Color="{StaticResource SystemListMediumColor}" />
<SolidColorBrush x:Key="SystemControlHighlightAccentRevealBackgroundBrush" Color="{StaticResource SystemAccentColor}" />
<!-- TODO implement AcrylicBrush --> <!-- TODO implement AcrylicBrush -->
<!--<AcrylicBrush x:Key="SystemControlTransientBackgroundBrush" BackgroundSource="HostBackdrop" TintColor="{StaticResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{StaticResource SystemChromeMediumLowColor}" />--> <!--<AcrylicBrush x:Key="SystemControlTransientBackgroundBrush" BackgroundSource="HostBackdrop" TintColor="{StaticResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{StaticResource SystemChromeMediumLowColor}" />-->
<SolidColorBrush x:Key="SystemControlTransientBackgroundBrush" Color="{StaticResource SystemChromeMediumLowColor}" /> <SolidColorBrush x:Key="SystemControlTransientBackgroundBrush" Color="{StaticResource SystemChromeMediumLowColor}" />

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> <Style.Resources>
<Color x:Key="SystemAccentColor">#FF0078D7</Color> <Color x:Key="SystemAccentColor">#FF0078D7</Color>
<Color x:Key="SystemAltHighColor">#FF000000</Color> <Color x:Key="SystemAltHighColor">#FF000000</Color>
@ -31,6 +33,10 @@
<Color x:Key="SystemRevealListLowColor">#FF1D1D1D</Color> <Color x:Key="SystemRevealListLowColor">#FF1D1D1D</Color>
<Color x:Key="SystemRevealListMediumColor">#FF333333</Color> <Color x:Key="SystemRevealListMediumColor">#FF333333</Color>
<!--<AcrylicBrush x:Key="SystemControlAcrylicWindowBrush" BackgroundSource="HostBackdrop" TintColor="{ThemeResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{ThemeResource SystemChromeMediumColor}" />--> <!--<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 --> <!-- Override system shape defaults -->
<CornerRadius x:Key="ControlCornerRadius">2,2,2,2</CornerRadius> <CornerRadius x:Key="ControlCornerRadius">2,2,2,2</CornerRadius>
@ -86,6 +92,57 @@
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" /> <StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" /> <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 --> <!-- BaseResources for ComboBox.xaml -->
<StaticResource x:Key="ComboBoxItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" /> <StaticResource x:Key="ComboBoxItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ComboBoxItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" /> <StaticResource x:Key="ComboBoxItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
@ -312,5 +369,38 @@
<StaticResource x:Key="RadioButtonCheckGlyphStrokePointerOver" ResourceKey="SystemControlTransparentBrush" /> <StaticResource x:Key="RadioButtonCheckGlyphStrokePointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="RadioButtonCheckGlyphStrokePressed" ResourceKey="SystemControlTransparentBrush" /> <StaticResource x:Key="RadioButtonCheckGlyphStrokePressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="RadioButtonCheckGlyphStrokeDisabled" 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.Resources>
</Style> </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> <Style.Resources>
<Color x:Key="SystemAccentColor">#FF0078D7</Color> <Color x:Key="SystemAccentColor">#FF0078D7</Color>
<Color x:Key="SystemAltHighColor">#FFFFFFFF</Color> <Color x:Key="SystemAltHighColor">#FFFFFFFF</Color>
@ -31,6 +33,10 @@
<Color x:Key="SystemRevealListLowColor">#FFE6E6E6</Color> <Color x:Key="SystemRevealListLowColor">#FFE6E6E6</Color>
<Color x:Key="SystemRevealListMediumColor">#FFCCCCCC</Color> <Color x:Key="SystemRevealListMediumColor">#FFCCCCCC</Color>
<!--<AcrylicBrush x:Key="SystemControlAcrylicWindowBrush" BackgroundSource="HostBackdrop" TintColor="{ThemeResource SystemChromeAltHighColor}" TintOpacity="0.8" FallbackColor="{ThemeResource SystemChromeMediumColor}" />--> <!--<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 --> <!-- Override system shape defaults -->
<CornerRadius x:Key="ControlCornerRadius">2,2,2,2</CornerRadius> <CornerRadius x:Key="ControlCornerRadius">2,2,2,2</CornerRadius>
@ -87,6 +93,58 @@
<StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" /> <StaticResource x:Key="ButtonBorderBrushPressed" ResourceKey="SystemControlHighlightTransparentBrush" />
<StaticResource x:Key="ButtonBorderBrushDisabled" ResourceKey="SystemControlDisabledTransparentBrush" /> <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 --> <!-- BaseResources for ComboBox.xaml -->
<StaticResource x:Key="ComboBoxItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" /> <StaticResource x:Key="ComboBoxItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ComboBoxItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" /> <StaticResource x:Key="ComboBoxItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
@ -313,5 +371,38 @@
<StaticResource x:Key="RadioButtonCheckGlyphStrokePointerOver" ResourceKey="SystemControlTransparentBrush" /> <StaticResource x:Key="RadioButtonCheckGlyphStrokePointerOver" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="RadioButtonCheckGlyphStrokePressed" ResourceKey="SystemControlTransparentBrush" /> <StaticResource x:Key="RadioButtonCheckGlyphStrokePressed" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="RadioButtonCheckGlyphStrokeDisabled" 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.Resources>
</Style> </Style>

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

@ -1,6 +1,6 @@
<Style xmlns="https://github.com/avaloniaui" <Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"> xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style.Resources> <Style.Resources>
<!-- Resources for Button.xaml --> <!-- Resources for Button.xaml -->
<StaticResource x:Key="AccentButtonBackground" ResourceKey="SystemControlBackgroundAccentBrush" /> <StaticResource x:Key="AccentButtonBackground" ResourceKey="SystemControlBackgroundAccentBrush" />
@ -39,6 +39,87 @@
<SolidColorBrush x:Key="ButtonPressedBackgroundThemeBrush" Color="#FFFFFFFF" /> <SolidColorBrush x:Key="ButtonPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="ButtonPressedForegroundThemeBrush" Color="#FF000000" /> <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 --> <!-- Resources for ComboBox.xaml -->
<x:Double x:Key="ComboBoxArrowThemeFontSize">21</x:Double> <x:Double x:Key="ComboBoxArrowThemeFontSize">21</x:Double>
<x:Double x:Key="ComboBoxThemeMinWidth">64</x:Double> <x:Double x:Key="ComboBoxThemeMinWidth">64</x:Double>
@ -101,8 +182,8 @@
<StaticResource x:Key="ComboBoxDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" /> <StaticResource x:Key="ComboBoxDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
<StaticResource x:Key="ComboBoxDropDownGlyphForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" /> <StaticResource x:Key="ComboBoxDropDownGlyphForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocused" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" /> <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocused" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />
<StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocusedPressed" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" /> <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocusedPressed" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />
<StaticResource x:Key="ComboBoxDropDownForeground" ResourceKey="SystemControlForegroundBaseHighBrush" /> <StaticResource x:Key="ComboBoxDropDownForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ComboBoxDropDownBackground" ResourceKey="SystemControlTransientBackgroundBrush" /> <StaticResource x:Key="ComboBoxDropDownBackground" ResourceKey="SystemControlTransientBackgroundBrush" />
<StaticResource x:Key="ComboBoxDropDownBorderBrush" ResourceKey="SystemControlTransientBorderBrush" /> <StaticResource x:Key="ComboBoxDropDownBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
@ -169,6 +250,87 @@
<SolidColorBrush x:Key="ListBoxItemSelectedForegroundThemeBrush" Color="White" /> <SolidColorBrush x:Key="ListBoxItemSelectedForegroundThemeBrush" Color="White" />
<SolidColorBrush x:Key="ListBoxItemSelectedPointerOverBackgroundThemeBrush" Color="#FF5F37BE" /> <SolidColorBrush x:Key="ListBoxItemSelectedPointerOverBackgroundThemeBrush" Color="#FF5F37BE" />
<!-- Resources for MenuFlyout.xaml (Menu, ContextMenu, etc) -->
<x:Double x:Key="MenuFlyoutSeparatorThemeHeight">1</x:Double>
<x:Double x:Key="MenuFlyoutThemeMinHeight">32</x:Double>
<Thickness x:Key="MenuFlyoutPresenterThemePadding">0,0</Thickness>
<!--<Thickness x:Key="MenuFlyoutItemCheckGlyphMargin">12,11,0,13</Thickness>-->
<Thickness x:Key="MenuFlyoutItemChevronMargin">12,0,0,0</Thickness>
<!--<Thickness x:Key="MenuFlyoutItemPlaceholderThemeThickness">28,0,0,0</Thickness>-->
<Thickness x:Key="MenuFlyoutSeparatorThemePadding">12,4,12,4</Thickness>
<StaticResource x:Key="MenuFlyoutItemBackground" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutItemBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowBrush" />
<StaticResource x:Key="MenuFlyoutItemBackgroundPressed" ResourceKey="SystemControlHighlightListMediumBrush" />
<StaticResource x:Key="MenuFlyoutItemBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutItemForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutItemForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<!--<StaticResource x:Key="MenuFlyoutSubItemBackground" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutSubItemBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowBrush" />
<StaticResource x:Key="MenuFlyoutSubItemBackgroundPressed" ResourceKey="SystemControlHighlightListAccentHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemBackgroundSubMenuOpened" ResourceKey="SystemControlHighlightListLowBrush" />
<StaticResource x:Key="MenuFlyoutSubItemBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutSubItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemForegroundSubMenuOpened" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />-->
<StaticResource x:Key="MenuFlyoutSubItemChevron" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemChevronPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemChevronPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemChevronSubMenuOpened" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemChevronDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="MenuFlyoutLightDismissOverlayBackground" ResourceKey="SystemControlPageBackgroundMediumAltMediumBrush" />
<!--<SolidColorBrush x:Key="MenuFlyoutItemFocusedBackgroundThemeBrush" Color="#FF212121" />
<SolidColorBrush x:Key="MenuFlyoutItemFocusedForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="MenuFlyoutItemDisabledForegroundThemeBrush" Color="#66FFFFFF" />
<SolidColorBrush x:Key="MenuFlyoutItemPointerOverBackgroundThemeBrush" Color="#FF212121" />
<SolidColorBrush x:Key="MenuFlyoutItemPointerOverForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="MenuFlyoutItemPressedBackgroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="MenuFlyoutItemPressedForegroundThemeBrush" Color="#FF000000" />-->
<!--<SolidColorBrush x:Key="MenuFlyoutSeparatorThemeBrush" Color="#FF7A7A7A" />-->
<!--<Thickness x:Key="MenuFlyoutItemDoublePlaceholderThemeThickness">56,0,0,0</Thickness>-->
<StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForeground" ResourceKey="SystemControlForegroundBaseMediumBrush" />
<StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseMediumBrush" />
<StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundPressed" ResourceKey="SystemControlHighlightAltBaseMediumBrush" />
<StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<Thickness x:Key="MenuFlyoutItemThemePadding">11,9,11,10</Thickness>
<Thickness x:Key="MenuFlyoutItemThemePaddingNarrow">11,4,11,7</Thickness>
<StaticResource x:Key="MenuFlyoutPresenterBackground" ResourceKey="SystemControlTransientBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutPresenterBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
<Thickness x:Key="MenuFlyoutPresenterBorderThemeThickness">1</Thickness>
<!-- Resources for Windows.UI.Xaml.Controls.MenuFlyoutItem --><!--
<StaticResource x:Key="MenuFlyoutItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightListMediumRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />
--><!-- Resources for Windows.UI.Xaml.Controls.ToggleMenuFlyoutItem --><!--
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightListMediumRevealBackgroundBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />
--><!-- Resources for Windows.UI.Xaml.Controls.MenuFlyoutSubItem --><!--
<StaticResource x:Key="MenuFlyoutSubItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightAccentRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundSubMenuOpened" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushSubMenuOpened" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />-->
<!--<Thickness x:Key="LanguageSwitcherMenuFlyoutItemPlaceholderThemeThickness">44,0,0,0</Thickness>-->
<!-- Resources for TextBox.xaml --> <!-- Resources for TextBox.xaml -->
<SolidColorBrush x:Key="TextBoxForegroundHeaderThemeBrush" Color="#FFFFFFFF" /> <SolidColorBrush x:Key="TextBoxForegroundHeaderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush" Color="#AB000000" /> <SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush" Color="#AB000000" />
@ -290,6 +452,33 @@
<SolidColorBrush x:Key="CheckBoxPressedBorderThemeBrush" Color="#FFFFFFFF" /> <SolidColorBrush x:Key="CheckBoxPressedBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="CheckBoxPressedForegroundThemeBrush" Color="#FF000000" /> <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 --> <!-- Resources for RadioButton.xaml -->
<x:Double x:Key="RadioButtonBorderThemeThickness">1</x:Double> <x:Double x:Key="RadioButtonBorderThemeThickness">1</x:Double>
<StaticResource x:Key="RadioButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" /> <StaticResource x:Key="RadioButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
@ -343,5 +532,66 @@
<SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FFFFFFFF" /> <SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FF000000" /> <SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" /> <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.Resources>
</Style> </Style>

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

@ -1,6 +1,6 @@
<Style xmlns="https://github.com/avaloniaui" <Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"> xmlns:sys="clr-namespace:System;assembly=netstandard">
<Style.Resources> <Style.Resources>
<!-- Resources for Button.xaml --> <!-- Resources for Button.xaml -->
<StaticResource x:Key="AccentButtonBackground" ResourceKey="SystemControlBackgroundAccentBrush" /> <StaticResource x:Key="AccentButtonBackground" ResourceKey="SystemControlBackgroundAccentBrush" />
@ -39,6 +39,86 @@
<SolidColorBrush x:Key="ButtonPressedBackgroundThemeBrush" Color="#FF000000" /> <SolidColorBrush x:Key="ButtonPressedBackgroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="ButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" /> <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 --> <!-- Resources for ComboBox.xaml -->
<x:Double x:Key="ComboBoxArrowThemeFontSize">21</x:Double> <x:Double x:Key="ComboBoxArrowThemeFontSize">21</x:Double>
<x:Double x:Key="ComboBoxThemeMinWidth">64</x:Double> <x:Double x:Key="ComboBoxThemeMinWidth">64</x:Double>
@ -101,8 +181,8 @@
<StaticResource x:Key="ComboBoxDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" /> <StaticResource x:Key="ComboBoxDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
<StaticResource x:Key="ComboBoxDropDownGlyphForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" /> <StaticResource x:Key="ComboBoxDropDownGlyphForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocused" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" /> <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocused" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />
<StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocusedPressed" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" /> <StaticResource x:Key="ComboBoxDropDownGlyphForegroundFocusedPressed" ResourceKey="SystemControlHighlightAltBaseMediumHighBrush" />
<StaticResource x:Key="ComboBoxDropDownForeground" ResourceKey="SystemControlForegroundBaseHighBrush" /> <StaticResource x:Key="ComboBoxDropDownForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="ComboBoxDropDownBackground" ResourceKey="SystemControlTransientBackgroundBrush" /> <StaticResource x:Key="ComboBoxDropDownBackground" ResourceKey="SystemControlTransientBackgroundBrush" />
<StaticResource x:Key="ComboBoxDropDownBorderBrush" ResourceKey="SystemControlTransientBorderBrush" /> <StaticResource x:Key="ComboBoxDropDownBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
@ -150,7 +230,7 @@
<StaticResource x:Key="ComboBoxFocusedDropDownBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" /> <StaticResource x:Key="ComboBoxFocusedDropDownBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="ComboBoxFocusedDropDownBackgroundPointerPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" /> <StaticResource x:Key="ComboBoxFocusedDropDownBackgroundPointerPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
<StaticResource x:Key="ComboBoxEditableDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" /> <StaticResource x:Key="ComboBoxEditableDropDownGlyphForeground" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
<!-- Resources for ListBox.xaml --> <!-- Resources for ListBox.xaml -->
<Thickness x:Key="ListBoxBorderThemeThickness">0</Thickness> <Thickness x:Key="ListBoxBorderThemeThickness">0</Thickness>
<SolidColorBrush x:Key="ListBoxBackgroundThemeBrush" Color="#CCFFFFFF" /> <SolidColorBrush x:Key="ListBoxBackgroundThemeBrush" Color="#CCFFFFFF" />
@ -169,6 +249,87 @@
<SolidColorBrush x:Key="ListBoxItemSelectedForegroundThemeBrush" Color="White" /> <SolidColorBrush x:Key="ListBoxItemSelectedForegroundThemeBrush" Color="White" />
<SolidColorBrush x:Key="ListBoxItemSelectedPointerOverBackgroundThemeBrush" Color="#FF5F37BE" /> <SolidColorBrush x:Key="ListBoxItemSelectedPointerOverBackgroundThemeBrush" Color="#FF5F37BE" />
<!-- Resources for MenuFlyout.xaml (Menu, ContextMenu, etc) -->
<x:Double x:Key="MenuFlyoutSeparatorThemeHeight">1</x:Double>
<x:Double x:Key="MenuFlyoutThemeMinHeight">32</x:Double>
<Thickness x:Key="MenuFlyoutPresenterThemePadding">0,0</Thickness>
<!--<Thickness x:Key="MenuFlyoutItemCheckGlyphMargin">12,11,0,13</Thickness>-->
<Thickness x:Key="MenuFlyoutItemChevronMargin">12,0,0,0</Thickness>
<!--<Thickness x:Key="MenuFlyoutItemPlaceholderThemeThickness">28,0,0,0</Thickness>-->
<Thickness x:Key="MenuFlyoutSeparatorThemePadding">12,4,12,4</Thickness>
<StaticResource x:Key="MenuFlyoutItemBackground" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutItemBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowBrush" />
<StaticResource x:Key="MenuFlyoutItemBackgroundPressed" ResourceKey="SystemControlHighlightListMediumBrush" />
<StaticResource x:Key="MenuFlyoutItemBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutItemForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutItemForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<!--<StaticResource x:Key="MenuFlyoutSubItemBackground" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutSubItemBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowBrush" />
<StaticResource x:Key="MenuFlyoutSubItemBackgroundPressed" ResourceKey="SystemControlHighlightListAccentHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemBackgroundSubMenuOpened" ResourceKey="SystemControlHighlightListLowBrush" />
<StaticResource x:Key="MenuFlyoutSubItemBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutSubItemForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemForegroundPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemForegroundSubMenuOpened" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />-->
<StaticResource x:Key="MenuFlyoutSubItemChevron" ResourceKey="SystemControlForegroundBaseMediumHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemChevronPointerOver" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemChevronPressed" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemChevronSubMenuOpened" ResourceKey="SystemControlHighlightAltBaseHighBrush" />
<StaticResource x:Key="MenuFlyoutSubItemChevronDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="MenuFlyoutLightDismissOverlayBackground" ResourceKey="SystemControlPageBackgroundMediumAltMediumBrush" />
<!--<SolidColorBrush x:Key="MenuFlyoutItemFocusedBackgroundThemeBrush" Color="#FFE5E5E5" />
<SolidColorBrush x:Key="MenuFlyoutItemFocusedForegroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="MenuFlyoutItemDisabledForegroundThemeBrush" Color="#66000000" />
<SolidColorBrush x:Key="MenuFlyoutItemPointerOverBackgroundThemeBrush" Color="#FFE5E5E5" />
<SolidColorBrush x:Key="MenuFlyoutItemPointerOverForegroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="MenuFlyoutItemPressedBackgroundThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="MenuFlyoutItemPressedForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="MenuFlyoutSeparatorThemeBrush" Color="#FF7A7A7A" />-->
<!--<Thickness x:Key="MenuFlyoutItemDoublePlaceholderThemeThickness">56,0,0,0</Thickness>-->
<StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForeground" ResourceKey="SystemControlForegroundBaseMediumBrush" />
<StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundPointerOver" ResourceKey="SystemControlHighlightAltBaseMediumBrush" />
<StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundPressed" ResourceKey="SystemControlHighlightAltBaseMediumBrush" />
<StaticResource x:Key="MenuFlyoutItemKeyboardAcceleratorTextForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<Thickness x:Key="MenuFlyoutItemThemePadding">11,9,11,10</Thickness>
<Thickness x:Key="MenuFlyoutItemThemePaddingNarrow">11,4,11,7</Thickness>
<StaticResource x:Key="MenuFlyoutPresenterBackground" ResourceKey="SystemControlTransientBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutPresenterBorderBrush" ResourceKey="SystemControlTransientBorderBrush" />
<Thickness x:Key="MenuFlyoutPresenterBorderThemeThickness">1</Thickness>
<!-- Resources for Windows.UI.Xaml.Controls.MenuFlyoutItem -->
<!--<StaticResource x:Key="MenuFlyoutItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightListMediumRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="MenuFlyoutItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />
--><!-- Resources for Windows.UI.Xaml.Controls.ToggleMenuFlyoutItem --><!--
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightListMediumRevealBackgroundBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="ToggleMenuFlyoutItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />
--><!-- Resources for Windows.UI.Xaml.Controls.MenuFlyoutSubItem --><!--
<StaticResource x:Key="MenuFlyoutSubItemRevealBackground" ResourceKey="SystemControlTransparentRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundPointerOver" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundPressed" ResourceKey="SystemControlHighlightAccentRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundSubMenuOpened" ResourceKey="SystemControlHighlightListLowRevealBackgroundBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBackgroundDisabled" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrush" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushPressed" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushPointerOver" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushSubMenuOpened" ResourceKey="SystemControlTransparentRevealBorderBrush" />
<StaticResource x:Key="MenuFlyoutSubItemRevealBorderBrushDisabled" ResourceKey="SystemControlTransparentBrush" />
<Thickness x:Key="LanguageSwitcherMenuFlyoutItemPlaceholderThemeThickness">44,0,0,0</Thickness>-->
<!-- Resources for TextBox.xaml --> <!-- Resources for TextBox.xaml -->
<SolidColorBrush x:Key="TextBoxForegroundHeaderThemeBrush" Color="#FF000000" /> <SolidColorBrush x:Key="TextBoxForegroundHeaderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush" Color="#AB000000" /> <SolidColorBrush x:Key="TextBoxPlaceholderTextThemeBrush" Color="#AB000000" />
@ -290,6 +451,33 @@
<SolidColorBrush x:Key="CheckBoxPressedBorderThemeBrush" Color="#FF000000" /> <SolidColorBrush x:Key="CheckBoxPressedBorderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="CheckBoxPressedForegroundThemeBrush" Color="#FFFFFFFF" /> <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 --> <!-- Resources for RadioButton.xaml -->
<x:Double x:Key="RadioButtonBorderThemeThickness">1</x:Double> <x:Double x:Key="RadioButtonBorderThemeThickness">1</x:Double>
<StaticResource x:Key="RadioButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" /> <StaticResource x:Key="RadioButtonForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
@ -343,5 +531,66 @@
<SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FF000000" /> <SolidColorBrush x:Key="RadioButtonPressedBorderThemeBrush" Color="#FF000000" />
<SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" /> <SolidColorBrush x:Key="RadioButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="RadioButtonContentPointerOverForegroundThemeBrush" Color="{DynamicResource SystemColorHighlightTextColor}" /> <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.Resources>
</Style> </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.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.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.Accents.FluentControlResourcesDark.xaml?assembly=Avalonia.Themes.Fluent" />
<StyleInclude Source="resm:Avalonia.Themes.Fluent.FluentTheme.xaml?assembly=Avalonia.Themes.Fluent" />
</Styles> </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.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.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.Accents.FluentControlResourcesLight.xaml?assembly=Avalonia.Themes.Fluent" />
<StyleInclude Source="resm:Avalonia.Themes.Fluent.FluentTheme.xaml?assembly=Avalonia.Themes.Fluent" />
</Styles> </Styles>

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

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

200
src/Avalonia.Themes.Fluent/ButtonSpinner.xaml

@ -1,104 +1,140 @@
<Styles xmlns="https://github.com/avaloniaui"> <Styles xmlns="https://github.com/avaloniaui"
<Style Selector="ButtonSpinner"> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Setter Property="Background" Value="Transparent"/> xmlns:sys="clr-namespace:System;assembly=netstandard"
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/> xmlns:converters="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls">
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/> <Design.PreviewWith>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Border Padding="20"
<Setter Property="VerticalContentAlignment" Value="Center"/> Background="Black">
<StackPanel Spacing="20">
<ButtonSpinner ButtonSpinnerLocation="Right"
Content="Right disabled inline spinner"
AllowSpin="False" />
<ButtonSpinner ButtonSpinnerLocation="Left"
Content="Left spinner" />
<ButtonSpinner ShowButtonSpinner="False"
Content="Hide spinner" />
</StackPanel>
</Border>
</Design.PreviewWith>
<Styles.Resources>
<converters:MarginMultiplierConverter x:Key="ButtonSpinner_OnlyLeftThinknessConverter"
Indent="1"
Left="True" />
<converters:MarginMultiplierConverter x:Key="ButtonSpinner_OnlyRightThinknessConverter"
Indent="1"
Right="True" />
<StreamGeometry x:Key="ButtonSpinnerIncreaseButtonIcon">M0,9 L10,0 20,9 19,10 10,2 1,10 z</StreamGeometry>
<StreamGeometry x:Key="ButtonSpinnerDecreaseButtonIcon">M0,1 L10,10 20,1 19,0 10,8 1,0 z</StreamGeometry>
</Styles.Resources>
<!-- RepeatButton.ButtonSpinnerRepeatButton -->
<Style Selector="RepeatButton.ButtonSpinnerRepeatButton">
<Setter Property="MinWidth" Value="34" />
<Setter Property="VerticalAlignment" Value="Stretch" />
</Style> </Style>
<Style Selector="ButtonSpinner /template/ RepeatButton">
<Setter Property="Background" Value="Transparent"/> <Style Selector="RepeatButton.ButtonSpinnerRepeatButton /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="Transparent"/> <Setter Property="CornerRadius" Value="0" />
<Setter Property="BorderBrush" Value="{TemplateBinding BorderBrush}" />
</Style> </Style>
<Style Selector="ButtonSpinner /template/ RepeatButton:pointerover"> <Style Selector="RepeatButton.ButtonSpinnerRepeatButton:disabled">
<Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/> <Setter Property="BorderBrush" Value="{TemplateBinding BorderBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
</Style> </Style>
<Style Selector="ButtonSpinner /template/ RepeatButton#PART_IncreaseButton"> <Style Selector="RepeatButton.ButtonSpinnerRepeatButton:disabled > Path">
<Setter Property="Content"> <Setter Property="Fill" Value="{DynamicResource RepeatButtonForegroundDisabled}" />
<Template>
<Path Fill="{DynamicResource ThemeForegroundBrush}"
Width="8"
Height="4"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M0,5 L4.5,.5 9,5 6,5 4.5,3.5 3,5 z"/>
</Template>
</Setter>
</Style> </Style>
<Style Selector="ButtonSpinner /template/ RepeatButton#PART_DecreaseButton">
<Setter Property="Content"> <!-- ButtonSpinner -->
<Template> <Style Selector="ButtonSpinner">
<Path Fill="{DynamicResource ThemeForegroundBrush}" <Setter Property="Background" Value="Transparent" />
Width="8" <Setter Property="Foreground" Value="{DynamicResource TextControlForeground}" />
Height="4" <Setter Property="Padding" Value="10, 0" />
Stretch="Uniform" <Setter Property="Background" Value="{DynamicResource TextControlBackground}" />
HorizontalAlignment="Center" <Setter Property="BorderBrush" Value="{DynamicResource TextControlBorderBrush}" />
VerticalAlignment="Center" <Setter Property="BorderThickness" Value="{DynamicResource TextControlBorderThemeThickness}" />
Data="M0,0 L3,0 4.5,1.5 6,0 9,0 4.5,4.5 z"/> <Setter Property="MinHeight" Value="{DynamicResource TextControlThemeMinHeight}" />
</Template> <Setter Property="MinWidth" Value="{DynamicResource TextControlThemeMinWidth}" />
</Setter> <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
</Style> <Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Style Selector="ButtonSpinner:right"> <Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Border Name="border" <Border Background="{TemplateBinding Background}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
Margin="{TemplateBinding Padding}" CornerRadius="{DynamicResource ControlCornerRadius}">
HorizontalAlignment="{TemplateBinding HorizontalAlignment}" <Grid ColumnDefinitions="Auto,*,Auto">
VerticalAlignment="{TemplateBinding VerticalAlignment}"> <ContentPresenter Name="PART_ContentPresenter"
<Grid ColumnDefinitions="*,Auto"> Grid.Column="1"
<ContentPresenter Name="PART_ContentPresenter" Grid.Column="0"
ContentTemplate="{TemplateBinding ContentTemplate}" ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}" Content="{TemplateBinding Content}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}"/> Padding="{TemplateBinding Padding}" />
<Grid Grid.Column="1" RowDefinitions="*,*" IsVisible="{TemplateBinding ShowButtonSpinner}">
<RepeatButton Grid.Row="0" Name="PART_IncreaseButton"/> <StackPanel Name="PART_SpinnerPanel"
<RepeatButton Grid.Row="1" Name="PART_DecreaseButton"/> Orientation="Horizontal"
</Grid> IsVisible="{TemplateBinding ShowButtonSpinner}">
<RepeatButton Name="PART_IncreaseButton"
Classes="ButtonSpinnerRepeatButton"
VerticalContentAlignment="Center"
Foreground="{TemplateBinding Foreground}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
FontSize="{TemplateBinding FontSize}">
<Path Fill="{TemplateBinding Foreground}"
Width="16"
Height="8"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{StaticResource ButtonSpinnerIncreaseButtonIcon}" />
</RepeatButton>
<RepeatButton Name="PART_DecreaseButton"
Classes="ButtonSpinnerRepeatButton"
Foreground="{TemplateBinding Foreground}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
VerticalContentAlignment="Center"
FontSize="{TemplateBinding FontSize}">
<Path Fill="{TemplateBinding Foreground}"
Width="16"
Height="8"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{StaticResource ButtonSpinnerDecreaseButtonIcon}" />
</RepeatButton>
</StackPanel>
</Grid> </Grid>
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>
<Style Selector="ButtonSpinner:left">
<Setter Property="Template"> <!-- ButtonSpinnerLocation=Right -->
<ControlTemplate> <Style Selector="ButtonSpinner:right /template/ StackPanel#PART_SpinnerPanel">
<Border Name="border" <Setter Property="Grid.Column" Value="2" />
Background="{TemplateBinding Background}" </Style>
BorderBrush="{TemplateBinding BorderBrush}" <Style Selector="ButtonSpinner:right /template/ RepeatButton.ButtonSpinnerRepeatButton">
BorderThickness="{TemplateBinding BorderThickness}" <Setter Property="BorderThickness" Value="{Binding $parent[ButtonSpinner].BorderThickness, Converter={StaticResource ButtonSpinner_OnlyLeftThinknessConverter}}" />
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}">
<Grid ColumnDefinitions="Auto,*">
<Grid Grid.Column="0" RowDefinitions="*,*" IsVisible="{TemplateBinding ShowButtonSpinner}">
<RepeatButton Grid.Row="0" Name="PART_IncreaseButton"/>
<RepeatButton Grid.Row="1" Name="PART_DecreaseButton"/>
</Grid>
<ContentPresenter Name="PART_ContentPresenter" Grid.Column="1"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style> </Style>
<Style Selector="ButtonSpinner:pointerover /template/ Border#border">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}"/> <!-- ButtonSpinnerLocation=Left -->
<Style Selector="ButtonSpinner:left /template/ StackPanel#PART_SpinnerPanel">
<Setter Property="Grid.Column" Value="0" />
</Style> </Style>
<Style Selector="ButtonSpinner:focus /template/ Border#border"> <Style Selector="ButtonSpinner:left /template/ RepeatButton.ButtonSpinnerRepeatButton">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}"/> <Setter Property="BorderThickness" Value="{Binding $parent[ButtonSpinner].BorderThickness, Converter={StaticResource ButtonSpinner_OnlyRightThinknessConverter}}" />
</Style> </Style>
<Style Selector="ButtonSpinner:error /template/ Border#border">
<Setter Property="BorderBrush" Value="{DynamicResource ErrorBrush}"/> <!-- Error state -->
<Style Selector="ButtonSpinner:error">
<Setter Property="BorderBrush" Value="{DynamicResource ErrorBrush}" />
</Style> </Style>
</Styles> </Styles>

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

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

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

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

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

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

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

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

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

@ -8,176 +8,127 @@
<Styles xmlns="https://github.com/avaloniaui" <Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="CalendarItem"> <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"> <Setter Property="DayTitleTemplate">
<Template> <Template>
<TextBlock FontWeight="Bold" <TextBlock Text="{Binding}"
FontSize="9.5"
Margin="0,4,0,4"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{Binding}" /> FontSize="12"/>
</Template> </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> </Setter>
</Style> </Style>
<Style Selector="CalendarItem /template/ Rectangle#DisabledVisual"> <!-- BackgroundLayer shouldn't show in the week day names row-->
<Setter Property="IsVisible" Value="False"/> <Style Selector="Calendar[DisplayMode=Month] CalendarItem /template/ Border#BackgroundLayer">
</Style> <Setter Property="Margin" Value="0,38,0,0"/>
<Style Selector="CalendarItem:calendardisabled /template/ Rectangle#DisabledVisual">
<Setter Property="IsVisible" Value="True"/>
</Style> </Style>
</Styles> </Styles>

6
src/Avalonia.Themes.Fluent/Common.xaml

@ -0,0 +1,6 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="TextBlock.CaptionTextBlockStyle">
<Setter Property="FontSize" Value="12" />
<Setter Property="FontWeight" Value="Normal" />
</Style>
</Styles>

69
src/Avalonia.Themes.Fluent/ContextMenu.xaml

@ -1,22 +1,61 @@
<Style xmlns="https://github.com/avaloniaui" Selector="ContextMenu"> <Style xmlns="https://github.com/avaloniaui"
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/> Selector="ContextMenu">
<Setter Property="BorderThickness" Value="1"/> <Design.PreviewWith>
<Setter Property="Padding" Value="4,2"/> <Border Background="{DynamicResource ThemeAccentBrush}"
<Setter Property="TextBlock.FontSize" Value="{DynamicResource FontSizeNormal}" /> Margin="16"
<Setter Property="TextBlock.FontWeight" Value="Normal" /> Padding="48"
<Setter Property="Template"> Width="400"
Height="200">
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Standard _Menu Item" />
<Separator />
<MenuItem Header="Menu with _Submenu">
<MenuItem Header="Submenu _1" />
<MenuItem Header="Submenu _2" />
</MenuItem>
<MenuItem Header="Menu Item with _Icon" />
<MenuItem Header="Menu Item with _Checkbox">
<MenuItem.Icon>
<CheckBox BorderThickness="0"
IsHitTestVisible="False"
IsChecked="True" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</Border.ContextMenu>
<TextBlock Text="Defined in XAML" />
</Border>
</Design.PreviewWith>
<Setter Property="Background" Value="{DynamicResource MenuFlyoutPresenterBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutPresenterBorderBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}" />
<Setter Property="MaxWidth" Value="{DynamicResource FlyoutThemeMaxWidth}" />
<Setter Property="MinHeight" Value="{DynamicResource MenuFlyoutThemeMinHeight}" />
<Setter Property="Padding" Value="{DynamicResource MenuFlyoutPresenterThemePadding}" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="TextBlock.FontSize" Value="{DynamicResource FontSizeNormal}" />
<Setter Property="TextBlock.FontWeight" Value="Normal" />
<Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Border Background="{TemplateBinding Background}" <Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"> Padding="{TemplateBinding Padding}"
<ScrollViewer> MaxWidth="{TemplateBinding MaxWidth}"
<ItemsPresenter Name="PART_ItemsPresenter" MinHeight="{TemplateBinding MinHeight}"
Items="{TemplateBinding Items}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
ItemsPanel="{TemplateBinding ItemsPanel}" CornerRadius="{DynamicResource OverlayCornerRadius}">
ItemTemplate="{TemplateBinding ItemTemplate}" <ScrollViewer>
KeyboardNavigation.TabNavigation="Continue"/> <ItemsPresenter Name="PART_ItemsPresenter"
</ScrollViewer> Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
Margin="{DynamicResource MenuFlyoutScrollerMargin}"
KeyboardNavigation.TabNavigation="Continue"
Grid.IsSharedSizeScope="True" />
</ScrollViewer>
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>

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.CalendarDayButton.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.CalendarItem.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.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.ButtonSpinner.xaml?assembly=Avalonia.Themes.Fluent"/>
<StyleInclude Source="resm:Avalonia.Themes.Fluent.NumericUpDown.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"/> <StyleInclude Source="resm:Avalonia.Themes.Fluent.AutoCompleteBox.xaml?assembly=Avalonia.Themes.Fluent"/>

28
src/Avalonia.Themes.Fluent/Menu.xaml

@ -1,16 +1,34 @@
<Style xmlns="https://github.com/avaloniaui" Selector="Menu"> <Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Selector="Menu">
<Design.PreviewWith>
<Border Padding="20">
<Menu>
<MenuItem Header="New" />
<MenuItem Header="Open" />
</Menu>
</Border>
</Design.PreviewWith>
<Style.Resources>
<x:Double x:Key="MenuHeight">32</x:Double>
</Style.Resources>
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="{StaticResource MenuHeight}" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Border Background="{TemplateBinding Background}" <Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
HorizontalAlignment="Stretch"
Padding="{TemplateBinding Padding}"> Padding="{TemplateBinding Padding}">
<ItemsPresenter Name="PART_ItemsPresenter" <ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}" Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}" ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}" ItemTemplate="{TemplateBinding ItemTemplate}"
KeyboardNavigation.TabNavigation="Continue"/> VerticalAlignment="Stretch"
KeyboardNavigation.TabNavigation="Continue" />
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>

244
src/Avalonia.Themes.Fluent/MenuItem.xaml

@ -2,98 +2,143 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls" xmlns:conv="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls"
xmlns:sys="clr-namespace:System;assembly=netstandard"> xmlns:sys="clr-namespace:System;assembly=netstandard">
<Design.PreviewWith>
<Border Padding="20"
Width="400"
Height="200">
<Menu VerticalAlignment="Top">
<MenuItem Header="File">
<MenuItem Header="New"
InputGesture="Ctrl+N">
<MenuItem Header="XML" />
</MenuItem>
<MenuItem Header="Open">
<MenuItem.Icon>
<CheckBox BorderThickness="0"
IsHitTestVisible="False"
IsChecked="True" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Exit"
InputGesture="Alt+F4" />
</MenuItem>
<MenuItem Header="Edit">
<MenuItem Header="Go To">
<MenuItem Header="Go To Line"/>
</MenuItem>
</MenuItem>
<MenuItem Header="View">
<MenuItem Header="Designer" InputGesture="Shift+F7" />
</MenuItem>
<MenuItem Header="Project">
<MenuItem Header="Add class" />
</MenuItem>
</Menu>
</Border>
</Design.PreviewWith>
<Styles.Resources> <Styles.Resources>
<conv:PlatformKeyGestureConverter x:Key="KeyGestureConverter"/> <conv:PlatformKeyGestureConverter x:Key="KeyGestureConverter" />
<Thickness x:Key="MenuFlyoutScrollerMargin">0,4,0,4</Thickness>
<Thickness x:Key="MenuIconPresenterMargin">0,0,12,0</Thickness>
<Thickness x:Key="MenuInputGestureTextMargin">24,0,0,0</Thickness>
<StreamGeometry x:Key="MenuItemChevronPathData">M 1,0 10,10 l -9,10 -1,-1 L 8,10 -0,1 Z</StreamGeometry>
</Styles.Resources> </Styles.Resources>
<Style Selector="MenuItem"> <Style Selector="MenuItem">
<Setter Property="Background" Value="Transparent"/> <Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackground}" />
<Setter Property="BorderThickness" Value="1"/> <Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutItemRevealBorderBrush}" />
<Setter Property="Padding" Value="6 0"/> <Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemForeground}" />
<Setter Property="Padding" Value="{DynamicResource MenuFlyoutItemThemePadding}" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Border Name="root" <Border Name="PART_LayoutRoot"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"> BorderThickness="{TemplateBinding BorderThickness}">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/> <ColumnDefinition Width="Auto"
<ColumnDefinition Width="5"/> SharedSizeGroup="MenuItemIcon" />
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIGT"/> <ColumnDefinition Width="Auto"
<ColumnDefinition Width="20"/> SharedSizeGroup="MenuItemIGT" />
<ColumnDefinition Width="Auto"
SharedSizeGroup="MenuItemChevron" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<ContentPresenter Name="icon" <ContentPresenter Name="PART_IconPresenter"
Content="{TemplateBinding Icon}" Content="{TemplateBinding Icon}"
Width="16" Width="16"
Height="16" Height="16"
Margin="3" Margin="{DynamicResource MenuIconPresenterMargin}"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center"/> VerticalAlignment="Center"/>
<Path Name="check"
Fill="{TemplateBinding Foreground}"
Data="F1M10,1.2L4.7,9.1 4.5,9.1 0,5.2 1.3,3.5 4.3,6.1 8.3,0 10,1.2z"
IsVisible="False"
Margin="3"
VerticalAlignment="Center"/>
<ContentPresenter Name="PART_HeaderPresenter" <ContentPresenter Name="PART_HeaderPresenter"
Content="{TemplateBinding Header}" Content="{TemplateBinding Header}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="Center" VerticalAlignment="Center"
Grid.Column="2"> HorizontalAlignment="Stretch"
TextBlock.Foreground="{TemplateBinding Foreground}"
Grid.Column="1">
<ContentPresenter.DataTemplates> <ContentPresenter.DataTemplates>
<DataTemplate DataType="sys:String"> <DataTemplate DataType="sys:String">
<AccessText Text="{Binding}"/> <AccessText Text="{Binding}" />
</DataTemplate> </DataTemplate>
</ContentPresenter.DataTemplates> </ContentPresenter.DataTemplates>
</ContentPresenter> </ContentPresenter>
<TextBlock x:Name="PART_InputGestureText" <TextBlock x:Name="PART_InputGestureText"
Grid.Column="3" Grid.Column="2"
Text="{TemplateBinding InputGesture, Converter={StaticResource KeyGestureConverter}}" Classes="CaptionTextBlockStyle"
VerticalAlignment="Center"/> Margin="{DynamicResource MenuInputGestureTextMargin}"
<Path Name="rightArrow" Text="{TemplateBinding InputGesture,
Data="M0,0L4,3.5 0,7z" Converter={StaticResource KeyGestureConverter}}"
Fill="{DynamicResource ThemeForegroundBrush}" HorizontalAlignment="Right"
Margin="10,0,0,0" VerticalAlignment="Center" />
<Path Name="PART_ChevronPath"
Stretch="Uniform"
Width="8"
Height="16"
Data="{StaticResource MenuItemChevronPathData}"
Margin="{DynamicResource MenuFlyoutItemChevronMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Grid.Column="4"/> Grid.Column="3" />
<Popup Name="PART_Popup" <Popup Name="PART_Popup"
WindowManagerAddShadowHint="True"
PlacementMode="Right" PlacementMode="Right"
StaysOpen="True" StaysOpen="True"
IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}"> IsOpen="{TemplateBinding IsSubMenuOpen,
<Border Background="{TemplateBinding Background}" Mode=TwoWay}">
BorderBrush="{DynamicResource ThemeBorderMidBrush}" <Border Background="{DynamicResource MenuFlyoutPresenterBackground}"
BorderThickness="{TemplateBinding BorderThickness}"> BorderBrush="{DynamicResource MenuFlyoutPresenterBorderBrush}"
<ScrollViewer> BorderThickness="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}"
<ItemsPresenter Name="PART_ItemsPresenter" Padding="{DynamicResource MenuFlyoutPresenterThemePadding}"
Items="{TemplateBinding Items}" MaxWidth="{DynamicResource FlyoutThemeMaxWidth}"
ItemsPanel="{TemplateBinding ItemsPanel}" MinHeight="{DynamicResource MenuFlyoutThemeMinHeight}"
ItemTemplate="{TemplateBinding ItemTemplate}" HorizontalAlignment="Stretch"
Grid.IsSharedSizeScope="True"/> CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer>
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
Margin="{DynamicResource MenuFlyoutScrollerMargin}"
Grid.IsSharedSizeScope="True" />
</ScrollViewer> </ScrollViewer>
</Border> </Border>
</Popup> </Popup>
</Grid> </Grid>
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>
<Style Selector="MenuItem:separator">
<Setter Property="Template">
<ControlTemplate>
<Separator Background="{DynamicResource ThemeControlMidBrush}"
Margin="20,1,0,1"
Height="1"/>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="Menu > MenuItem"> <Style Selector="Menu > MenuItem">
<Setter Property="Padding" Value="6 0"/>
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Border Name="root" <Border Name="PART_LayoutRoot"
Background="{TemplateBinding Background}" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"> BorderThickness="{TemplateBinding BorderThickness}">
@ -103,22 +148,31 @@
Margin="{TemplateBinding Padding}"> Margin="{TemplateBinding Padding}">
<ContentPresenter.DataTemplates> <ContentPresenter.DataTemplates>
<DataTemplate DataType="sys:String"> <DataTemplate DataType="sys:String">
<AccessText Text="{Binding}"/> <AccessText Text="{Binding}" />
</DataTemplate> </DataTemplate>
</ContentPresenter.DataTemplates> </ContentPresenter.DataTemplates>
</ContentPresenter> </ContentPresenter>
<Popup Name="PART_Popup" <Popup Name="PART_Popup"
IsOpen="{TemplateBinding IsSubMenuOpen, Mode=TwoWay}" WindowManagerAddShadowHint="False"
MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}"
IsOpen="{TemplateBinding IsSubMenuOpen,
Mode=TwoWay}"
StaysOpen="True"> StaysOpen="True">
<Border Background="{TemplateBinding Background}" <Border Background="{DynamicResource MenuFlyoutPresenterBackground}"
BorderBrush="{DynamicResource ThemeBorderMidBrush}" BorderBrush="{DynamicResource MenuFlyoutPresenterBorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"> BorderThickness="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}"
Padding="{DynamicResource MenuFlyoutPresenterThemePadding}"
MaxWidth="{DynamicResource FlyoutThemeMaxWidth}"
MinHeight="{DynamicResource MenuFlyoutThemeMinHeight}"
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer> <ScrollViewer>
<ItemsPresenter Name="PART_ItemsPresenter" <ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}" Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}" ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}" ItemTemplate="{TemplateBinding ItemTemplate}"
Grid.IsSharedSizeScope="True"/> Margin="{DynamicResource MenuFlyoutScrollerMargin}"
Grid.IsSharedSizeScope="True" />
</ScrollViewer> </ScrollViewer>
</Border> </Border>
</Popup> </Popup>
@ -128,20 +182,78 @@
</Setter> </Setter>
</Style> </Style>
<Style Selector="MenuItem /template/ ItemsPresenter#PART_ItemsPresenter"> <Style Selector="MenuItem">
<Setter Property="Margin" Value="2"/> <!-- Narrow padding should be used for mouse input, when non-narrow one should be used for touch input in future. -->
<Setter Property="Padding" Value="{DynamicResource MenuFlyoutItemThemePaddingNarrow}" />
</Style>
<Style Selector="MenuItem /template/ ContentPresenter#PART_IconPresenter">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="MenuItem:icon /template/ ContentPresenter#PART_IconPresenter">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="MenuItem /template/ TextBlock#PART_InputGestureText">
<Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}" />
</Style>
<Style Selector="MenuItem /template/ Path#PART_ChevronPath">
<Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevron}" />
</Style> </Style>
<Style Selector="MenuItem:selected /template/ Border#root"> <Style Selector="MenuItem:selected /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/> <Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource ThemeAccentBrush}"/> <Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutItemBorderBrushPointerOver}" />
</Style>
<Style Selector="MenuItem:selected /template/ TextBlock#PART_InputGestureText">
<Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundPointerOver}" />
</Style>
<Style Selector="MenuItem:selected /template/ Path#PART_ChevronPath">
<Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronPointerOver}" />
</Style> </Style>
<Style Selector="MenuItem:empty /template/ Path#rightArrow"> <Style Selector="MenuItem:pressed /template/ Border#PART_LayoutRoot">
<Setter Property="IsVisible" Value="False"/> <Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutItemBorderBrushPressed}" />
</Style>
<Style Selector="MenuItem:pressed /template/ TextBlock#PART_InputGestureText">
<Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundPressed}" />
</Style>
<Style Selector="MenuItem:pressed /template/ Path#PART_ChevronPath">
<Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronPressed}" />
</Style> </Style>
<Style Selector="MenuItem:disabled"> <Style Selector="MenuItem:disabled">
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/> <Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutItemBorderBrushDisabled}" />
</Style>
<Style Selector="MenuItem:disabled /template/ TextBlock#PART_InputGestureText">
<Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundDisabled}" />
</Style>
<Style Selector="MenuItem:disabled /template/ Path#PART_ChevronPath">
<Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronDisabled}" />
</Style>
<Style Selector="MenuItem:open /template/ Path#PART_ChevronPath">
<Setter Property="Fill" Value="{DynamicResource MenuFlyoutSubItemChevronSubMenuOpened}" />
</Style>
<Style Selector="MenuItem:empty /template/ Path#PART_ChevronPath">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="MenuItem:separator">
<Setter Property="Template">
<ControlTemplate>
<Separator />
</ControlTemplate>
</Setter>
</Style>
<Style Selector="MenuItem > Separator, ContextMenu > Separator">
<Setter Property="Background" Value="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Margin" Value="{DynamicResource MenuFlyoutSeparatorThemePadding}" />
<Setter Property="Height" Value="{DynamicResource MenuFlyoutSeparatorThemeHeight}" />
</Style> </Style>
</Styles> </Styles>

52
src/Avalonia.Themes.Fluent/NumericUpDown.xaml

@ -1,38 +1,60 @@
<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"
Background="Black">
<StackPanel Spacing="20">
<NumericUpDown Minimum="0"
Maximum="10"
Increment="0.5"
Width="150"
Watermark="Enter text" />
<NumericUpDown Minimum="0"
Maximum="10"
Increment="0.5"
Width="150"
ButtonSpinnerLocation="Left"
Watermark="Enter text" />
</StackPanel>
</Border>
</Design.PreviewWith>
<Style Selector="NumericUpDown"> <Style Selector="NumericUpDown">
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" /> <Setter Property="Foreground" Value="{DynamicResource TextControlForeground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/> <Setter Property="Background" Value="{DynamicResource TextControlBackground}" />
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/> <Setter Property="BorderThickness" Value="{DynamicResource TextControlBorderThemeThickness}" />
<Setter Property="Padding" Value="4"/> <Setter Property="BorderBrush" Value="{DynamicResource TextControlBorderBrush}" />
<Setter Property="MinHeight" Value="{DynamicResource TextControlThemeMinHeight}" />
<Setter Property="MinWidth" Value="{DynamicResource TextControlThemeMinWidth}" />
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="Padding" Value="{DynamicResource TextControlThemePadding}" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<ButtonSpinner Name="PART_Spinner" <ButtonSpinner Name="PART_Spinner"
Background="{TemplateBinding Background}" Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
Padding="0"
HorizontalContentAlignment="Stretch" HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
AllowSpin="{TemplateBinding AllowSpin}" AllowSpin="{TemplateBinding AllowSpin}"
ShowButtonSpinner="{TemplateBinding ShowButtonSpinner}" ShowButtonSpinner="{TemplateBinding ShowButtonSpinner}"
ButtonSpinnerLocation="{TemplateBinding ButtonSpinnerLocation}"> ButtonSpinnerLocation="{TemplateBinding ButtonSpinnerLocation}">
<TextBox Name="PART_TextBox" <TextBox Name="PART_TextBox"
BorderThickness="0" Background="Transparent"
Background="{TemplateBinding Background}" BorderBrush="Transparent"
BorderBrush="{TemplateBinding BorderBrush}" Margin="-2"
Padding="{TemplateBinding Padding}" Padding="{TemplateBinding Padding}"
Watermark="{TemplateBinding Watermark}" Watermark="{TemplateBinding Watermark}"
DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}" DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"
IsReadOnly="{TemplateBinding IsReadOnly}" IsReadOnly="{TemplateBinding IsReadOnly}"
Text="{TemplateBinding Text}" Text="{TemplateBinding Text}"
AcceptsReturn="False" AcceptsReturn="False"
TextWrapping="NoWrap"> TextWrapping="NoWrap" />
</TextBox>
</ButtonSpinner> </ButtonSpinner>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>
<Style Selector="NumericUpDown /template/ TextBox#PART_TextBox">
<Setter Property="Margin" Value="4"/> </Styles>
<Setter Property="MinWidth" Value="20"/>
</Style>
</Styles>

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

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

12
src/Avalonia.Themes.Fluent/Separator.xaml

@ -4,17 +4,15 @@
<Setter Property="Focusable" Value="False"/> <Setter Property="Focusable" Value="False"/>
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Border BorderBrush="{TemplateBinding BorderBrush}" <Border Padding="{TemplateBinding Margin}"
Height="{TemplateBinding Height}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"/> Background="{TemplateBinding Background}"/>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>
<Style Selector="MenuItem > Separator, ContextMenu > Separator">
<Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="Margin" Value="29,1,0,1"/>
<Setter Property="Height" Value="1"/>
</Style>
</Styles> </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"> <Style Selector="Slider:horizontal">
<Setter Property="MinWidth" Value="40"/> <Setter Property="Background" Value="{DynamicResource SliderTrackFill}" />
<Setter Property="MinHeight" Value="20"/> <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"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Grid Name="grid"> <Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid.RowDefinitions> <Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
<RowDefinition Height="Auto"/> <ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}"
<RowDefinition Height="Auto" MinHeight="20"/> Margin="{DynamicResource SliderTopHeaderMargin}" />
<RowDefinition Height="Auto"/> <Grid x:Name="SliderContainer" Grid.Row="1">
</Grid.RowDefinitions> <Grid.Styles>
<Border Name="TrackBackground" Grid.Row="1" Height="4" Margin="6,0" VerticalAlignment="Center"/> <Style Selector="TickBar">
<Track Name="PART_Track" Grid.Row="1" Orientation="Horizontal"> <Setter Property="ReservedSpace" Value="{Binding #PART_Track.Thumb.Bounds}" />
<Track.DecreaseButton> </Style>
<RepeatButton Name="PART_DecreaseButton" </Grid.Styles>
Classes="repeattrack" /> <Grid x:Name="HorizontalTemplate" ColumnDefinitions="Auto,Auto,*" MinHeight="{DynamicResource SliderHorizontalHeight}">
</Track.DecreaseButton> <Grid.RowDefinitions>
<Track.IncreaseButton> <RowDefinition Height="{DynamicResource SliderPreContentMargin}" />
<RepeatButton Name="PART_IncreaseButton" <RowDefinition Height="Auto" />
Classes="repeattrack" /> <RowDefinition Height="{DynamicResource SliderPostContentMargin}" />
</Track.IncreaseButton> </Grid.RowDefinitions>
<Thumb Name="thumb" MinWidth="20" MinHeight="20"> <TickBar Name="TopTickBar" Placement="Top" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Bottom" Margin="0,0,0,4" Grid.ColumnSpan="3" />
<Thumb.Template> <!-- <TickBar Name="HorizontalInlineTickBar" Placement="Top" Fill="{DynamicResource SliderInlineTickBarFill}" Height="{DynamicResource SliderTrackThemeHeight}" Grid.Row="1" Grid.ColumnSpan="3" /> -->
<ControlTemplate> <TickBar Name="BottomTickBar" Placement="Bottom" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Top" Margin="0,4,0,0" Grid.Row="2" Grid.ColumnSpan="3" />
<Grid> <Track Name="PART_Track" Grid.Row="1" Grid.ColumnSpan="3" Orientation="Horizontal">
<Ellipse Width="12" Height="12" Fill="{DynamicResource ThemeAccentBrush}"/> <Track.DecreaseButton>
</Grid> <RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</ControlTemplate> <RepeatButton.Template>
</Thumb.Template> <ControlTemplate>
</Thumb> <Grid>
</Track> <Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
</Grid> <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> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>
<Style Selector="Slider:vertical"> <Style Selector="Slider:vertical">
<Setter Property="MinWidth" Value="20"/> <Setter Property="Background" Value="{DynamicResource SliderTrackFill}" />
<Setter Property="MinHeight" Value="40"/> <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"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Grid> <Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid.ColumnDefinitions> <Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
<ColumnDefinition Width="Auto"/> <ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}"
<ColumnDefinition Width="Auto" MinWidth="26"/> Margin="{DynamicResource SliderTopHeaderMargin}" />
<ColumnDefinition Width="Auto"/> <Grid x:Name="SliderContainer" Grid.Row="1">
</Grid.ColumnDefinitions> <Grid.Styles>
<Border Name="TrackBackground" Grid.Column="1" Width="4" Margin="0,6" HorizontalAlignment="Center"/> <Style Selector="TickBar">
<Track Name="PART_Track" Grid.Column="1" Orientation="Vertical" IsDirectionReversed="True"> <Setter Property="ReservedSpace" Value="{Binding #PART_Track.Thumb.Bounds}" />
<Track.DecreaseButton> </Style>
<RepeatButton Name="PART_DecreaseButton" </Grid.Styles>
Classes="repeattrack" /> <Grid x:Name="VerticalTemplate" RowDefinitions="*,Auto,Auto" MinWidth="{DynamicResource SliderVerticalWidth}">
</Track.DecreaseButton> <Grid.ColumnDefinitions>
<Track.IncreaseButton> <ColumnDefinition Width="{DynamicResource SliderPreContentMargin}" />
<RepeatButton Name="PART_IncreaseButton" <ColumnDefinition Width="Auto" />
Classes="repeattrack" /> <ColumnDefinition Width="{DynamicResource SliderPostContentMargin}" />
</Track.IncreaseButton> </Grid.ColumnDefinitions>
<Thumb Name="thumb" MinWidth="20" MinHeight="20"> <TickBar Name="LeftTickBar" Placement="Left" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Right" Margin="0,0,4,0" Grid.RowSpan="3" />
<Thumb.Template> <!-- <TickBar Name="VerticalInlineTickBar" Placement="Inline" Fill="{DynamicResource SliderInlineTickBarFill}" Width="{DynamicResource SliderTrackThemeHeight}" Grid.Column="1" Grid.RowSpan="3" /> -->
<ControlTemplate> <TickBar Name="RightTickBar" Placement="Right" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Column="2" Grid.RowSpan="3" />
<Grid> <Track Name="PART_Track" Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="3" Orientation="Vertical">
<Ellipse Width="12" Height="12" Fill="{DynamicResource ThemeAccentBrush}"/> <Track.DecreaseButton>
</Grid> <RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
</ControlTemplate> <RepeatButton.Template>
</Thumb.Template> <ControlTemplate>
</Thumb> <Grid>
</Track> <Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
</Grid> <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> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>
<Style Selector="Slider /template/ Track#PART_Track"> <Style Selector="Slider /template/ Track#PART_Track">
<Setter Property="Minimum" Value="{TemplateBinding Minimum}"/> <Setter Property="Minimum" Value="{TemplateBinding Minimum}" />
<Setter Property="Maximum" Value="{TemplateBinding Maximum}"/> <Setter Property="Maximum" Value="{TemplateBinding Maximum}" />
<Setter Property="Value" Value="{TemplateBinding Value, Mode=TwoWay}"/> <Setter Property="Value" Value="{TemplateBinding Value, Mode=TwoWay}" />
</Style> </Style>
<Style Selector="Slider /template/ Border#TrackBackground"> <Style Selector="Slider /template/ TickBar">
<Setter Property="BorderThickness" Value="2"/> <Setter Property="Fill" Value="{DynamicResource SliderTickBarFill}" />
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowBrush}"/> <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>
<Style Selector="Slider /template/ RepeatButton.repeattrack">
<Setter Property="Background" Value="Transparent"/> <!-- Normal State -->
<Setter Property="Foreground" Value="{DynamicResource ThemeBorderLowBrush}"/>
<Setter Property="Template"> <Style Selector="Slider /template/ Thumb.SliderThumbStyle">
<ControlTemplate> <Setter Property="Background" Value="{DynamicResource SliderThumbBackground}" />
<Border Background="{TemplateBinding Background}" /> </Style>
</ControlTemplate>
</Setter> <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>
<Style Selector="Slider:disabled /template/ Grid#grid">
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" />
</Style>
</Styles> </Styles>

1
src/Avalonia.Themes.Fluent/TextBox.xaml

@ -27,6 +27,7 @@
Grid.ColumnSpan="2" Grid.ColumnSpan="2"
TextBlock.FontWeight="Normal" TextBlock.FontWeight="Normal"
TextBlock.Foreground="{DynamicResource TextControlHeaderForeground}" TextBlock.Foreground="{DynamicResource TextControlHeaderForeground}"
IsVisible="False"
Margin="{DynamicResource TextBoxTopHeaderMargin}" /> Margin="{DynamicResource TextBoxTopHeaderMargin}" />
<Border Name="border" <Border Name="border"

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

@ -1,38 +1,108 @@
<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"> <Style Selector="ToggleButton">
<Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/> <Setter Property="Background" Value="{DynamicResource ToggleButtonBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowBrush}"/> <Setter Property="Foreground" Value="{DynamicResource ToggleButtonForeground}" />
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/> <Setter Property="BorderBrush" Value="{DynamicResource ToggleButtonBorderBrush}" />
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/> <Setter Property="BorderThickness" Value="{DynamicResource ToggleButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="4"/> <Setter Property="Padding" Value="{DynamicResource ButtonPadding}" />
<Setter Property="HorizontalContentAlignment" Value="Center"/> <Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Center"/> <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"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<ContentPresenter Name="PART_ContentPresenter" <ContentPresenter x:Name="PART_ContentPresenter"
Background="{TemplateBinding Background}" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}" CornerRadius="{DynamicResource ControlCornerRadius}"
Content="{TemplateBinding Content}" Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Padding="{TemplateBinding Padding}" Padding="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/> VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>
<Style Selector="ToggleButton:checked /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
</Style>
<Style Selector="ToggleButton:pointerover /template/ ContentPresenter"> <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>
<Style Selector="ToggleButton:pressed /template/ ContentPresenter"> <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>
<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> </Style>
</Styles> </Styles>

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

@ -1,17 +1,78 @@
<Style xmlns="https://github.com/avaloniaui" Selector="ToolTip"> <Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}"/> <Design.PreviewWith>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/> <Grid RowDefinitions="Auto,Auto"
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/> ColumnDefinitions="Auto,Auto"
<Setter Property="Padding" Value="4,2"/> HorizontalAlignment="Center">
<Setter Property="Template"> <Border Grid.Column="0"
<ControlTemplate> Grid.Row="1"
<ContentPresenter Name="PART_ContentPresenter" Background="{DynamicResource ThemeAccentBrush}"
Background="{TemplateBinding Background}" Margin="5"
BorderBrush="{TemplateBinding BorderBrush}" Padding="50"
BorderThickness="{TemplateBinding BorderThickness}" ToolTip.Tip="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.">
ContentTemplate="{TemplateBinding ContentTemplate}" <TextBlock>Hover Here</TextBlock>
Content="{TemplateBinding Content}" </Border>
Padding="{TemplateBinding Padding}"/> <CheckBox Grid.Column="1"
</ControlTemplate> Margin="5"
</Setter> Grid.Row="0"
</Style> 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.Platform;
using Avalonia.Rendering.SceneGraph; using Avalonia.Rendering.SceneGraph;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.Visuals.Media.Imaging; using Avalonia.Visuals.Media.Imaging;
namespace Avalonia.Media namespace Avalonia.Media
@ -154,12 +155,12 @@ namespace Avalonia.Media
return; return;
} }
if (Math.Abs(radiusX) > double.Epsilon) if (!MathUtilities.IsZero(radiusX))
{ {
radiusX = Math.Min(radiusX, rect.Width / 2); radiusX = Math.Min(radiusX, rect.Width / 2);
} }
if (Math.Abs(radiusY) > double.Epsilon) if (!MathUtilities.IsZero(radiusY))
{ {
radiusY = Math.Min(radiusY, rect.Height / 2); radiusY = Math.Min(radiusY, rect.Height / 2);
} }

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

@ -4,6 +4,7 @@ using System.Linq;
using Avalonia.Media.Immutable; using Avalonia.Media.Immutable;
using Avalonia.Media.TextFormatting.Unicode; using Avalonia.Media.TextFormatting.Unicode;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Utilities;
using Avalonia.Utility; using Avalonia.Utility;
namespace Avalonia.Media.TextFormatting namespace Avalonia.Media.TextFormatting
@ -184,7 +185,7 @@ namespace Avalonia.Media.TextFormatting
/// </summary> /// </summary>
private void UpdateLayout() 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); var textLine = CreateEmptyTextLine(0);

35
src/Avalonia.X11/X11Atoms.cs

@ -22,6 +22,7 @@
// //
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using static Avalonia.X11.XLib; using static Avalonia.X11.XLib;
// ReSharper disable FieldCanBeMadeReadOnly.Global // ReSharper disable FieldCanBeMadeReadOnly.Global
@ -40,8 +41,9 @@ namespace Avalonia.X11
internal class X11Atoms internal class X11Atoms
{ {
private readonly IntPtr _display;
// Our atoms // Our atoms
public readonly IntPtr AnyPropertyType = (IntPtr)0; public readonly IntPtr AnyPropertyType = (IntPtr)0;
public readonly IntPtr XA_PRIMARY = (IntPtr)1; public readonly IntPtr XA_PRIMARY = (IntPtr)1;
public readonly IntPtr XA_SECONDARY = (IntPtr)2; public readonly IntPtr XA_SECONDARY = (IntPtr)2;
@ -187,10 +189,13 @@ namespace Avalonia.X11
public readonly IntPtr ATOM_PAIR; public readonly IntPtr ATOM_PAIR;
public readonly IntPtr MANAGER; public readonly IntPtr MANAGER;
public readonly IntPtr _KDE_NET_WM_BLUR_BEHIND_REGION; 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) public X11Atoms(IntPtr display)
{ {
_display = display;
// make sure this array stays in sync with the statements below // 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); XInternAtoms(display, atomNames, atomNames.Length, true, atoms);
for (var c = 0; c < fields.Length; c++) 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]); 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;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Input;
using Avalonia.Input.Platform; using Avalonia.Input.Platform;
using static Avalonia.X11.XLib; using static Avalonia.X11.XLib;
namespace Avalonia.X11 namespace Avalonia.X11
@ -10,12 +12,14 @@ namespace Avalonia.X11
class X11Clipboard : IClipboard class X11Clipboard : IClipboard
{ {
private readonly X11Info _x11; private readonly X11Info _x11;
private string _storedString; private IDataObject _storedDataObject;
private IntPtr _handle; private IntPtr _handle;
private TaskCompletionSource<IntPtr[]> _requestedFormatsTcs; private TaskCompletionSource<IntPtr[]> _requestedFormatsTcs;
private TaskCompletionSource<string> _requestedTextTcs; private TaskCompletionSource<object> _requestedDataTcs;
private readonly IntPtr[] _textAtoms; private readonly IntPtr[] _textAtoms;
private readonly IntPtr _avaloniaSaveTargetsAtom; 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) public X11Clipboard(AvaloniaX11Platform platform)
{ {
@ -31,6 +35,11 @@ namespace Avalonia.X11
}.Where(a => a != IntPtr.Zero).ToArray(); }.Where(a => a != IntPtr.Zero).ToArray();
} }
bool IsStringAtom(IntPtr atom)
{
return _textAtoms.Contains(atom);
}
Encoding GetStringEncoding(IntPtr atom) Encoding GetStringEncoding(IntPtr atom)
{ {
return (atom == _x11.Atoms.XA_STRING return (atom == _x11.Atoms.XA_STRING
@ -75,21 +84,31 @@ namespace Avalonia.X11
Encoding textEnc; Encoding textEnc;
if (target == _x11.Atoms.TARGETS) if (target == _x11.Atoms.TARGETS)
{ {
var atoms = _textAtoms; var atoms = new HashSet<IntPtr> { _x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE };
atoms = atoms.Concat(new[] {_x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE}) foreach (var fmt in _storedDataObject.GetDataFormats())
.ToArray(); {
if (fmt == DataFormats.Text)
foreach (var ta in _textAtoms)
atoms.Add(ta);
else
atoms.Add(_x11.Atoms.GetAtom(fmt));
}
XChangeProperty(_x11.Display, window, property, 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; return property;
} }
else if(target == _x11.Atoms.SAVE_TARGETS && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero) else if(target == _x11.Atoms.SAVE_TARGETS && _x11.Atoms.SAVE_TARGETS != IntPtr.Zero)
{ {
return property; return property;
} }
else if ((textEnc = GetStringEncoding(target)) != null) else if ((textEnc = GetStringEncoding(target)) != null
&& _storedDataObject?.Contains(DataFormats.Text) == true)
{ {
var text = _storedDataObject.GetText();
var data = textEnc.GetBytes(_storedString ?? ""); if(text == null)
return IntPtr.Zero;
var data = textEnc.GetBytes(text);
fixed (void* pdata = data) fixed (void* pdata = data)
XChangeProperty(_x11.Display, window, property, target, 8, XChangeProperty(_x11.Display, window, property, target, 8,
PropertyMode.Replace, PropertyMode.Replace,
@ -121,6 +140,23 @@ namespace Avalonia.X11
return property; 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 else
return IntPtr.Zero; return IntPtr.Zero;
} }
@ -131,15 +167,15 @@ namespace Avalonia.X11
if (sel.property == IntPtr.Zero) if (sel.property == IntPtr.Zero)
{ {
_requestedFormatsTcs?.TrySetResult(null); _requestedFormatsTcs?.TrySetResult(null);
_requestedTextTcs?.TrySetResult(null); _requestedDataTcs?.TrySetResult(null);
} }
XGetWindowProperty(_x11.Display, _handle, sel.property, IntPtr.Zero, new IntPtr (0x7fffffff), true, (IntPtr)Atom.AnyPropertyType, 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; Encoding textEnc = null;
if (nitems == IntPtr.Zero) if (nitems == IntPtr.Zero)
{ {
_requestedFormatsTcs?.TrySetResult(null); _requestedFormatsTcs?.TrySetResult(null);
_requestedTextTcs?.TrySetResult(null); _requestedDataTcs?.TrySetResult(null);
} }
else else
{ {
@ -154,10 +190,24 @@ namespace Avalonia.X11
_requestedFormatsTcs?.TrySetResult(formats); _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()); 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; return _requestedFormatsTcs.Task;
} }
Task<string> SendTextRequest(IntPtr format) Task<object> SendDataRequest(IntPtr format)
{ {
if (_requestedTextTcs == null || _requestedFormatsTcs.Task.IsCompleted) if (_requestedDataTcs == null || _requestedFormatsTcs.Task.IsCompleted)
_requestedTextTcs = new TaskCompletionSource<string>(); _requestedDataTcs = new TaskCompletionSource<object>();
XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD, format, format, _handle, IntPtr.Zero); 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() public async Task<string> GetTextAsync()
{ {
if (XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD) == IntPtr.Zero) if (!HasOwner)
return null; return null;
var res = await SendFormatRequest(); var res = await SendFormatRequest();
var target = _x11.Atoms.UTF8_STRING; 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) void StoreAtomsInClipboardManager(IntPtr[] atoms)
@ -220,15 +272,52 @@ namespace Avalonia.X11
public Task SetTextAsync(string text) 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); XSetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD, _handle, IntPtr.Zero);
StoreAtomsInClipboardManager(_textAtoms); StoreAtomsInClipboardManager(_textAtoms);
return Task.CompletedTask; 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);
} }
} }
} }

18
src/Avalonia.X11/XI2Manager.cs

@ -97,7 +97,7 @@ namespace Avalonia.X11
{ {
_platform = platform; _platform = platform;
_x11 = platform.Info; _x11 = platform.Info;
_multitouch = platform.Options?.EnableMultiTouch ?? false; _multitouch = platform.Options?.EnableMultiTouch ?? true;
var devices =(XIDeviceInfo*) XIQueryDevice(_x11.Display, var devices =(XIDeviceInfo*) XIQueryDevice(_x11.Display,
(int)XiPredefinedDeviceId.XIAllMasterDevices, out int num); (int)XiPredefinedDeviceId.XIAllMasterDevices, out int num);
for (var c = 0; c < num; c++) for (var c = 0; c < num; c++)
@ -237,6 +237,22 @@ namespace Avalonia.X11
RawPointerEventType.Move, ev.Position, ev.Modifiers)); RawPointerEventType.Move, ev.Position, ev.Modifiers));
} }
if (ev.Type == XiEventType.XI_ButtonPress && ev.Button >= 4 && ev.Button <= 7 && !ev.Emulated)
{
Vector? scrollDelta = ev.Button switch
{
4 => new Vector(0, 1),
5 => new Vector(0, -1),
6 => new Vector(1, 0),
7 => new Vector(-1, 0),
_ => null
};
if (scrollDelta.HasValue)
client.ScheduleXI2Input(new RawMouseWheelEventArgs(client.MouseDevice, ev.Timestamp,
client.InputRoot, ev.Position, scrollDelta.Value, ev.Modifiers));
}
if (ev.Type == XiEventType.XI_ButtonPress || ev.Type == XiEventType.XI_ButtonRelease) if (ev.Type == XiEventType.XI_ButtonPress || ev.Type == XiEventType.XI_ButtonRelease)
{ {
var down = ev.Type == XiEventType.XI_ButtonPress; var down = ev.Type == XiEventType.XI_ButtonPress;

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, public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
int format, PropertyMode mode, ref IntPtr value, int nelements); 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)] [DllImport(libX11)]
public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type, public static extern int XChangeProperty(IntPtr display, IntPtr window, IntPtr property, IntPtr type,
int format, PropertyMode mode, uint[] data, int nelements); int format, PropertyMode mode, uint[] data, int nelements);

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) 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 culture = CultureInfo.CurrentCulture;
var converted = converter.Convert(values, targetType, ConverterParameter, culture); 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))); Math.Max(rrect.RadiiTopRight.X, Math.Max(rrect.RadiiBottomRight.X, rrect.RadiiBottomLeft.X)));
var radiusY = Math.Max(rrect.RadiiTopLeft.Y, var radiusY = Math.Max(rrect.RadiiTopLeft.Y,
Math.Max(rrect.RadiiTopRight.Y, Math.Max(rrect.RadiiBottomRight.Y, rrect.RadiiBottomLeft.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) if (brush != null)
{ {

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

Loading…
Cancel
Save