Browse Source

Merge branch 'master' into features/Controls/HotkeyManager_Without_Command

pull/7500/head
Max Katz 5 years ago
committed by GitHub
parent
commit
748515b97d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      native/Avalonia.Native/src/OSX/controlhost.mm
  2. 9
      native/Avalonia.Native/src/OSX/window.mm
  3. 2
      readme.md
  4. 32
      samples/ControlCatalog/Pages/ButtonsPage.xaml
  5. 5
      samples/ControlCatalog/Pages/CanvasPage.xaml
  6. 3
      samples/ControlCatalog/Pages/PointersPage.cs
  7. 3
      samples/RenderDemo/MainWindow.xaml
  8. 7
      samples/RenderDemo/Pages/TextFormatterPage.axaml
  9. 118
      samples/RenderDemo/Pages/TextFormatterPage.axaml.cs
  10. 4
      samples/RenderDemo/RenderDemo.csproj
  11. 18
      samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml
  12. 16
      src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
  13. 11
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  14. 2
      src/Avalonia.Animation/Easing/Easing.cs
  15. 2
      src/Avalonia.Base/Collections/AvaloniaDictionary.cs
  16. 2
      src/Avalonia.Base/Collections/AvaloniaList.cs
  17. 2
      src/Avalonia.Base/Data/Core/PropertyPath.cs
  18. 10
      src/Avalonia.Base/StyledPropertyBase.cs
  19. 2
      src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs
  20. 2
      src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs
  21. 2
      src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs
  22. 26
      src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs
  23. 2
      src/Avalonia.Controls.DataGrid/Themes/Default.xaml
  24. 2
      src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
  25. 17
      src/Avalonia.Controls/ApiCompatBaseline.txt
  26. 2
      src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
  27. 8
      src/Avalonia.Controls/AutoCompleteBox.cs
  28. 119
      src/Avalonia.Controls/Button.cs
  29. 2
      src/Avalonia.Controls/ButtonSpinner.cs
  30. 21
      src/Avalonia.Controls/Calendar/Calendar.cs
  31. 5
      src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
  32. 5
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  33. 4
      src/Avalonia.Controls/Chrome/CaptionButtons.cs
  34. 1
      src/Avalonia.Controls/Chrome/TitleBar.cs
  35. 2
      src/Avalonia.Controls/ComboBox.cs
  36. 2
      src/Avalonia.Controls/ContentControl.cs
  37. 24
      src/Avalonia.Controls/Control.cs
  38. 9
      src/Avalonia.Controls/DateTimePickers/DatePicker.cs
  39. 20
      src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs
  40. 12
      src/Avalonia.Controls/DateTimePickers/TimePicker.cs
  41. 17
      src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs
  42. 167
      src/Avalonia.Controls/Documents/TextElement.cs
  43. 15
      src/Avalonia.Controls/DropDownButton.cs
  44. 9
      src/Avalonia.Controls/Flyouts/MenuFlyoutPresenter.cs
  45. 12
      src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
  46. 2
      src/Avalonia.Controls/ListBox.cs
  47. 1
      src/Avalonia.Controls/MenuItem.cs
  48. 1
      src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
  49. 5
      src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
  50. 10
      src/Avalonia.Controls/Platform/IPlatformNativeSurfaceHandle.cs
  51. 69
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  52. 5
      src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositionerPopupImplHelper.cs
  53. 7
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  54. 4
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  55. 10
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  56. 31
      src/Avalonia.Controls/Primitives/TemplatedControl.cs
  57. 1
      src/Avalonia.Controls/ProgressBar.cs
  58. 3
      src/Avalonia.Controls/ScrollViewer.cs
  59. 4
      src/Avalonia.Controls/Selection/InternalSelectionModel.cs
  60. 126
      src/Avalonia.Controls/Shapes/Rectangle.cs
  61. 3
      src/Avalonia.Controls/Slider.cs
  62. 34
      src/Avalonia.Controls/SplitButton/SplitButton.cs
  63. 1
      src/Avalonia.Controls/SplitView.cs
  64. 2
      src/Avalonia.Controls/TabControl.cs
  65. 201
      src/Avalonia.Controls/TextBlock.cs
  66. 112
      src/Avalonia.Controls/TextBox.cs
  67. 2
      src/Avalonia.Controls/ToggleSwitch.cs
  68. 2
      src/Avalonia.Controls/TopLevel.cs
  69. 2
      src/Avalonia.Controls/TreeView.cs
  70. 1
      src/Avalonia.Controls/TreeViewItem.cs
  71. 4
      src/Avalonia.Controls/Utils/CollectionChangedEventManager.cs
  72. 7
      src/Avalonia.Controls/Window.cs
  73. 24
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/package-lock.json
  74. 6
      src/Avalonia.Diagnostics/Diagnostics/DevTools.cs
  75. 5
      src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs
  76. 5
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/BindingSetterViewModel.cs
  77. 49
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs
  78. 3
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/ResourceSetterViewModel.cs
  79. 4
      src/Avalonia.Diagnostics/Diagnostics/Views/ConsoleView.xaml
  80. 62
      src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml
  81. 24
      src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml.cs
  82. 2
      src/Avalonia.Diagnostics/Diagnostics/Views/LayoutExplorerView.axaml
  83. 32
      src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs
  84. 3
      src/Avalonia.Dialogs/ManagedFileChooser.cs
  85. 7
      src/Avalonia.Headless/HeadlessPlatformStubs.cs
  86. 2
      src/Avalonia.Input/FocusManager.cs
  87. 2
      src/Avalonia.Input/TouchDevice.cs
  88. 13
      src/Avalonia.Styling/Controls/Metadata/PseudoClassesAttribute.cs
  89. 55
      src/Avalonia.Styling/Controls/Metadata/TemplatePartAttribute.cs
  90. 2
      src/Avalonia.Themes.Default/Controls/Button.xaml
  91. 2
      src/Avalonia.Themes.Default/Controls/CaptionButtons.xaml
  92. 2
      src/Avalonia.Themes.Default/Controls/CheckBox.xaml
  93. 18
      src/Avalonia.Themes.Default/Controls/DatePicker.xaml
  94. 67
      src/Avalonia.Themes.Default/Controls/DropDownButton.xaml
  95. 2
      src/Avalonia.Themes.Default/Controls/RepeatButton.xaml
  96. 26
      src/Avalonia.Themes.Default/Controls/SplitButton.xaml
  97. 12
      src/Avalonia.Themes.Default/Controls/TimePicker.xaml
  98. 2
      src/Avalonia.Themes.Default/Controls/ToggleButton.xaml
  99. 5
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  100. 28
      src/Avalonia.Themes.Fluent/Controls/Button.xaml

3
native/Avalonia.Native/src/OSX/controlhost.mm

@ -36,7 +36,10 @@ public:
virtual void DestroyDefaultChild(void* child) override
{
// ARC will release the object for us
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-value"
(__bridge_transfer NSView*) child;
#pragma clang diagnostic pop
}
};

9
native/Avalonia.Native/src/OSX/window.mm

@ -457,7 +457,8 @@ public:
}
point = ConvertPointY(point);
auto viewPoint = [Window convertScreenToBase:ToNSPoint(point)];
NSRect convertRect = [Window convertRectToScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)];
auto viewPoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y);
*ret = [View translateLocalPoint:ToAvnPoint(viewPoint)];
@ -477,7 +478,8 @@ public:
}
auto cocoaViewPoint = ToNSPoint([View translateLocalPoint:point]);
auto cocoaScreenPoint = [Window convertBaseToScreen:cocoaViewPoint];
NSRect convertRect = [Window convertRectToScreen:NSMakeRect(cocoaViewPoint.x, cocoaViewPoint.y, 0.0, 0.0)];
auto cocoaScreenPoint = NSPointFromCGPoint(NSMakePoint(convertRect.origin.x, convertRect.origin.y));
*ret = ConvertPointY(ToAvnPoint(cocoaScreenPoint));
return S_OK;
@ -573,7 +575,8 @@ public:
if(!((nseventType >= NSEventTypeLeftMouseDown && nseventType <= NSEventTypeMouseExited)
|| (nseventType >= NSEventTypeOtherMouseDown && nseventType <= NSEventTypeOtherMouseDragged)))
{
auto nspoint = [Window convertBaseToScreen: ToNSPoint(point)];
NSRect convertRect = [Window convertRectToScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)];
auto nspoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y);
CGPoint cgpoint = NSPointToCGPoint(nspoint);
auto cgevent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, cgpoint, kCGMouseButtonLeft);
nsevent = [NSEvent eventWithCGEvent: cgevent];

2
readme.md

@ -1,7 +1,7 @@
[![Telegram](https://raw.githubusercontent.com/Patrolavia/telegram-badge/master/chat.svg)](https://t.me/Avalonia)
[![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) [![Discord](https://img.shields.io/badge/discord-join%20chat-46BC99)]( https://aka.ms/dotnet-discord) [![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)
[![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) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg)
## 📖 About

32
samples/ControlCatalog/Pages/ButtonsPage.xaml

@ -147,6 +147,35 @@
</StackPanel>
</Border>
<!-- DropDownButton -->
<Border Classes="header-border">
<StackPanel Orientation="Vertical"
Spacing="4">
<TextBlock Text="DropDownButton"
Classes="header" />
<TextBlock TextWrapping="Wrap">A button with an added drop-down chevron to visually indicate it has a flyout with additional actions.</TextBlock>
</StackPanel>
</Border>
<Border Classes="thin"
Padding="15">
<StackPanel Orientation="Vertical"
Spacing="8">
<DropDownButton Flyout="{StaticResource SharedMenuFlyout}">
<TextBlock Text="Drop Down Button" />
</DropDownButton>
<DropDownButton Padding="0,0,8,0">
<Border Background="Teal"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="32"
Width="32" />
</DropDownButton>
<DropDownButton IsEnabled="False">Disabled</DropDownButton>
<DropDownButton />
</StackPanel>
</Border>
<!-- SplitButton -->
<Border Classes="header-border">
<StackPanel Orientation="Vertical"
@ -169,7 +198,8 @@
<TextBlock Text="Disabled" />
</SplitButton>
<SplitButton Flyout="{StaticResource SharedMenuFlyout}"
Content="Re-themed">
Content="Re-themed"
Foreground="White">
<SplitButton.Styles>
<Style>
<Style.Resources>

5
samples/ControlCatalog/Pages/CanvasPage.xaml

@ -4,7 +4,7 @@
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h2">A panel which lays out its children by explicit coordinates</TextBlock>
<Canvas Background="Yellow" Width="300" Height="400">
<Rectangle Fill="Blue" Width="63" Height="41" Canvas.Left="40" Canvas.Top="31">
<Rectangle Fill="Blue" Width="63" Height="41" Canvas.Left="40" Canvas.Top="31" RadiusX="10" RadiusY="10">
<Rectangle.OpacityMask>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<LinearGradientBrush.GradientStops>
@ -12,8 +12,9 @@
<GradientStop Offset="1" Color="Transparent"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.OpacityMask>
</Rectangle.OpacityMask>
</Rectangle>
<Rectangle Fill="Green" Stroke="Black" StrokeThickness="2" Width="40" Height="20" Canvas.Left="150" Canvas.Top="10" RadiusX="10" RadiusY="5" />
<Ellipse Fill="Green" Width="58" Height="58" Canvas.Left="88" Canvas.Top="100"/>
<Path Fill="Orange" Data="M 0,0 c 0,0 50,0 50,-50 c 0,0 50,0 50,50 h -50 v 50 l -50,-50 Z" Canvas.Left="30" Canvas.Top="250"/>
<Path Fill="OrangeRed" Canvas.Left="180" Canvas.Top="250">

3
samples/ControlCatalog/Pages/PointersPage.cs

@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Media;
@ -131,7 +132,7 @@ public class PointersPage : Decorator
{
public PointerIntermediatePointsTab()
{
this[TextBlock.ForegroundProperty] = Brushes.Black;
this[TextElement.ForegroundProperty] = Brushes.Black;
var slider = new Slider
{
Margin = new Thickness(5),

3
samples/RenderDemo/MainWindow.xaml

@ -60,6 +60,9 @@
<TabItem Header="FormattedText">
<pages:FormattedTextPage />
</TabItem>
<TabItem Header="TextFormatter">
<pages:TextFormatterPage />
</TabItem>
<TabItem Header="LineBounds">
<pages:LineBoundsPage />
</TabItem>

7
samples/RenderDemo/Pages/TextFormatterPage.axaml

@ -0,0 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="RenderDemo.Pages.TextFormatterPage">
</UserControl>

118
samples/RenderDemo/Pages/TextFormatterPage.axaml.cs

@ -0,0 +1,118 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;
namespace RenderDemo.Pages
{
public class TextFormatterPage : UserControl
{
private TextLine _textLine;
public TextFormatterPage()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public override void Render(DrawingContext context)
{
_textLine?.Draw(context, new Point());
}
protected override Size MeasureOverride(Size availableSize)
{
var defaultRunProperties = new GenericTextRunProperties(Typeface.Default, foregroundBrush: Brushes.Black,
baselineAlignment: BaselineAlignment.Center);
var paragraphProperties = new GenericTextParagraphProperties(defaultRunProperties);
var control = new Button { Content = new TextBlock { Text = "ClickMe" } };
Content = control;
var textSource = new CustomTextSource(control, defaultRunProperties);
control.Measure(Size.Infinity);
_textLine =
TextFormatter.Current.FormatLine(textSource, 0, double.PositiveInfinity, paragraphProperties);
return base.MeasureOverride(availableSize);
}
protected override Size ArrangeOverride(Size finalSize)
{
var currentX = 0d;
foreach (var textRun in _textLine.TextRuns)
{
if (textRun is ControlRun controlRun)
{
controlRun.Control.Arrange(new Rect(new Point(currentX, 0), controlRun.Size));
}
if (textRun is DrawableTextRun drawableTextRun)
{
currentX += drawableTextRun.Size.Width;
}
}
return finalSize;
}
private class CustomTextSource : ITextSource
{
private readonly Control _control;
private readonly TextRunProperties _defaultProperties;
private readonly string _text = "<-Hello World->";
public CustomTextSource(Control control, TextRunProperties defaultProperties)
{
_control = control;
_defaultProperties = defaultProperties;
}
public TextRun? GetTextRun(int textSourceIndex)
{
if (textSourceIndex >= _text.Length * 2 + TextRun.DefaultTextSourceLength)
{
return null;
}
if (textSourceIndex == _text.Length)
{
return new ControlRun(_control, _defaultProperties);
}
return new TextCharacters(_text.AsMemory(), _defaultProperties);
}
}
private class ControlRun : DrawableTextRun
{
private readonly Control _control;
public ControlRun(Control control, TextRunProperties properties)
{
_control = control;
Properties = properties;
}
public Control Control => _control;
public override Size Size => _control.DesiredSize;
public override double Baseline => 0;
public override TextRunProperties? Properties { get; }
public override void Draw(DrawingContext drawingContext, Point origin)
{
// noop
}
}
}
}

4
samples/RenderDemo/RenderDemo.csproj

@ -5,6 +5,10 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\src\Avalonia.Visuals\Rendering\SceneGraph\LineBoundsHelper.cs" Link="LineBoundsHelper.cs" />
<Compile Update="Pages\TextFormatterPage.axaml.cs">
<DependentUpon>TextFormatterPage.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />

18
samples/SampleControls/HamburgerMenu/HamburgerMenu.xaml

@ -195,9 +195,9 @@
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
TextBlock.FontFamily="{TemplateBinding FontFamily}"
TextBlock.FontSize="{TemplateBinding FontSize}"
TextBlock.FontWeight="{TemplateBinding FontWeight}" />
TextElement.FontFamily="{TemplateBinding FontFamily}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontWeight="{TemplateBinding FontWeight}" />
</Panel>
</Border>
</ControlTemplate>
@ -216,25 +216,25 @@
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CornerRadius="{TemplateBinding CornerRadius}"
TextBlock.FontFamily="{TemplateBinding FontFamily}"
TextBlock.FontSize="{TemplateBinding FontSize}"
TextBlock.FontWeight="{TemplateBinding FontWeight}" />
TextElement.FontFamily="{TemplateBinding FontFamily}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontWeight="{TemplateBinding FontWeight}" />
</ControlTemplate>
</Setter>
</Style>
<Style Selector="catalog|HamburgerMenu > TabItem /template/ Border#PART_LayoutRoot, :is(Button).NavigationButton /template/ ContentPresenter">
<Setter Property="Border.Background" Value="Transparent" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemBaseHighColor}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SystemBaseHighColor}" />
</Style>
<Style Selector="catalog|HamburgerMenu > TabItem:pointerover /template/ Border#PART_LayoutRoot, :is(Button).NavigationButton:pointerover /template/ ContentPresenter">
<Setter Property="Border.Background" Value="{DynamicResource SystemChromeLowColor}" />
<Setter Property="Border.BoxShadow" Value="{StaticResource NavigationItemShadow}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TabItemHeaderForegroundUnselectedPointerOver}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource TabItemHeaderForegroundUnselectedPointerOver}" />
</Style>
<Style Selector="catalog|HamburgerMenu > TabItem:pressed /template/ Border#PART_LayoutRoot, :is(Button).NavigationButton:pressed /template/ ContentPresenter">
<Setter Property="Border.Background" Value="{DynamicResource SystemChromeLowColor}" />
<Setter Property="Border.BoxShadow" Value="{StaticResource NavigationItemShadow}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TabItemHeaderForegroundUnselectedPressed}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource TabItemHeaderForegroundUnselectedPressed}" />
</Style>
<Style Selector=":is(Button).NavigationButton:pressed">
<Setter Property="RenderTransform" Value="none" />

16
src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs

@ -2,18 +2,22 @@ using System;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Platform;
namespace Avalonia.Android
{
public abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle
public abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformNativeSurfaceHandle
{
bool _invalidateQueued;
readonly object _lock = new object();
private readonly Handler _handler;
IntPtr IPlatformHandle.Handle =>
AndroidFramebuffer.ANativeWindow_fromSurface(JNIEnv.Handle, Holder.Surface.Handle);
public InvalidationAwareSurfaceView(Context context) : base(context)
{
@ -25,7 +29,7 @@ namespace Avalonia.Android
{
lock (_lock)
{
if(_invalidateQueued)
if (_invalidateQueued)
return;
_handler.Post(() =>
{
@ -70,7 +74,7 @@ namespace Avalonia.Android
public void SurfaceDestroyed(ISurfaceHolder holder)
{
Log.Info("AVALONIA", "Surface Destroyed");
}
protected void DoDraw()
@ -83,5 +87,9 @@ namespace Avalonia.Android
}
protected abstract void Draw();
public string HandleDescriptor => "SurfaceView";
public PixelSize Size => new PixelSize(Holder.SurfaceFrame.Width(), Holder.SurfaceFrame.Height());
public double Scaling => Resources.DisplayMetrics.Density;
}
}

11
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using Android.Content;
using Android.Graphics;
using Android.Runtime;
using Android.Views;
using Android.Views.InputMethods;
using Avalonia.Android.OpenGL;
@ -38,11 +37,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_keyboardHelper = new AndroidKeyboardEventsHelper<TopLevelImpl>(this);
_touchHelper = new AndroidTouchEventsHelper<TopLevelImpl>(this, () => InputRoot,
GetAvaloniaPointFromEvent);
_gl = GlPlatformSurface.TryCreate(this);
_framebuffer = new FramebufferManager(this);
RenderScaling = (int)_view.Resources.DisplayMetrics.Density;
RenderScaling = (int)_view.Scaling;
MaxClientSize = new PixelSize(_view.Resources.DisplayMetrics.WidthPixels,
_view.Resources.DisplayMetrics.HeightPixels).ToSize(RenderScaling);
@ -77,7 +75,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IPlatformHandle Handle => _view;
public IEnumerable<object> Surfaces => new object[] { _gl, _framebuffer };
public IEnumerable<object> Surfaces => new object[] { _gl, _framebuffer, Handle };
public IRenderer CreateRenderer(IRenderRoot root) =>
AndroidPlatform.Options.UseDeferredRendering
@ -216,10 +214,9 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => new AcrylicPlatformCompensationLevels(1, 1, 1);
IntPtr EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo.Handle =>
AndroidFramebuffer.ANativeWindow_fromSurface(JNIEnv.Handle, _view.Holder.Surface.Handle);
IntPtr EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo.Handle => ((IPlatformHandle)_view).Handle;
public PixelSize Size => new PixelSize(_view.Holder.SurfaceFrame.Width(), _view.Holder.SurfaceFrame.Height());
public PixelSize Size => _view.Size;
public double Scaling => RenderScaling;

2
src/Avalonia.Animation/Easing/Easing.cs

@ -39,7 +39,7 @@ namespace Avalonia.Animation.Easings
var derivedTypes = typeof(Easing).Assembly.GetTypes()
.Where(p => p.Namespace == s_thisType.Namespace)
.Where(p => p.IsSubclassOf(s_thisType))
.Select(p => p).ToList();
.Select(p => p);
foreach (var easingType in derivedTypes)
_easingTypes.Add(easingType.Name, easingType);

2
src/Avalonia.Base/Collections/AvaloniaDictionary.cs

@ -123,7 +123,7 @@ namespace Avalonia.Collections
{
var e = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Remove,
old.ToList(),
old.ToArray(),
-1);
CollectionChanged(this, e);
}

2
src/Avalonia.Base/Collections/AvaloniaList.cs

@ -222,7 +222,7 @@ namespace Avalonia.Collections
{
var e = ResetBehavior == ResetBehavior.Reset ?
EventArgsCache.ResetCollectionChanged :
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, _inner.ToList(), 0);
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, _inner.ToArray(), 0);
_inner.Clear();

2
src/Avalonia.Base/Data/Core/PropertyPath.cs

@ -10,7 +10,7 @@ namespace Avalonia.Data.Core
public PropertyPath(IEnumerable<IPropertyPathElement> elements)
{
Elements = elements.ToList();
Elements = elements.ToArray();
}
}

10
src/Avalonia.Base/StyledPropertyBase.cs

@ -159,9 +159,9 @@ namespace Avalonia
}
/// <inheritdoc/>
public override void Accept<TData>(IAvaloniaPropertyVisitor<TData> vistor, ref TData data)
public override void Accept<TData>(IAvaloniaPropertyVisitor<TData> visitor, ref TData data)
{
vistor.Visit(this, ref data);
visitor.Visit(this, ref data);
}
/// <summary>
@ -242,11 +242,5 @@ namespace Avalonia
_ = type ?? throw new ArgumentNullException(nameof(type));
return GetMetadata(type).DefaultValue;
}
[DebuggerHidden]
private Func<IAvaloniaObject, TValue, TValue> Cast<THost>(Func<THost, TValue, TValue> validate)
{
return (o, v) => validate((THost)o, v);
}
}
}

2
src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs

@ -23,7 +23,7 @@ namespace Avalonia.Utilities
var assetDoc = XDocument.Load(stream);
XNamespace assetNs = assetDoc.Root!.Attribute("xmlns")!.Value;
List<AvaloniaResourcesIndexEntry> entries=
List<AvaloniaResourcesIndexEntry> entries =
(from entry in assetDoc.Root.Element(assetNs + "Entries")!.Elements(assetNs + "AvaloniaResourcesIndexEntry")
select new AvaloniaResourcesIndexEntry
{

2
src/Avalonia.Build.Tasks/GenerateAvaloniaResourcesTask.cs

@ -105,7 +105,7 @@ namespace Avalonia.Build.Tasks
{
var typeToXamlIndex = new Dictionary<string, string>();
foreach (var s in sources.ToList())
foreach (var s in sources.ToArray())
{
if (s.Path.ToLowerInvariant().EndsWith(".xaml") || s.Path.ToLowerInvariant().EndsWith(".paml") || s.Path.ToLowerInvariant().EndsWith(".axaml"))
{

2
src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs

@ -3946,7 +3946,7 @@ namespace Avalonia.Collections
{
sort.Initialize(itemType);
if(seq is IOrderedEnumerable<object> orderedEnum)
if (seq is IOrderedEnumerable<object> orderedEnum)
{
seq = sort.ThenBy(orderedEnum);
}

26
src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs

@ -10,6 +10,7 @@ using System;
using System.ComponentModel;
using Avalonia.Layout;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Controls.Documents;
namespace Avalonia.Controls
{
@ -32,7 +33,7 @@ namespace Avalonia.Controls
/// Identifies the FontFamily dependency property.
/// </summary>
public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
TextBlock.FontFamilyProperty.AddOwner<DataGridTextColumn>();
TextElement.FontFamilyProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font name.
@ -47,7 +48,7 @@ namespace Avalonia.Controls
/// Identifies the FontSize dependency property.
/// </summary>
public static readonly AttachedProperty<double> FontSizeProperty =
TextBlock.FontSizeProperty.AddOwner<DataGridTextColumn>();
TextElement.FontSizeProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font size.
@ -64,7 +65,7 @@ namespace Avalonia.Controls
/// Identifies the FontStyle dependency property.
/// </summary>
public static readonly AttachedProperty<FontStyle> FontStyleProperty =
TextBlock.FontStyleProperty.AddOwner<DataGridTextColumn>();
TextElement.FontStyleProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font style.
@ -79,7 +80,7 @@ namespace Avalonia.Controls
/// Identifies the FontWeight dependency property.
/// </summary>
public static readonly AttachedProperty<FontWeight> FontWeightProperty =
TextBlock.FontWeightProperty.AddOwner<DataGridTextColumn>();
TextElement.FontWeightProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font weight or thickness.
@ -90,11 +91,26 @@ namespace Avalonia.Controls
set => SetValue(FontWeightProperty, value);
}
/// <summary>
/// Identifies the FontStretch dependency property.
/// </summary>
public static readonly AttachedProperty<FontStretch> FontStretchProperty =
TextElement.FontStretchProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font weight or thickness.
/// </summary>
public FontStretch FontStretch
{
get => GetValue(FontStretchProperty);
set => SetValue(FontStretchProperty, value);
}
/// <summary>
/// Identifies the Foreground dependency property.
/// </summary>
public static readonly AttachedProperty<IBrush> ForegroundProperty =
TextBlock.ForegroundProperty.AddOwner<DataGridTextColumn>();
TextElement.ForegroundProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets a brush that describes the foreground of the column cells.

2
src/Avalonia.Controls.DataGrid/Themes/Default.xaml

@ -17,7 +17,7 @@
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
TextElement.Foreground="{TemplateBinding Foreground}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>

2
src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml

@ -124,7 +124,7 @@
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
TextElement.Foreground="{TemplateBinding Foreground}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />

17
src/Avalonia.Controls/ApiCompatBaseline.txt

@ -29,6 +29,21 @@ MembersMustExist : Member 'public void Avalonia.Controls.NumericUpDownValueChang
MembersMustExist : Member 'public System.Double Avalonia.Controls.NumericUpDownValueChangedEventArgs.NewValue.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.Double Avalonia.Controls.NumericUpDownValueChangedEventArgs.OldValue.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<System.Boolean> Avalonia.StyledProperty<System.Boolean> Avalonia.Controls.ScrollViewer.AllowAutoHideProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.AttachedProperty<Avalonia.Media.FontFamily> Avalonia.AttachedProperty<Avalonia.Media.FontFamily> Avalonia.Controls.TextBlock.FontFamilyProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.AttachedProperty<Avalonia.Media.FontStyle> Avalonia.AttachedProperty<Avalonia.Media.FontStyle> Avalonia.Controls.TextBlock.FontStyleProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.AttachedProperty<Avalonia.Media.FontWeight> Avalonia.AttachedProperty<Avalonia.Media.FontWeight> Avalonia.Controls.TextBlock.FontWeightProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.AttachedProperty<Avalonia.Media.IBrush> Avalonia.AttachedProperty<Avalonia.Media.IBrush> Avalonia.Controls.TextBlock.ForegroundProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.AttachedProperty<System.Double> Avalonia.AttachedProperty<System.Double> Avalonia.Controls.TextBlock.FontSizeProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.FontFamily Avalonia.Controls.TextBlock.GetFontFamily(Avalonia.Controls.Control)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.Double Avalonia.Controls.TextBlock.GetFontSize(Avalonia.Controls.Control)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.FontStyle Avalonia.Controls.TextBlock.GetFontStyle(Avalonia.Controls.Control)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.FontWeight Avalonia.Controls.TextBlock.GetFontWeight(Avalonia.Controls.Control)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.IBrush Avalonia.Controls.TextBlock.GetForeground(Avalonia.Controls.Control)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.TextBlock.SetFontFamily(Avalonia.Controls.Control, Avalonia.Media.FontFamily)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.TextBlock.SetFontSize(Avalonia.Controls.Control, System.Double)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.TextBlock.SetFontStyle(Avalonia.Controls.Control, Avalonia.Media.FontStyle)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.TextBlock.SetFontWeight(Avalonia.Controls.Control, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.TextBlock.SetForeground(Avalonia.Controls.Control, Avalonia.Media.IBrush)' does not exist in the implementation but it does exist in the contract.
CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.TopLevel' does not implement interface 'Avalonia.Utilities.IWeakSubscriber<Avalonia.Controls.ResourcesChangedEventArgs>' in the implementation but it does in the contract.
CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.Viewbox' does not inherit from base type 'Avalonia.Controls.Decorator' in the implementation but it does in the contract.
MembersMustExist : Member 'public Avalonia.AvaloniaProperty<Avalonia.Media.Stretch> Avalonia.AvaloniaProperty<Avalonia.Media.Stretch> Avalonia.Controls.Viewbox.StretchProperty' does not exist in the implementation but it does exist in the contract.
@ -72,4 +87,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platfor
MembersMustExist : Member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size, Avalonia.Platform.PlatformResizeReason)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.ITrayIconImpl Avalonia.Platform.IWindowingPlatform.CreateTrayIcon()' is present in the implementation but not in the contract.
Total Issues: 73
Total Issues: 88

2
src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs

@ -65,7 +65,7 @@ namespace Avalonia.Controls.ApplicationLifetimes
/// <inheritdoc/>
public Window? MainWindow { get; set; }
public IReadOnlyList<Window> Windows => _windows.ToList();
public IReadOnlyList<Window> Windows => _windows.ToArray();
private void HandleWindowClosed(Window window)
{

8
src/Avalonia.Controls/AutoCompleteBox.cs

@ -252,6 +252,10 @@ namespace Avalonia.Controls
/// drop-down that contains possible matches based on the input in the text
/// box.
/// </summary>
[TemplatePart(ElementPopup, typeof(Popup))]
[TemplatePart(ElementSelector, typeof(SelectingItemsControl))]
[TemplatePart(ElementSelectionAdapter, typeof(ISelectionAdapter))]
[TemplatePart(ElementTextBox, typeof(TextBox))]
[PseudoClasses(":dropdownopen")]
public class AutoCompleteBox : TemplatedControl
{
@ -2180,7 +2184,7 @@ namespace Avalonia.Controls
}
// Store a local cached copy of the data
_items = newValue == null ? null : new List<object>(newValue.Cast<object>().ToList());
_items = newValue == null ? null : new List<object>(newValue.Cast<object>());
// Clear and set the view on the selection adapter
ClearView();
@ -2239,7 +2243,7 @@ namespace Avalonia.Controls
ClearView();
if (Items != null)
{
_items = new List<object>(Items.Cast<object>().ToList());
_items = new List<object>(Items.Cast<object>());
}
}

119
src/Avalonia.Controls/Button.cs

@ -29,11 +29,14 @@ namespace Avalonia.Controls
}
/// <summary>
/// A button control.
/// A standard button control.
/// </summary>
[PseudoClasses(":pressed")]
[PseudoClasses(pcFlyoutOpen, pcPressed)]
public class Button : ContentControl, ICommandSource, IClickableControl
{
protected const string pcPressed = ":pressed";
protected const string pcFlyoutOpen = ":flyout-open";
/// <summary>
/// Defines the <see cref="ClickMode"/> property.
/// </summary>
@ -92,6 +95,7 @@ namespace Avalonia.Controls
private ICommand? _command;
private bool _commandCanExecute = true;
private KeyGesture? _hotkey;
private bool _isFlyoutOpen = false;
/// <summary>
/// Initializes static members of the <see cref="Button"/> class.
@ -107,7 +111,6 @@ namespace Avalonia.Controls
/// </summary>
public Button()
{
UpdatePseudoClasses(IsPressed);
}
/// <summary>
@ -328,11 +331,30 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Opens the button's flyout.
/// </summary>
protected virtual void OpenFlyout()
{
Flyout?.ShowAt(this);
}
/// <summary>
/// Invoked when the button's flyout is opened.
/// </summary>
protected virtual void OnFlyoutOpened()
{
// Available for derived types
}
/// <summary>
/// Invoked when the button's flyout is closed.
/// </summary>
protected virtual void OnFlyoutClosed()
{
// Available for derived types
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
@ -382,6 +404,14 @@ namespace Avalonia.Controls
IsPressed = false;
}
/// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
UnregisterFlyoutEvents(Flyout);
RegisterFlyoutEvents(Flyout);
UpdatePseudoClasses();
}
/// <inheritdoc/>
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
@ -442,17 +472,26 @@ namespace Avalonia.Controls
}
else if (change.Property == IsPressedProperty)
{
UpdatePseudoClasses(change.NewValue.GetValueOrDefault<bool>());
UpdatePseudoClasses();
}
else if (change.Property == FlyoutProperty)
{
var oldFlyout = change.OldValue.GetValueOrDefault() as FlyoutBase;
var newFlyout = change.NewValue.GetValueOrDefault() as FlyoutBase;
// If flyout is changed while one is already open, make sure we
// close the old one first
if (change.OldValue.GetValueOrDefault() is FlyoutBase oldFlyout &&
if (oldFlyout != null &&
oldFlyout.IsOpen)
{
oldFlyout.Hide();
}
// Must unregister events here while a reference to the old flyout still exists
UnregisterFlyoutEvents(oldFlyout);
RegisterFlyoutEvents(newFlyout);
UpdatePseudoClasses();
}
}
@ -493,6 +532,32 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Registers all flyout events.
/// </summary>
/// <param name="flyout">The flyout to connect events to.</param>
private void RegisterFlyoutEvents(FlyoutBase? flyout)
{
if (flyout != null)
{
flyout.Opened += Flyout_Opened;
flyout.Closed += Flyout_Closed;
}
}
/// <summary>
/// Explicitly unregisters all flyout events.
/// </summary>
/// <param name="flyout">The flyout to disconnect events from.</param>
private void UnregisterFlyoutEvents(FlyoutBase? flyout)
{
if (flyout != null)
{
flyout.Opened -= Flyout_Opened;
flyout.Closed -= Flyout_Closed;
}
}
/// <summary>
/// Starts listening for the Enter key when the button <see cref="IsDefault"/>.
/// </summary>
@ -560,13 +625,53 @@ namespace Avalonia.Controls
/// <summary>
/// Updates the visual state of the control by applying latest PseudoClasses.
/// </summary>
private void UpdatePseudoClasses(bool isPressed)
private void UpdatePseudoClasses()
{
PseudoClasses.Set(":pressed", isPressed);
PseudoClasses.Set(pcFlyoutOpen, _isFlyoutOpen);
PseudoClasses.Set(pcPressed, IsPressed);
}
void ICommandSource.CanExecuteChanged(object sender, EventArgs e) => this.CanExecuteChanged(sender, e);
void IClickableControl.RaiseClick() => OnClick();
/// <summary>
/// Event handler for when the button's flyout is opened.
/// </summary>
private void Flyout_Opened(object? sender, EventArgs e)
{
var flyout = sender as FlyoutBase;
// It is possible to share flyouts among multiple controls including Button.
// This can cause a problem here since all controls that share a flyout receive
// the same Opened/Closed events at the same time.
// For Button that means they all would be updating their pseudoclasses accordingly.
// In other words, all Buttons with a shared Flyout would have the backgrounds changed together.
// To fix this, only continue here if the Flyout target matches this Button instance.
if (object.ReferenceEquals(flyout?.Target, this))
{
_isFlyoutOpen = true;
UpdatePseudoClasses();
OnFlyoutOpened();
}
}
/// <summary>
/// Event handler for when the button's flyout is closed.
/// </summary>
private void Flyout_Closed(object? sender, EventArgs e)
{
var flyout = sender as FlyoutBase;
// See comments in Flyout_Opened
if (object.ReferenceEquals(flyout?.Target, this))
{
_isFlyoutOpen = false;
UpdatePseudoClasses();
OnFlyoutClosed();
}
}
}
}

2
src/Avalonia.Controls/ButtonSpinner.cs

@ -16,6 +16,8 @@ namespace Avalonia.Controls
/// <summary>
/// Represents a spinner control that includes two Buttons.
/// </summary>
[TemplatePart("PART_DecreaseButton", typeof(Button))]
[TemplatePart("PART_IncreaseButton", typeof(Button))]
[PseudoClasses(":left", ":right")]
public class ButtonSpinner : Spinner
{

21
src/Avalonia.Controls/Calendar/Calendar.cs

@ -6,6 +6,7 @@
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input;
@ -222,6 +223,8 @@ namespace Avalonia.Controls
/// element in XAML.
/// </para>
/// </remarks>
[TemplatePart(PART_ElementMonth, typeof(CalendarItem))]
[TemplatePart(PART_ElementRoot, typeof(Panel))]
public class Calendar : TemplatedControl
{
internal const int RowsPerMonth = 7;
@ -261,6 +264,7 @@ namespace Avalonia.Controls
AvaloniaProperty.Register<Calendar, DayOfWeek>(
nameof(FirstDayOfWeek),
defaultValue: DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek);
/// <summary>
/// Gets or sets the day that is considered the beginning of the week.
/// </summary>
@ -273,6 +277,7 @@ namespace Avalonia.Controls
get { return GetValue(FirstDayOfWeekProperty); }
set { SetValue(FirstDayOfWeekProperty, value); }
}
/// <summary>
/// FirstDayOfWeekProperty property changed handler.
/// </summary>
@ -289,6 +294,7 @@ namespace Avalonia.Controls
throw new ArgumentOutOfRangeException("d", "Invalid DayOfWeek");
}
}
/// <summary>
/// Inherited code: Requires comment.
/// </summary>
@ -311,6 +317,7 @@ namespace Avalonia.Controls
AvaloniaProperty.Register<Calendar, bool>(
nameof(IsTodayHighlighted),
defaultValue: true);
/// <summary>
/// Gets or sets a value indicating whether the current date is
/// highlighted.
@ -324,6 +331,7 @@ namespace Avalonia.Controls
get { return GetValue(IsTodayHighlightedProperty); }
set { SetValue(IsTodayHighlightedProperty, value); }
}
/// <summary>
/// IsTodayHighlightedProperty property changed handler.
/// </summary>
@ -343,6 +351,7 @@ namespace Avalonia.Controls
public static readonly StyledProperty<IBrush> HeaderBackgroundProperty =
AvaloniaProperty.Register<Calendar, IBrush>(nameof(HeaderBackground));
public IBrush HeaderBackground
{
get { return GetValue(HeaderBackgroundProperty); }
@ -367,6 +376,7 @@ namespace Avalonia.Controls
get { return GetValue(DisplayModeProperty); }
set { SetValue(DisplayModeProperty, value); }
}
/// <summary>
/// DisplayModeProperty property changed handler.
/// </summary>
@ -424,6 +434,7 @@ namespace Avalonia.Controls
|| mode == CalendarMode.Year
|| mode == CalendarMode.Decade;
}
private void OnDisplayModeChanged(CalendarModeChangedEventArgs args)
{
DisplayModeChanged?.Invoke(this, args);
@ -433,6 +444,7 @@ namespace Avalonia.Controls
AvaloniaProperty.Register<Calendar, CalendarSelectionMode>(
nameof(SelectionMode),
defaultValue: CalendarSelectionMode.SingleDate);
/// <summary>
/// Gets or sets a value that indicates what kind of selections are
/// allowed.
@ -457,6 +469,7 @@ namespace Avalonia.Controls
get { return GetValue(SelectionModeProperty); }
set { SetValue(SelectionModeProperty, value); }
}
private void OnSelectionModeChanged(AvaloniaPropertyChangedEventArgs e)
{
if (IsValidSelectionMode(e.NewValue!))
@ -471,6 +484,7 @@ namespace Avalonia.Controls
throw new ArgumentOutOfRangeException("d", "Invalid SelectionMode");
}
}
/// <summary>
/// Inherited code: Requires comment.
/// </summary>
@ -492,6 +506,7 @@ namespace Avalonia.Controls
o => o.SelectedDate,
(o, v) => o.SelectedDate = v,
defaultBindingMode: BindingMode.TwoWay);
/// <summary>
/// Gets or sets the currently selected date.
/// </summary>
@ -720,6 +735,7 @@ namespace Avalonia.Controls
o => o.DisplayDate,
(o, v) => o.DisplayDate = v,
defaultBindingMode: BindingMode.TwoWay);
/// <summary>
/// Gets or sets the date to display.
/// </summary>
@ -1973,6 +1989,7 @@ namespace Avalonia.Controls
}
}
}
private void Calendar_KeyUp(KeyEventArgs e)
{
if (!e.Handled && (e.Key == Key.LeftShift || e.Key == Key.RightShift))
@ -1980,6 +1997,7 @@ namespace Avalonia.Controls
ProcessShiftKeyUp();
}
}
internal void ProcessShiftKeyUp()
{
if (_isShiftPressed && (SelectionMode == CalendarSelectionMode.SingleRange || SelectionMode == CalendarSelectionMode.MultipleRange))
@ -2028,6 +2046,7 @@ namespace Avalonia.Controls
}
}
}
protected override void OnLostFocus(RoutedEventArgs e)
{
base.OnLostFocus(e);
@ -2054,6 +2073,7 @@ namespace Avalonia.Controls
}
}
}
/// <summary>
/// Called when the IsEnabled property changes.
/// </summary>
@ -2098,6 +2118,7 @@ namespace Avalonia.Controls
private const string PART_ElementRoot = "Root";
private const string PART_ElementMonth = "CalendarItem";
/// <summary>
/// Builds the visual tree for the
/// <see cref="T:System.Windows.Controls.Calendar" /> when a new

5
src/Avalonia.Controls/Calendar/CalendarDatePicker.cs

@ -7,6 +7,7 @@ using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input;
@ -116,6 +117,10 @@ namespace Avalonia.Controls
Custom = 2
}
[TemplatePart(ElementButton, typeof(Button))]
[TemplatePart(ElementCalendar, typeof(Calendar))]
[TemplatePart(ElementPopup, typeof(Popup))]
[TemplatePart(ElementTextBox, typeof(TextBox))]
public class CalendarDatePicker : TemplatedControl
{
private const string ElementTextBox = "PART_TextBox";

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

@ -19,6 +19,11 @@ namespace Avalonia.Controls.Primitives
/// Represents the currently displayed month or year on a
/// <see cref="T:Avalonia.Controls.Calendar" />.
/// </summary>
[TemplatePart(PART_ElementHeaderButton, typeof(Button))]
[TemplatePart(PART_ElementMonthView, typeof(Grid))]
[TemplatePart(PART_ElementNextButton, typeof(Button))]
[TemplatePart(PART_ElementPreviousButton, typeof(Button))]
[TemplatePart(PART_ElementYearView, typeof(Grid))]
[PseudoClasses(":calendardisabled")]
public sealed class CalendarItem : TemplatedControl
{

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

@ -8,6 +8,10 @@ namespace Avalonia.Controls.Chrome
/// <summary>
/// Draws window minimize / maximize / close buttons in a <see cref="TitleBar"/> when managed client decorations are enabled.
/// </summary>
[TemplatePart("PART_CloseButton", typeof(Panel))]
[TemplatePart("PART_RestoreButton", typeof(Panel))]
[TemplatePart("PART_MinimiseButton", typeof(Panel))]
[TemplatePart("PART_FullScreenButton", typeof(Panel))]
[PseudoClasses(":minimized", ":normal", ":maximized", ":fullscreen")]
public class CaptionButtons : TemplatedControl
{

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

@ -8,6 +8,7 @@ namespace Avalonia.Controls.Chrome
/// <summary>
/// Draws a titlebar when managed client decorations are enabled.
/// </summary>
[TemplatePart("PART_CaptionButtons", typeof(CaptionButtons))]
[PseudoClasses(":minimized", ":normal", ":maximized", ":fullscreen")]
public class TitleBar : TemplatedControl
{

2
src/Avalonia.Controls/ComboBox.cs

@ -13,12 +13,14 @@ using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.VisualTree;
using Avalonia.Controls.Metadata;
namespace Avalonia.Controls
{
/// <summary>
/// A drop-down list control.
/// </summary>
[TemplatePart("PART_Popup", typeof(Popup))]
public class ComboBox : SelectingItemsControl
{
/// <summary>

2
src/Avalonia.Controls/ContentControl.cs

@ -1,4 +1,5 @@
using Avalonia.Collections;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
@ -12,6 +13,7 @@ namespace Avalonia.Controls
/// <summary>
/// Displays <see cref="Content"/> according to a <see cref="FuncDataTemplate"/>.
/// </summary>
[TemplatePart("PART_ContentPresenter", typeof(IContentPresenter))]
public class ContentControl : TemplatedControl, IContentControl, IContentPresenterHost
{
/// <summary>

24
src/Avalonia.Controls/Control.cs

@ -1,7 +1,7 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Documents;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Input;
@ -67,7 +67,7 @@ namespace Avalonia.Controls
/// </summary>
public static readonly AttachedProperty<FlowDirection> FlowDirectionProperty =
AvaloniaProperty.RegisterAttached<Control, Control, FlowDirection>(nameof(FlowDirection), inherits: true);
private DataTemplates? _dataTemplates;
private IControl? _focusAdorner;
private AutomationPeer? _automationPeer;
@ -137,6 +137,26 @@ namespace Avalonia.Controls
public new IControl? Parent => (IControl?)base.Parent;
/// <summary>
/// Gets the value of the attached <see cref="FlowDirectionProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The flow direction.</returns>
public static FlowDirection GetFlowDirection(Control control)
{
return control.GetValue(FlowDirectionProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="FlowDirectionProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFlowDirection(Control control, FlowDirection value)
{
control.SetValue(FlowDirectionProperty, value);
}
/// <inheritdoc/>
bool IDataTemplateHost.IsDataTemplatesInitialized => _dataTemplates != null;

9
src/Avalonia.Controls/DateTimePickers/DatePicker.cs

@ -14,6 +14,15 @@ namespace Avalonia.Controls
/// <summary>
/// A control to allow the user to select a date
/// </summary>
[TemplatePart("ButtonContentGrid", typeof(Grid))]
[TemplatePart("DayText", typeof(TextBlock))]
[TemplatePart("FirstSpacer", typeof(Rectangle))]
[TemplatePart("FlyoutButton", typeof(Button))]
[TemplatePart("MonthText", typeof(TextBlock))]
[TemplatePart("PickerPresenter", typeof(DatePickerPresenter))]
[TemplatePart("Popup", typeof(Popup))]
[TemplatePart("SecondSpacer", typeof(Rectangle))]
[TemplatePart("YearText", typeof(TextBlock))]
[PseudoClasses(":hasnodate")]
public class DatePicker : TemplatedControl
{

20
src/Avalonia.Controls/DateTimePickers/DatePickerPresenter.cs

@ -1,4 +1,5 @@
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Input;
using Avalonia.Interactivity;
@ -12,6 +13,23 @@ namespace Avalonia.Controls
/// Defines the presenter used for selecting a date for a
/// <see cref="DatePicker"/>
/// </summary>
[TemplatePart("AcceptButton", typeof(Button))]
[TemplatePart("DayDownButton", typeof(RepeatButton))]
[TemplatePart("DayHost", typeof(Panel))]
[TemplatePart("DaySelector", typeof(DateTimePickerPanel))]
[TemplatePart("DayUpButton", typeof(RepeatButton))]
[TemplatePart("DismissButton", typeof(Button))]
[TemplatePart("FirstSpacer", typeof(Rectangle))]
[TemplatePart("MonthDownButton", typeof(RepeatButton))]
[TemplatePart("MonthHost", typeof(Panel))]
[TemplatePart("MonthSelector", typeof(DateTimePickerPanel))]
[TemplatePart("MonthUpButton", typeof(RepeatButton))]
[TemplatePart("PickerContainer", typeof(Grid))]
[TemplatePart("SecondSpacer", typeof(Rectangle))]
[TemplatePart("YearDownButton", typeof(RepeatButton))]
[TemplatePart("YearHost", typeof(Panel))]
[TemplatePart("YearSelector", typeof(DateTimePickerPanel))]
[TemplatePart("YearUpButton", typeof(RepeatButton))]
public class DatePickerPresenter : PickerPresenterBase
{
/// <summary>

12
src/Avalonia.Controls/DateTimePickers/TimePicker.cs

@ -12,6 +12,18 @@ namespace Avalonia.Controls
/// <summary>
/// A control to allow the user to select a time.
/// </summary>
[TemplatePart("FirstColumnDivider", typeof(Rectangle))]
[TemplatePart("FirstPickerHost", typeof(Border))]
[TemplatePart("FlyoutButton", typeof(Button))]
[TemplatePart("FlyoutButtonContentGrid", typeof(Grid))]
[TemplatePart("HourTextBlock", typeof(TextBlock))]
[TemplatePart("MinuteTextBlock", typeof(TextBlock))]
[TemplatePart("PeriodTextBlock", typeof(TextBlock))]
[TemplatePart("PickerPresenter", typeof(TimePickerPresenter))]
[TemplatePart("Popup", typeof(Popup))]
[TemplatePart("SecondColumnDivider", typeof(Rectangle))]
[TemplatePart("SecondPickerHost", typeof(Border))]
[TemplatePart("ThirdPickerHost", typeof(Border))]
[PseudoClasses(":hasnotime")]
public class TimePicker : TemplatedControl
{

17
src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs

@ -1,4 +1,5 @@
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Input;
using Avalonia.Interactivity;
@ -10,6 +11,20 @@ namespace Avalonia.Controls
/// Defines the presenter used for selecting a time. Intended for use with
/// <see cref="TimePicker"/> but can be used independently
/// </summary>
[TemplatePart("AcceptButton", typeof(Button))]
[TemplatePart("DismissButton", typeof(Button))]
[TemplatePart("HourDownButton", typeof(RepeatButton))]
[TemplatePart("HourSelector", typeof(DateTimePickerPanel))]
[TemplatePart("HourUpButton", typeof(RepeatButton))]
[TemplatePart("MinuteDownButton", typeof(RepeatButton))]
[TemplatePart("MinuteSelector", typeof(DateTimePickerPanel))]
[TemplatePart("MinuteUpButton", typeof(RepeatButton))]
[TemplatePart("PeriodDownButton", typeof(RepeatButton))]
[TemplatePart("PeriodHost", typeof(Panel))]
[TemplatePart("PeriodSelector", typeof(DateTimePickerPanel))]
[TemplatePart("PeriodUpButton", typeof(RepeatButton))]
[TemplatePart("PickerContainer", typeof(Grid))]
[TemplatePart("SecondSpacer", typeof(Rectangle))]
public class TimePickerPresenter : PickerPresenterBase
{
/// <summary>

167
src/Avalonia.Controls/Documents/TextElement.cs

@ -13,37 +13,60 @@ namespace Avalonia.Controls.Documents
/// Defines the <see cref="Background"/> property.
/// </summary>
public static readonly StyledProperty<IBrush?> BackgroundProperty =
AvaloniaProperty.Register<TextElement, IBrush?>(nameof(Background), inherits: true);
Border.BackgroundProperty.AddOwner<TextElement>();
/// <summary>
/// Defines the <see cref="FontFamily"/> property.
/// </summary>
public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
TextBlock.FontFamilyProperty.AddOwner<TextElement>();
AvaloniaProperty.RegisterAttached<TextElement, Control, FontFamily>(
nameof(FontFamily),
defaultValue: FontFamily.Default,
inherits: true);
/// <summary>
/// Defines the <see cref="FontSize"/> property.
/// </summary>
public static readonly AttachedProperty<double> FontSizeProperty =
TextBlock.FontSizeProperty.AddOwner<TextElement>();
AvaloniaProperty.RegisterAttached<TextElement, Control, double>(
nameof(FontSize),
defaultValue: 12,
inherits: true);
/// <summary>
/// Defines the <see cref="FontStyle"/> property.
/// </summary>
public static readonly AttachedProperty<FontStyle> FontStyleProperty =
TextBlock.FontStyleProperty.AddOwner<TextElement>();
AvaloniaProperty.RegisterAttached<TextElement, Control, FontStyle>(
nameof(FontStyle),
inherits: true);
/// <summary>
/// Defines the <see cref="FontWeight"/> property.
/// </summary>
public static readonly AttachedProperty<FontWeight> FontWeightProperty =
TextBlock.FontWeightProperty.AddOwner<TextElement>();
AvaloniaProperty.RegisterAttached<TextElement, Control, FontWeight>(
nameof(FontWeight),
inherits: true,
defaultValue: FontWeight.Normal);
/// <summary>
/// Defines the <see cref="FontStretch"/> property.
/// </summary>
public static readonly AttachedProperty<FontStretch> FontStretchProperty =
AvaloniaProperty.RegisterAttached<TextElement, Control, FontStretch>(
nameof(FontStretch),
inherits: true,
defaultValue: FontStretch.Normal);
/// <summary>
/// Defines the <see cref="Foreground"/> property.
/// </summary>
public static readonly AttachedProperty<IBrush?> ForegroundProperty =
TextBlock.ForegroundProperty.AddOwner<TextElement>();
AvaloniaProperty.RegisterAttached<TextElement, Control, IBrush?>(
nameof(Foreground),
Brushes.Black,
inherits: true);
/// <summary>
/// Gets or sets a brush used to paint the control's background.
@ -90,6 +113,15 @@ namespace Avalonia.Controls.Documents
set { SetValue(FontWeightProperty, value); }
}
/// <summary>
/// Gets or sets the font stretch.
/// </summary>
public FontStretch FontStretch
{
get { return GetValue(FontStretchProperty); }
set { SetValue(FontStretchProperty, value); }
}
/// <summary>
/// Gets or sets a brush used to paint the text.
/// </summary>
@ -98,7 +130,127 @@ namespace Avalonia.Controls.Documents
get { return GetValue(ForegroundProperty); }
set { SetValue(ForegroundProperty, value); }
}
/// <summary>
/// Gets the value of the attached <see cref="FontFamilyProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font family.</returns>
public static FontFamily GetFontFamily(Control control)
{
return control.GetValue(FontFamilyProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="FontFamilyProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFontFamily(Control control, FontFamily value)
{
control.SetValue(FontFamilyProperty, value);
}
/// <summary>
/// Gets the value of the attached <see cref="FontSizeProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font size.</returns>
public static double GetFontSize(Control control)
{
return control.GetValue(FontSizeProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="FontSizeProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFontSize(Control control, double value)
{
control.SetValue(FontSizeProperty, value);
}
/// <summary>
/// Gets the value of the attached <see cref="FontStyleProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font style.</returns>
public static FontStyle GetFontStyle(Control control)
{
return control.GetValue(FontStyleProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="FontStyleProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFontStyle(Control control, FontStyle value)
{
control.SetValue(FontStyleProperty, value);
}
/// <summary>
/// Gets the value of the attached <see cref="FontWeightProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font weight.</returns>
public static FontWeight GetFontWeight(Control control)
{
return control.GetValue(FontWeightProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="FontWeightProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFontWeight(Control control, FontWeight value)
{
control.SetValue(FontWeightProperty, value);
}
/// <summary>
/// Gets the value of the attached <see cref="FontStretchProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font stretch.</returns>
public static FontStretch GetFontStretch(Control control)
{
return control.GetValue(FontStretchProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="FontStretchProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFontStretch(Control control, FontStretch value)
{
control.SetValue(FontStretchProperty, value);
}
/// <summary>
/// Gets the value of the attached <see cref="ForegroundProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The foreground.</returns>
public static IBrush? GetForeground(Control control)
{
return control.GetValue(ForegroundProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="ForegroundProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetForeground(Control control, IBrush? value)
{
control.SetValue(ForegroundProperty, value);
}
/// <summary>
/// Raised when the visual representation of the text element changes.
/// </summary>
@ -115,6 +267,7 @@ namespace Avalonia.Controls.Documents
case nameof(FontSize):
case nameof(FontStyle):
case nameof(FontWeight):
case nameof(FontStretch):
case nameof(Foreground):
Invalidate();
break;

15
src/Avalonia.Controls/DropDownButton.cs

@ -0,0 +1,15 @@
namespace Avalonia.Controls
{
/// <summary>
/// A button with an added drop-down chevron to visually indicate it has a flyout with additional actions.
/// </summary>
public class DropDownButton : Button
{
/// <summary>
/// Initializes a new instance of the <see cref="DropDownButton"/> class.
/// </summary>
public DropDownButton()
{
}
}
}

9
src/Avalonia.Controls/Flyouts/MenuFlyoutPresenter.cs

@ -8,15 +8,6 @@ namespace Avalonia.Controls
{
public class MenuFlyoutPresenter : MenuBase
{
public static readonly StyledProperty<CornerRadius> CornerRadiusProperty =
Border.CornerRadiusProperty.AddOwner<FlyoutPresenter>();
public CornerRadius CornerRadius
{
get => GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
public MenuFlyoutPresenter()
:base(new DefaultMenuInteractionHandler(true))
{

12
src/Avalonia.Controls/Generators/ItemContainerGenerator.cs

@ -82,7 +82,7 @@ namespace Avalonia.Controls.Generators
{
var toMove = _containers.Where(x => x.Key >= index)
.OrderByDescending(x => x.Key)
.ToList();
.ToArray();
foreach (var i in toMove)
{
@ -111,7 +111,7 @@ namespace Avalonia.Controls.Generators
}
var toMove = _containers.Where(x => x.Key >= startingIndex)
.OrderBy(x => x.Key).ToList();
.OrderBy(x => x.Key).ToArray();
foreach (var i in toMove)
{
@ -122,9 +122,9 @@ namespace Avalonia.Controls.Generators
Dematerialized?.Invoke(this, new ItemContainerEventArgs(startingIndex, result));
if (toMove.Count > 0)
if (toMove.Length > 0)
{
var containers = toMove.Select(x => x.Value).ToList();
var containers = toMove.Select(x => x.Value).ToArray();
Recycled?.Invoke(this, new ItemContainerEventArgs(containers[0].Index, containers));
}
}
@ -138,10 +138,10 @@ namespace Avalonia.Controls.Generators
/// <inheritdoc/>
public virtual IEnumerable<ItemContainerInfo> Clear()
{
var result = Containers.ToList();
var result = Containers.ToArray();
_containers.Clear();
if (result.Count > 0)
if (result.Length > 0)
{
Dematerialized?.Invoke(this, new ItemContainerEventArgs(0, result));
}

2
src/Avalonia.Controls/ListBox.cs

@ -1,5 +1,6 @@
using System.Collections;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Selection;
@ -12,6 +13,7 @@ namespace Avalonia.Controls
/// <summary>
/// An <see cref="ItemsControl"/> in which individual items can be selected.
/// </summary>
[TemplatePart("PART_ScrollViewer", typeof(IScrollable))]
public class ListBox : SelectingItemsControl
{
/// <summary>

1
src/Avalonia.Controls/MenuItem.cs

@ -20,6 +20,7 @@ namespace Avalonia.Controls
/// <summary>
/// A menu item control.
/// </summary>
[TemplatePart("PART_Popup", typeof(Popup))]
[PseudoClasses(":separator", ":icon", ":open", ":pressed", ":selected")]
public class MenuItem : HeaderedSelectingItemsControl, IMenuItem, ISelectable, ICommandSource, IClickableControl
{

1
src/Avalonia.Controls/Notifications/WindowNotificationManager.cs

@ -14,6 +14,7 @@ namespace Avalonia.Controls.Notifications
/// <summary>
/// An <see cref="INotificationManager"/> that displays notifications in a <see cref="Window"/>.
/// </summary>
[TemplatePart("PART_Items", typeof(Panel))]
[PseudoClasses(":topleft", ":topright", ":bottomleft", ":bottomright")]
public class WindowNotificationManager : TemplatedControl, IManagedNotificationManager, ICustomSimpleHitTest
{

5
src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs

@ -2,6 +2,7 @@
using System.Globalization;
using System.IO;
using System.Linq;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input;
@ -15,6 +16,8 @@ namespace Avalonia.Controls
/// <summary>
/// Control that represents a TextBox with button spinners that allow incrementing and decrementing numeric values.
/// </summary>
[TemplatePart("PART_Spinner", typeof(Spinner))]
[TemplatePart("PART_TextBox", typeof(TextBox))]
public class NumericUpDown : TemplatedControl
{
/// <summary>
@ -1051,7 +1054,7 @@ namespace Avalonia.Controls
var currentValueTextSpecialCharacters = currentValueText.Where(c => !char.IsDigit(c));
var textSpecialCharacters = text.Where(c => !char.IsDigit(c));
// same non-digit characters on currentValueText and new text => remove them on new Text to parse it again.
if (currentValueTextSpecialCharacters.Except(textSpecialCharacters).ToList().Count == 0)
if (!currentValueTextSpecialCharacters.Except(textSpecialCharacters).Any())
{
foreach (var character in textSpecialCharacters)
{

10
src/Avalonia.Controls/Platform/IPlatformNativeSurfaceHandle.cs

@ -0,0 +1,10 @@
using System;
namespace Avalonia.Platform
{
public interface IPlatformNativeSurfaceHandle : IPlatformHandle
{
PixelSize Size { get; }
double Scaling { get; }
}
}

69
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -8,6 +8,7 @@ using Avalonia.Utilities;
using Avalonia.VisualTree;
using Avalonia.Layout;
using Avalonia.Media.Immutable;
using Avalonia.Controls.Documents;
namespace Avalonia.Controls.Presenters
{
@ -121,8 +122,8 @@ namespace Avalonia.Controls.Presenters
/// </summary>
public FontFamily FontFamily
{
get => TextBlock.GetFontFamily(this);
set => TextBlock.SetFontFamily(this, value);
get => TextElement.GetFontFamily(this);
set => TextElement.SetFontFamily(this, value);
}
/// <summary>
@ -130,8 +131,8 @@ namespace Avalonia.Controls.Presenters
/// </summary>
public double FontSize
{
get => TextBlock.GetFontSize(this);
set => TextBlock.SetFontSize(this, value);
get => TextElement.GetFontSize(this);
set => TextElement.SetFontSize(this, value);
}
/// <summary>
@ -139,8 +140,8 @@ namespace Avalonia.Controls.Presenters
/// </summary>
public FontStyle FontStyle
{
get => TextBlock.GetFontStyle(this);
set => TextBlock.SetFontStyle(this, value);
get => TextElement.GetFontStyle(this);
set => TextElement.SetFontStyle(this, value);
}
/// <summary>
@ -148,8 +149,8 @@ namespace Avalonia.Controls.Presenters
/// </summary>
public FontWeight FontWeight
{
get => TextBlock.GetFontWeight(this);
set => TextBlock.SetFontWeight(this, value);
get => TextElement.GetFontWeight(this);
set => TextElement.SetFontWeight(this, value);
}
/// <summary>
@ -157,8 +158,8 @@ namespace Avalonia.Controls.Presenters
/// </summary>
public FontStretch FontStretch
{
get => TextBlock.GetFontStretch(this);
set => TextBlock.SetFontStretch(this, value);
get => TextElement.GetFontStretch(this);
set => TextElement.SetFontStretch(this, value);
}
/// <summary>
@ -166,8 +167,8 @@ namespace Avalonia.Controls.Presenters
/// </summary>
public IBrush? Foreground
{
get => TextBlock.GetForeground(this);
set => TextBlock.SetForeground(this, value);
get => TextElement.GetForeground(this);
set => TextElement.SetForeground(this, value);
}
/// <summary>
@ -353,7 +354,7 @@ namespace Avalonia.Controls.Presenters
foreach (var rect in rects)
{
context.FillRectangle(selectionBrush, rect);
context.FillRectangle(selectionBrush, PixelRect.FromRect(rect, 1).ToRect(1));
}
}
@ -528,9 +529,9 @@ namespace Avalonia.Controls.Presenters
{
return finalSize;
}
_constraint = finalSize;
_constraint = new Size(finalSize.Width, Math.Ceiling(finalSize.Height));
_textLayout = null;
return finalSize;
@ -637,14 +638,7 @@ namespace Avalonia.Controls.Presenters
if (Text is null)
{
return default;
}
if (FlowDirection == FlowDirection.RightToLeft)
{
direction = direction == LogicalDirection.Forward ?
LogicalDirection.Backward :
LogicalDirection.Forward;
}
}
var characterHit = _lastCharacterHit;
var caretIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
@ -666,7 +660,7 @@ namespace Avalonia.Controls.Presenters
caretIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
if (textLine.NewLineLength > 0 && caretIndex == textLine.TextRange.Start + textLine.TextRange.Length)
if (textLine.NewLineLength > 0 && caretIndex == textLine.FirstTextSourceIndex + textLine.Length)
{
characterHit = new CharacterHit(caretIndex);
}
@ -678,7 +672,7 @@ namespace Avalonia.Controls.Presenters
break;
}
if (caretIndex - textLine.NewLineLength == textLine.TextRange.Start + textLine.TextRange.Length)
if (caretIndex - textLine.NewLineLength == textLine.FirstTextSourceIndex + textLine.Length)
{
break;
}
@ -719,6 +713,13 @@ namespace Avalonia.Controls.Presenters
public void MoveCaretHorizontal(LogicalDirection direction = LogicalDirection.Forward)
{
if (FlowDirection == FlowDirection.RightToLeft)
{
direction = direction == LogicalDirection.Forward ?
LogicalDirection.Backward :
LogicalDirection.Forward;
}
var characterHit = GetNextCharacterHit(direction);
UpdateCaret(characterHit);
@ -779,19 +780,25 @@ namespace Avalonia.Controls.Presenters
switch (change.Property.Name)
{
case nameof (TextBlock.Foreground):
case nameof (TextBlock.FontSize):
case nameof (TextBlock.FontStyle):
case nameof (TextBlock.FontWeight):
case nameof (TextBlock.FontFamily):
case nameof (Foreground):
case nameof (FontSize):
case nameof (FontStyle):
case nameof (FontWeight):
case nameof (FontFamily):
case nameof (FontStretch):
case nameof (Text):
case nameof (TextAlignment):
case nameof (TextWrapping):
case nameof (SelectionStart):
case nameof (SelectionEnd):
case nameof (SelectionForegroundBrush):
case nameof (PasswordChar):
case nameof (RevealPassword):
case nameof(FlowDirection):
{
InvalidateTextLayout();
break;

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

@ -23,8 +23,9 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
public IReadOnlyList<ManagedPopupPositionerScreenInfo> Screens =>
_parent.Screen.AllScreens.Select(s => new ManagedPopupPositionerScreenInfo(
s.Bounds.ToRect(1), s.WorkingArea.ToRect(1))).ToList();
_parent.Screen.AllScreens
.Select(s => new ManagedPopupPositionerScreenInfo(s.Bounds.ToRect(1), s.WorkingArea.ToRect(1)))
.ToArray();
public Rect ParentClientAreaScreenGeometry
{

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

@ -17,7 +17,6 @@ namespace Avalonia.Controls.Primitives
/// </summary>
public sealed class PopupRoot : WindowBase, IInteractive, IHostedVisualTreeRoot, IDisposable, IStyleHost, IPopupHost
{
private readonly TopLevel _parent;
private PopupPositionerParameters _positionerParameters;
/// <summary>
@ -47,7 +46,7 @@ namespace Avalonia.Controls.Primitives
public PopupRoot(TopLevel parent, IPopupImpl impl, IAvaloniaDependencyResolver? dependencyResolver)
: base(impl, dependencyResolver)
{
_parent = parent;
ParentTopLevel = parent;
}
/// <summary>
@ -73,6 +72,8 @@ namespace Avalonia.Controls.Primitives
/// </summary>
IStyleHost? IStyleHost.StylingParent => Parent;
public TopLevel ParentTopLevel { get; }
/// <inheritdoc/>
public void Dispose()
{
@ -91,7 +92,7 @@ namespace Avalonia.Controls.Primitives
PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
Rect? rect = null)
{
_positionerParameters.ConfigurePosition(_parent, target,
_positionerParameters.ConfigurePosition(ParentTopLevel, target,
placement, offset, anchor, gravity, constraintAdjustment, rect);
if (_positionerParameters.Size != default)

4
src/Avalonia.Controls/Primitives/ScrollBar.cs

@ -22,6 +22,10 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// A scrollbar control.
/// </summary>
[TemplatePart("PART_LineDownButton", typeof(Button))]
[TemplatePart("PART_LineUpButton", typeof(Button))]
[TemplatePart("PART_PageDownButton", typeof(Button))]
[TemplatePart("PART_PageUpButton", typeof(Button))]
[PseudoClasses(":vertical", ":horizontal")]
public class ScrollBar : RangeBase
{

10
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -292,11 +292,11 @@ namespace Avalonia.Controls.Primitives
"collection is different to the Items on the control.");
}
var oldSelection = _selection?.SelectedItems.ToList();
var oldSelection = _selection?.SelectedItems.ToArray();
DeinitializeSelectionModel(_selection);
_selection = value;
if (oldSelection?.Count > 0)
if (oldSelection?.Length > 0)
{
RaiseEvent(new SelectionChangedEventArgs(
SelectionChangedEvent,
@ -845,8 +845,8 @@ namespace Avalonia.Controls.Primitives
{
var ev = new SelectionChangedEventArgs(
SelectionChangedEvent,
e.DeselectedItems.ToList(),
e.SelectedItems.ToList());
e.DeselectedItems.ToArray(),
e.SelectedItems.ToArray());
RaiseEvent(ev);
}
}
@ -988,7 +988,7 @@ namespace Avalonia.Controls.Primitives
RaiseEvent(new SelectionChangedEventArgs(
SelectionChangedEvent,
Array.Empty<object>(),
Selection.SelectedItems.ToList()));
Selection.SelectedItems.ToArray()));
}
}

31
src/Avalonia.Controls/Primitives/TemplatedControl.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Controls.Documents;
using Avalonia.Controls.Templates;
using Avalonia.Interactivity;
using Avalonia.Logging;
@ -41,31 +42,37 @@ namespace Avalonia.Controls.Primitives
/// Defines the <see cref="FontFamily"/> property.
/// </summary>
public static readonly StyledProperty<FontFamily> FontFamilyProperty =
TextBlock.FontFamilyProperty.AddOwner<TemplatedControl>();
TextElement.FontFamilyProperty.AddOwner<TemplatedControl>();
/// <summary>
/// Defines the <see cref="FontSize"/> property.
/// </summary>
public static readonly StyledProperty<double> FontSizeProperty =
TextBlock.FontSizeProperty.AddOwner<TemplatedControl>();
TextElement.FontSizeProperty.AddOwner<TemplatedControl>();
/// <summary>
/// Defines the <see cref="FontStyle"/> property.
/// </summary>
public static readonly StyledProperty<FontStyle> FontStyleProperty =
TextBlock.FontStyleProperty.AddOwner<TemplatedControl>();
TextElement.FontStyleProperty.AddOwner<TemplatedControl>();
/// <summary>
/// Defines the <see cref="FontWeight"/> property.
/// </summary>
public static readonly StyledProperty<FontWeight> FontWeightProperty =
TextBlock.FontWeightProperty.AddOwner<TemplatedControl>();
TextElement.FontWeightProperty.AddOwner<TemplatedControl>();
/// <summary>
/// Defines the <see cref="FontWeight"/> property.
/// </summary>
public static readonly StyledProperty<FontStretch> FontStretchProperty =
TextElement.FontStretchProperty.AddOwner<TemplatedControl>();
/// <summary>
/// Defines the <see cref="Foreground"/> property.
/// </summary>
public static readonly StyledProperty<IBrush?> ForegroundProperty =
TextBlock.ForegroundProperty.AddOwner<TemplatedControl>();
TextElement.ForegroundProperty.AddOwner<TemplatedControl>();
/// <summary>
/// Defines the <see cref="Padding"/> property.
@ -185,6 +192,15 @@ namespace Avalonia.Controls.Primitives
set { SetValue(FontWeightProperty, value); }
}
/// <summary>
/// Gets or sets the font stretch used to draw the control's text.
/// </summary>
public FontStretch FontStretch
{
get { return GetValue(FontStretchProperty); }
set { SetValue(FontStretchProperty, value); }
}
/// <summary>
/// Gets or sets the brush used to draw the control's text and other foreground elements.
/// </summary>
@ -340,6 +356,11 @@ namespace Avalonia.Controls.Primitives
base.OnDetachedFromLogicalTree(e);
}
/// <summary>
/// Called when the control's template is applied.
/// In simple terms, this means the method is called just before the control is displayed.
/// </summary>
/// <param name="e">The event args.</param>
protected virtual void OnApplyTemplate(TemplateAppliedEventArgs e)
{
}

1
src/Avalonia.Controls/ProgressBar.cs

@ -10,6 +10,7 @@ namespace Avalonia.Controls
/// <summary>
/// A control used to indicate the progress of an operation.
/// </summary>
[TemplatePart("PART_Indicator", typeof(Border))]
[PseudoClasses(":vertical", ":horizontal", ":indeterminate")]
public class ProgressBar : RangeBase
{

3
src/Avalonia.Controls/ScrollViewer.cs

@ -1,6 +1,7 @@
using System;
using System.Reactive.Linq;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
@ -11,6 +12,8 @@ namespace Avalonia.Controls
/// <summary>
/// A control which scrolls its content if the content is bigger than the space available.
/// </summary>
[TemplatePart("PART_HorizontalScrollBar", typeof(ScrollBar))]
[TemplatePart("PART_VerticalScrollBar", typeof(ScrollBar))]
public class ScrollViewer : ContentControl, IScrollable, IScrollAnchorProvider
{
/// <summary>

4
src/Avalonia.Controls/Selection/InternalSelectionModel.cs

@ -182,8 +182,8 @@ namespace Avalonia.Controls.Selection
try
{
var items = WritableSelectedItems;
var deselected = e.DeselectedItems.ToList();
var selected = e.SelectedItems.ToList();
var deselected = e.DeselectedItems.ToArray();
var selected = e.SelectedItems.ToArray();
_ignoreSelectedItemsChanges = true;

126
src/Avalonia.Controls/Shapes/Rectangle.cs

@ -2,19 +2,139 @@ using Avalonia.Media;
namespace Avalonia.Controls.Shapes
{
/// <summary>
/// Represents a rectangle with optional rounded corners.
/// </summary>
public class Rectangle : Shape
{
private const double PiOver2 = 1.57079633; // 90 deg to rad
/// <summary>
/// Defines the <see cref="RadiusX"/> property.
/// </summary>
public static readonly StyledProperty<double> RadiusXProperty =
AvaloniaProperty.Register<Rectangle, double>(nameof(RadiusX));
/// <summary>
/// Defines the <see cref="RadiusY"/> property.
/// </summary>
public static readonly StyledProperty<double> RadiusYProperty =
AvaloniaProperty.Register<Rectangle, double>(nameof(RadiusY));
static Rectangle()
{
AffectsGeometry<Rectangle>(BoundsProperty, StrokeThicknessProperty);
AffectsGeometry<Rectangle>(
BoundsProperty,
RadiusXProperty,
RadiusYProperty,
StrokeThicknessProperty);
}
/// <summary>
/// Gets or sets the radius on the X-axis used to round the corners of the rectangle.
/// Corner radii are represented by an ellipse so this is the X-axis width of the ellipse.
/// </summary>
public double RadiusX
{
get => GetValue(RadiusXProperty);
set => SetValue(RadiusXProperty, value);
}
/// <summary>
/// Gets or sets the radius on the Y-axis used to round the corners of the rectangle.
/// Corner radii are represented by an ellipse so this is the Y-axis height of the ellipse.
/// </summary>
public double RadiusY
{
get => GetValue(RadiusYProperty);
set => SetValue(RadiusYProperty, value);
}
/// <inheritdoc/>
protected override Geometry CreateDefiningGeometry()
{
var rect = new Rect(Bounds.Size).Deflate(StrokeThickness / 2);
return new RectangleGeometry(rect);
// TODO: If RectangleGeometry ever supports RadiusX/Y like in WPF,
// this code can be removed/combined with that implementation
double x = RadiusX;
double y = RadiusY;
if (x == 0 && y == 0)
{
// Optimization when there are no corner radii
var rect = new Rect(Bounds.Size).Deflate(StrokeThickness / 2);
return new RectangleGeometry(rect);
}
else
{
var rect = new Rect(Bounds.Size).Deflate(StrokeThickness / 2);
var geometry = new StreamGeometry();
var arcSize = new Size(x, y);
using (StreamGeometryContext context = geometry.Open())
{
// The rectangle is constructed as follows:
//
// (origin)
// Corner 4 Corner 1
// Top/Left Line 1 Top/Right
// \_ __________ _/
// | |
// Line 4 | | Line 2
// _ |__________| _
// / Line 3 \
// Corner 3 Corner 2
// Bottom/Left Bottom/Right
//
// - Lines 1,3 follow the deflated rectangle bounds minus RadiusX
// - Lines 2,4 follow the deflated rectangle bounds minus RadiusY
// - All corners are constructed using elliptical arcs
// Line 1 + Corner 1
context.BeginFigure(new Point(rect.Left + x, rect.Top), true);
context.LineTo(new Point(rect.Right - x, rect.Top));
context.ArcTo(
new Point(rect.Right, rect.Top + y),
arcSize,
rotationAngle: PiOver2,
isLargeArc: false,
SweepDirection.Clockwise);
// Line 2 + Corner 2
context.LineTo(new Point(rect.Right, rect.Bottom - y));
context.ArcTo(
new Point(rect.Right - x, rect.Bottom),
arcSize,
rotationAngle: PiOver2,
isLargeArc: false,
SweepDirection.Clockwise);
// Line 3 + Corner 3
context.LineTo(new Point(rect.Left + x, rect.Bottom));
context.ArcTo(
new Point(rect.Left, rect.Bottom - y),
arcSize,
rotationAngle: PiOver2,
isLargeArc: false,
SweepDirection.Clockwise);
// Line 4 + Corner 4
context.LineTo(new Point(rect.Left, rect.Top + y));
context.ArcTo(
new Point(rect.Left + x, rect.Top),
arcSize,
rotationAngle: PiOver2,
isLargeArc: false,
SweepDirection.Clockwise);
context.EndFigure(true);
}
return geometry;
}
}
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
return new Size(StrokeThickness, StrokeThickness);

3
src/Avalonia.Controls/Slider.cs

@ -42,6 +42,9 @@ namespace Avalonia.Controls
/// <summary>
/// A control that lets the user select from a range of values by moving a Thumb control along a Track.
/// </summary>
[TemplatePart("PART_DecreaseButton", typeof(Button))]
[TemplatePart("PART_IncreaseButton", typeof(Button))]
[TemplatePart("PART_Track", typeof(Track))]
[PseudoClasses(":vertical", ":horizontal", ":pressed")]
public class Slider : RangeBase
{

34
src/Avalonia.Controls/SplitButton/SplitButton.cs

@ -1,7 +1,6 @@
using System;
using System.Windows.Input;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
@ -13,6 +12,8 @@ namespace Avalonia.Controls
/// A button with primary and secondary parts that can each be pressed separately.
/// The primary part behaves like a <see cref="Button"/> and the secondary part opens a flyout.
/// </summary>
[TemplatePart("PART_PrimaryButton", typeof(Button))]
[TemplatePart("PART_SecondaryButton", typeof(Button))]
[PseudoClasses(pcFlyoutOpen, pcPressed)]
public class SplitButton : ContentControl, ICommandSource
{
@ -314,16 +315,9 @@ namespace Avalonia.Controls
}
// Must unregister events here while a reference to the old flyout still exists
if (oldFlyout != null)
{
UnregisterFlyoutEvents(oldFlyout);
}
if (newFlyout != null)
{
RegisterFlyoutEvents(newFlyout);
}
UnregisterFlyoutEvents(oldFlyout);
RegisterFlyoutEvents(newFlyout);
UpdatePseudoClasses();
}
@ -415,6 +409,22 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Invoked when the split button's flyout is opened.
/// </summary>
protected virtual void OnFlyoutOpened()
{
// Available for derived types
}
/// <summary>
/// Invoked when the split button's flyout is closed.
/// </summary>
protected virtual void OnFlyoutClosed()
{
// Available for derived types
}
////////////////////////////////////////////////////////////////////////
// Event Handling
////////////////////////////////////////////////////////////////////////
@ -464,6 +474,8 @@ namespace Avalonia.Controls
{
_isFlyoutOpen = true;
UpdatePseudoClasses();
OnFlyoutOpened();
}
}
@ -479,6 +491,8 @@ namespace Avalonia.Controls
{
_isFlyoutOpen = false;
UpdatePseudoClasses();
OnFlyoutClosed();
}
}
}

1
src/Avalonia.Controls/SplitView.cs

@ -77,6 +77,7 @@ namespace Avalonia.Controls
/// <summary>
/// A control with two views: A collapsible pane and an area for content
/// </summary>
[TemplatePart("PART_PaneRoot", typeof(Panel))]
[PseudoClasses(":open", ":closed")]
[PseudoClasses(":compactoverlay", ":compactinline", ":overlay", ":inline")]
[PseudoClasses(":left", ":right")]

2
src/Avalonia.Controls/TabControl.cs

@ -11,12 +11,14 @@ using Avalonia.Layout;
using Avalonia.LogicalTree;
using Avalonia.VisualTree;
using Avalonia.Automation;
using Avalonia.Controls.Metadata;
namespace Avalonia.Controls
{
/// <summary>
/// A tab control that displays a tab strip along with the content of the selected tab.
/// </summary>
[TemplatePart("PART_ItemsPresenter", typeof(ItemsPresenter))]
public class TabControl : SelectingItemsControl, IContentPresenterHost
{
/// <summary>

201
src/Avalonia.Controls/TextBlock.cs

@ -28,61 +28,50 @@ namespace Avalonia.Controls
public static readonly StyledProperty<Thickness> PaddingProperty =
Decorator.PaddingProperty.AddOwner<TextBlock>();
// TODO: Define these attached properties elsewhere (e.g. on a Text class) and AddOwner
// them into TextBlock.
/// <summary>
/// Defines the <see cref="FontFamily"/> property.
/// </summary>
public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, FontFamily>(
nameof(FontFamily),
defaultValue: FontFamily.Default,
inherits: true);
public static readonly StyledProperty<FontFamily> FontFamilyProperty =
TextElement.FontFamilyProperty.AddOwner<TextBlock>();
/// <summary>
/// Defines the <see cref="FontSize"/> property.
/// </summary>
public static readonly AttachedProperty<double> FontSizeProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, double>(
nameof(FontSize),
defaultValue: 12,
inherits: true);
public static readonly StyledProperty<double> FontSizeProperty =
TextElement.FontSizeProperty.AddOwner<TextBlock>();
/// <summary>
/// Defines the <see cref="FontStyle"/> property.
/// </summary>
public static readonly AttachedProperty<FontStyle> FontStyleProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, FontStyle>(
nameof(FontStyle),
inherits: true);
public static readonly StyledProperty<FontStyle> FontStyleProperty =
TextElement.FontStyleProperty.AddOwner<TextBlock>();
/// <summary>
/// Defines the <see cref="FontWeight"/> property.
/// </summary>
public static readonly AttachedProperty<FontWeight> FontWeightProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, FontWeight>(
nameof(FontWeight),
inherits: true,
defaultValue: FontWeight.Normal);
public static readonly StyledProperty<FontWeight> FontWeightProperty =
TextElement.FontWeightProperty.AddOwner<TextBlock>();
/// <summary>
/// Defines the <see cref="FontStretch"/> property.
/// Defines the <see cref="FontWeight"/> property.
/// </summary>
public static readonly AttachedProperty<FontStretch> FontStretchProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, FontStretch>(
nameof(FontStretch),
inherits: true,
defaultValue: FontStretch.Normal);
public static readonly StyledProperty<FontStretch> FontStretchProperty =
TextElement.FontStretchProperty.AddOwner<TextBlock>();
/// <summary>
/// Defines the <see cref="Foreground"/> property.
/// </summary>
public static readonly AttachedProperty<IBrush?> ForegroundProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, IBrush?>(
nameof(Foreground),
Brushes.Black,
inherits: true);
public static readonly StyledProperty<IBrush?> ForegroundProperty =
TextElement.ForegroundProperty.AddOwner<TextBlock>();
/// <summary>
/// DependencyProperty for <see cref="BaselineOffset" /> property.
/// </summary>
public static readonly AttachedProperty<double> BaselineOffsetProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, double>(
nameof(BaselineOffset),
0,
true);
/// <summary>
/// Defines the <see cref="LineHeight"/> property.
@ -222,7 +211,7 @@ namespace Avalonia.Controls
public InlineCollection Inlines { get; }
/// <summary>
/// Gets or sets the font family.
/// Gets or sets the font family used to draw the control's text.
/// </summary>
public FontFamily FontFamily
{
@ -231,7 +220,7 @@ namespace Avalonia.Controls
}
/// <summary>
/// Gets or sets the font size.
/// Gets or sets the size of the control's text in points.
/// </summary>
public double FontSize
{
@ -240,7 +229,7 @@ namespace Avalonia.Controls
}
/// <summary>
/// Gets or sets the font style.
/// Gets or sets the font style used to draw the control's text.
/// </summary>
public FontStyle FontStyle
{
@ -249,16 +238,16 @@ namespace Avalonia.Controls
}
/// <summary>
/// Gets or sets the font weight.
/// Gets or sets the font weight used to draw the control's text.
/// </summary>
public FontWeight FontWeight
{
get { return GetValue(FontWeightProperty); }
set { SetValue(FontWeightProperty, value); }
}
/// <summary>
/// Gets or sets the font stretch.
/// Gets or sets the font stretch used to draw the control's text.
/// </summary>
public FontStretch FontStretch
{
@ -267,7 +256,7 @@ namespace Avalonia.Controls
}
/// <summary>
/// Gets or sets a brush used to paint the text.
/// Gets or sets the brush used to draw the control's text and other foreground elements.
/// </summary>
public IBrush? Foreground
{
@ -328,125 +317,43 @@ namespace Avalonia.Controls
get => GetValue(TextDecorationsProperty);
set => SetValue(TextDecorationsProperty, value);
}
/// <summary>
/// Gets the value of the attached <see cref="FontFamilyProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font family.</returns>
public static FontFamily GetFontFamily(Control control)
{
return control.GetValue(FontFamilyProperty);
}
/// <summary>
/// Gets the value of the attached <see cref="FontSizeProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font size.</returns>
public static double GetFontSize(Control control)
{
return control.GetValue(FontSizeProperty);
}
/// <summary>
/// Gets the value of the attached <see cref="FontStyleProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font style.</returns>
public static FontStyle GetFontStyle(Control control)
{
return control.GetValue(FontStyleProperty);
}
/// <summary>
/// Gets the value of the attached <see cref="FontWeightProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font weight.</returns>
public static FontWeight GetFontWeight(Control control)
{
return control.GetValue(FontWeightProperty);
}
/// <summary>
/// Gets the value of the attached <see cref="FontStretchProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The font stretch.</returns>
public static FontStretch GetFontStretch(Control control)
{
return control.GetValue(FontStretchProperty);
}
/// <summary>
/// Gets the value of the attached <see cref="ForegroundProperty"/> on a control.
/// The BaselineOffset property provides an adjustment to baseline offset
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The foreground.</returns>
public static IBrush? GetForeground(Control control)
public double BaselineOffset
{
return control.GetValue(ForegroundProperty);
get { return (double)GetValue(BaselineOffsetProperty); }
set { SetValue(BaselineOffsetProperty, value); }
}
/// <summary>
/// Sets the value of the attached <see cref="FontFamilyProperty"/> on a control.
/// Reads the attached property from the given element
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFontFamily(Control control, FontFamily value)
/// <param name="control">The element to which to read the attached property.</param>
public static double GetBaselineOffset(Control control)
{
control.SetValue(FontFamilyProperty, value);
}
if (control == null)
{
throw new ArgumentNullException(nameof(control));
}
/// <summary>
/// Sets the value of the attached <see cref="FontSizeProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFontSize(Control control, double value)
{
control.SetValue(FontSizeProperty, value);
return control.GetValue(BaselineOffsetProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="FontStyleProperty"/> on a control.
/// Writes the attached property BaselineOffset to the given element.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFontStyle(Control control, FontStyle value)
/// <param name="control">The element to which to write the attached property.</param>
/// <param name="value">The property value to set</param>
public static void SetBaselineOffset(Control control, double value)
{
control.SetValue(FontStyleProperty, value);
}
/// <summary>
/// Sets the value of the attached <see cref="FontWeightProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFontWeight(Control control, FontWeight value)
{
control.SetValue(FontWeightProperty, value);
}
/// <summary>
/// Sets the value of the attached <see cref="FontStretchProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFontStretch(Control control, FontStretch value)
{
control.SetValue(FontStretchProperty, value);
}
if (control == null)
{
throw new ArgumentNullException(nameof(control));
}
/// <summary>
/// Sets the value of the attached <see cref="ForegroundProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetForeground(Control control, IBrush? value)
{
control.SetValue(ForegroundProperty, value);
control.SetValue(BaselineOffsetProperty, value);
}
/// <summary>
@ -562,7 +469,7 @@ namespace Avalonia.Controls
return finalSize;
}
_constraint = finalSize;
_constraint = new Size(finalSize.Width, Math.Ceiling(finalSize.Height));
_textLayout = null;
@ -588,15 +495,19 @@ namespace Avalonia.Controls
case nameof (FontWeight):
case nameof (FontStyle):
case nameof (FontFamily):
case nameof (FontStretch):
case nameof (TextWrapping):
case nameof (TextTrimming):
case nameof (TextAlignment):
case nameof (FlowDirection):
case nameof (Padding):
case nameof (LineHeight):
case nameof (MaxLines):
case nameof (InlinesProperty):
case nameof (Text):
case nameof (TextDecorations):

112
src/Avalonia.Controls/TextBox.cs

@ -23,6 +23,7 @@ namespace Avalonia.Controls
/// <summary>
/// Represents a control that can be used to display or edit unformatted text.
/// </summary>
[TemplatePart("PART_TextPresenter", typeof(TextPresenter))]
[PseudoClasses(":empty")]
public class TextBox : TemplatedControl, UndoRedoHelper<TextBox.UndoRedoState>.IUndoRedoHost
{
@ -77,6 +78,9 @@ namespace Avalonia.Controls
public static readonly StyledProperty<int> MaxLengthProperty =
AvaloniaProperty.Register<TextBox, int>(nameof(MaxLength), defaultValue: 0);
public static readonly StyledProperty<int> MaxLinesProperty =
AvaloniaProperty.Register<TextBox, int>(nameof(MaxLines), defaultValue: 0);
public static readonly DirectProperty<TextBox, string?> TextProperty =
TextBlock.TextProperty.AddOwnerWithDataValidation<TextBox>(
o => o.Text,
@ -349,6 +353,12 @@ namespace Avalonia.Controls
set { SetValue(MaxLengthProperty, value); }
}
public int MaxLines
{
get { return GetValue(MaxLinesProperty); }
set { SetValue(MaxLinesProperty, value); }
}
[Content]
public string? Text
{
@ -670,6 +680,39 @@ namespace Avalonia.Controls
_selectedTextChangesMadeSinceLastUndoSnapshot++;
SnapshotUndoRedo(ignoreChangeCount: false);
if (_presenter != null && MaxLines > 0)
{
var lineCount = _presenter.TextLayout.TextLines.Count;
var length = 0;
var graphemeEnumerator = new GraphemeEnumerator(input.AsMemory());
while (graphemeEnumerator.MoveNext())
{
var grapheme = graphemeEnumerator.Current;
if (grapheme.FirstCodepoint.IsBreakChar)
{
if(lineCount + 1 > MaxLines)
{
break;
}
else
{
lineCount++;
}
}
length += grapheme.Text.Length;
}
if (length < input.Length)
{
input = input.Remove(Math.Max(0, length));
}
}
var text = Text ?? string.Empty;
var newLength = input.Length + text.Length - Math.Abs(SelectionStart - SelectionEnd);
@ -997,18 +1040,25 @@ namespace Avalonia.Controls
SetSelectionForControlBackspace();
}
if (!DeleteSelection() && caretIndex > 0)
if (!DeleteSelection())
{
_presenter.MoveCaretHorizontal(LogicalDirection.Backward);
var characterHit = _presenter.GetNextCharacterHit(LogicalDirection.Backward);
var removedCharacters = Math.Max(0, caretIndex - _presenter.CaretIndex);
var length = Math.Max(0, caretIndex - removedCharacters);
var backspacePosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
SetTextInternal(text.Substring(0, length) +
text.Substring(caretIndex));
if (caretIndex != backspacePosition)
{
var start = Math.Min(backspacePosition, caretIndex);
var end = Math.Max(backspacePosition, caretIndex);
CaretIndex = _presenter.CaretIndex;
var length = end - start;
var editedText = text.Substring(0, start) + text.Substring(Math.Min(end, text.Length));
SetTextInternal(editedText);
CaretIndex = end;
}
}
SnapshotUndoRedo();
@ -1024,15 +1074,21 @@ namespace Avalonia.Controls
SetSelectionForControlDelete();
}
if (!DeleteSelection() && caretIndex < text.Length)
if (!DeleteSelection())
{
var characterHit = _presenter.GetNextCharacterHit();
var removedCharacters = Math.Max(0,
characterHit.FirstCharacterIndex + characterHit.TrailingLength - caretIndex);
var nextPosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
if(nextPosition != caretIndex)
{
var start = Math.Min(nextPosition, caretIndex);
var end = Math.Max(nextPosition, caretIndex);
SetTextInternal(text.Substring(0, caretIndex) +
text.Substring(caretIndex + removedCharacters));
var editedText = text.Substring(0, start) + text.Substring(Math.Min(end, text.Length));
SetTextInternal(editedText);
}
}
SnapshotUndoRedo();
@ -1249,17 +1305,17 @@ namespace Avalonia.Controls
private void MoveHorizontal(int direction, bool wholeWord, bool isSelecting)
{
if (_presenter == null)
{
return;
}
var text = Text ?? string.Empty;
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
if (!wholeWord)
{
if (_presenter == null)
{
return;
}
if (isSelecting)
{
_presenter.MoveCaretToTextPosition(selectionEnd);
@ -1303,10 +1359,16 @@ namespace Avalonia.Controls
SelectionEnd += offset;
_presenter.MoveCaretToTextPosition(SelectionEnd);
if (!isSelecting)
{
CaretIndex = SelectionEnd;
}
else
{
SelectionStart = selectionStart;
}
}
}
@ -1326,10 +1388,10 @@ namespace Avalonia.Controls
else
{
var textLines = _presenter.TextLayout.TextLines;
var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(caretIndex, true);
var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(caretIndex, false);
var textLine = textLines[lineIndex];
_presenter.MoveCaretToTextPosition(textLine.TextRange.Start);
_presenter.MoveCaretToTextPosition(textLine.FirstTextSourceIndex);
}
}
@ -1350,16 +1412,10 @@ namespace Avalonia.Controls
else
{
var textLines = _presenter.TextLayout.TextLines;
var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(caretIndex, true);
var lineIndex = _presenter.TextLayout.GetLineIndexFromCharacterIndex(caretIndex, false);
var textLine = textLines[lineIndex];
if (caretIndex == textLine.TextRange.Start + textLine.TextRange.Length - textLine.NewLineLength &&
lineIndex + 1 < textLines.Count)
{
textLine = textLines[++lineIndex];
}
var textPosition = textLine.TextRange.Start + textLine.TextRange.Length - textLine.NewLineLength;
var textPosition = textLine.FirstTextSourceIndex + textLine.Length;
_presenter.MoveCaretToTextPosition(textPosition, true);
}

2
src/Avalonia.Controls/ToggleSwitch.cs

@ -9,6 +9,8 @@ namespace Avalonia.Controls
/// <summary>
/// A Toggle Switch control.
/// </summary>
[TemplatePart("MovingKnobs", typeof(Panel))]
[TemplatePart("SwitchKnob", typeof(Panel))]
[PseudoClasses(":dragging")]
public class ToggleSwitch : ToggleButton
{

2
src/Avalonia.Controls/TopLevel.cs

@ -1,5 +1,6 @@
using System;
using System.Reactive.Linq;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
@ -26,6 +27,7 @@ namespace Avalonia.Controls
/// It handles scheduling layout, styling and rendering as well as
/// tracking the widget's <see cref="ClientSize"/>.
/// </remarks>
[TemplatePart("PART_TransparencyFallback", typeof(Border))]
public abstract class TopLevel : ContentControl,
IInputRoot,
ILayoutRoot,

2
src/Avalonia.Controls/TreeView.cs

@ -849,7 +849,7 @@ namespace Avalonia.Controls
/// <param name="desired">The desired items.</param>
private static void SynchronizeItems(IList items, IEnumerable<object> desired)
{
var list = items.Cast<object>().ToList();
var list = items.Cast<object>();
var toRemove = list.Except(desired).ToList();
var toAdd = desired.Except(list).ToList();

1
src/Avalonia.Controls/TreeViewItem.cs

@ -12,6 +12,7 @@ namespace Avalonia.Controls
/// <summary>
/// An item in a <see cref="TreeView"/>.
/// </summary>
[TemplatePart("PART_Header", typeof(IControl))]
[PseudoClasses(":pressed", ":selected")]
public class TreeViewItem : HeaderedItemsControl, ISelectable
{

4
src/Avalonia.Controls/Utils/CollectionChangedEventManager.cs

@ -105,7 +105,7 @@ namespace Avalonia.Controls.Utils
static void Notify(
INotifyCollectionChanged incc,
NotifyCollectionChangedEventArgs args,
List<WeakReference<ICollectionChangedListener>> listeners)
WeakReference<ICollectionChangedListener>[] listeners)
{
foreach (var l in listeners)
{
@ -132,7 +132,7 @@ namespace Avalonia.Controls.Utils
}
}
var l = Listeners.ToList();
var l = Listeners.ToArray();
if (Dispatcher.UIThread.CheckAccess())
{

7
src/Avalonia.Controls/Window.cs

@ -12,7 +12,6 @@ using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Styling;
using JetBrains.Annotations;
namespace Avalonia.Controls
{
@ -258,7 +257,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets a collection of child windows owned by this window.
/// </summary>
public IReadOnlyList<Window> OwnedWindows => _children.Select(x => x.child).ToList();
public IReadOnlyList<Window> OwnedWindows => _children.Select(x => x.child).ToArray();
/// <summary>
/// Gets or sets a value indicating how the window will size itself to fit its content.
@ -527,7 +526,7 @@ namespace Avalonia.Controls
private void CloseInternal()
{
foreach (var (child, _) in _children.ToList())
foreach (var (child, _) in _children.ToArray())
{
child.CloseInternal();
}
@ -551,7 +550,7 @@ namespace Avalonia.Controls
bool canClose = true;
foreach (var (child, _) in _children.ToList())
foreach (var (child, _) in _children.ToArray())
{
if (child.ShouldCancelClose(args))
{

24
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/package-lock.json

@ -1078,12 +1078,6 @@
"json5": "^2.1.2"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
"schema-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
@ -1636,9 +1630,9 @@
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"dev": true
},
"mobx": {
@ -1839,12 +1833,6 @@
"ms": "^2.1.1"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
@ -2592,12 +2580,6 @@
"json5": "^2.1.2"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
"schema-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",

6
src/Avalonia.Diagnostics/Diagnostics/DevTools.cs

@ -105,13 +105,15 @@ namespace Avalonia.Diagnostics
private static IDisposable Open(Application? application, DevToolsOptions options, Window? owner = default)
{
var focussedControl = KeyboardDevice.Instance?.FocusedElement as IControl;
if (application is null)
{
throw new ArgumentNullException(nameof(application));
}
if (s_open.TryGetValue(application, out var window))
{
{
window.Activate();
window.SelectedControl(focussedControl);
}
else
{
@ -122,7 +124,7 @@ namespace Avalonia.Diagnostics
Height = options.Size.Height,
};
window.SetOptions(options);
window.SelectedControl(focussedControl);
window.Closed += DevToolsClosed;
s_open.Add(application, window);
if (options.ShowAsChildWindow && owner is { })

5
src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs

@ -41,5 +41,10 @@ namespace Avalonia.Diagnostics
/// <remarks>Default handler is <see cref="Screenshots.FilePickerHandler"/></remarks>
public IScreenshotHandler ScreenshotHandler { get; set; }
= Convetions.DefaultScreenshotHandler;
/// <summary>
/// Gets or sets whether DevTools should use the dark mode theme
/// </summary>
public bool UseDarkMode { get; set; }
}
}

5
src/Avalonia.Diagnostics/Diagnostics/ViewModels/BindingSetterViewModel.cs

@ -14,11 +14,13 @@ namespace Avalonia.Diagnostics.ViewModels
case Binding binding:
Path = binding.Path;
Tint = Brushes.CornflowerBlue;
ValueTypeTooltip = "Reflection Binding";
break;
case CompiledBindingExtension binding:
Path = binding.Path.ToString();
Tint = Brushes.DarkGreen;
ValueTypeTooltip = "Compiled Binding";
break;
case TemplateBinding binding:
@ -32,6 +34,7 @@ namespace Avalonia.Diagnostics.ViewModels
}
Tint = Brushes.OrangeRed;
ValueTypeTooltip = "Template Binding";
break;
default:
@ -40,6 +43,8 @@ namespace Avalonia.Diagnostics.ViewModels
}
public IBrush Tint { get; }
public string ValueTypeTooltip { get; }
public string Path { get; }

49
src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs

@ -18,7 +18,7 @@ namespace Avalonia.Diagnostics.ViewModels
internal class ControlDetailsViewModel : ViewModelBase, IDisposable
{
private readonly IAvaloniaObject _avaloniaObject;
private IDictionary<object, List<PropertyViewModel>>? _propertyIndex;
private IDictionary<object, PropertyViewModel[]>? _propertyIndex;
private PropertyViewModel? _selectedProperty;
private DataGridCollectionView? _propertiesView;
private bool _snapshotStyles;
@ -155,31 +155,19 @@ namespace Avalonia.Diagnostics.ViewModels
public object? SelectedEntity
{
get => _selectedEntity;
set
{
RaiseAndSetIfChanged(ref _selectedEntity, value);
}
set => RaiseAndSetIfChanged(ref _selectedEntity, value);
}
public string? SelectedEntityName
{
get => _selectedEntityName;
set
{
RaiseAndSetIfChanged(ref _selectedEntityName, value);
}
set => RaiseAndSetIfChanged(ref _selectedEntityName, value);
}
public string? SelectedEntityType
{
get => _selectedEntityType;
set
{
RaiseAndSetIfChanged(ref _selectedEntityType, value);
}
set => RaiseAndSetIfChanged(ref _selectedEntityType, value);
}
public PropertyViewModel? SelectedProperty
@ -484,9 +472,9 @@ namespace Avalonia.Diagnostics.ViewModels
.Concat(GetClrProperties(o, _showImplementedInterfaces))
.OrderBy(x => x, PropertyComparer.Instance)
.ThenBy(x => x.Name)
.ToList();
.ToArray();
_propertyIndex = properties.GroupBy(x => x.Key).ToDictionary(x => x.Key, x => x.ToList());
_propertyIndex = properties.GroupBy(x => x.Key).ToDictionary(x => x.Key, x => x.ToArray());
var view = new DataGridCollectionView(properties);
view.GroupDescriptions.Add(new DataGridPathGroupDescription(nameof(AvaloniaPropertyViewModel.Group)));
@ -502,6 +490,31 @@ namespace Avalonia.Diagnostics.ViewModels
inpc2.PropertyChanged += ControlPropertyChanged;
}
}
internal void SelectProperty(AvaloniaProperty property)
{
SelectedProperty = null;
if (SelectedEntity != _avaloniaObject)
{
NavigateToProperty(_avaloniaObject, (_avaloniaObject as IControl)?.Name ?? _avaloniaObject.ToString());
}
if (PropertiesView is null)
{
return;
}
foreach (object o in PropertiesView)
{
if (o is AvaloniaPropertyViewModel propertyVm && propertyVm.Property == property)
{
SelectedProperty = propertyVm;
break;
}
}
}
internal void UpdatePropertiesView(bool showImplementedInterfaces)
{

3
src/Avalonia.Diagnostics/Diagnostics/ViewModels/ResourceSetterViewModel.cs

@ -7,11 +7,14 @@ namespace Avalonia.Diagnostics.ViewModels
public object Key { get; }
public IBrush Tint { get; }
public string ValueTypeTooltip { get; }
public ResourceSetterViewModel(AvaloniaProperty property, object resourceKey, object? resourceValue, bool isDynamic) : base(property, resourceValue)
{
Key = resourceKey;
Tint = isDynamic ? Brushes.Orange : Brushes.Brown;
ValueTypeTooltip = isDynamic ? "Dynamic Resource" : "Static Resource";
}
public void CopyResourceKey()

4
src/Avalonia.Diagnostics/Diagnostics/Views/ConsoleView.xaml

@ -11,7 +11,7 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel Margin="{TemplateBinding Padding}">
<TextBlock DockPanel.Dock="Left" Margin="0,0,4,0">></TextBlock>
<TextBlock DockPanel.Dock="Left" Margin="0,0,4,0"></TextBlock>
<TextPresenter Name="PART_TextPresenter"
Text="{TemplateBinding Text, Mode=TwoWay}"
CaretIndex="{TemplateBinding CaretIndex}"
@ -44,7 +44,7 @@
<DataTemplate>
<StackPanel Orientation="Vertical">
<DockPanel>
<TextBlock DockPanel.Dock="Left" Margin="0,0,4,0">></TextBlock>
<TextBlock DockPanel.Dock="Left" Margin="0,0,4,0"></TextBlock>
<TextBlock Text="{Binding Input}"/>
</DockPanel>
<TextBlock Foreground="{Binding Foreground}" Text="{Binding Output}"/>

62
src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml

@ -44,7 +44,9 @@
UseWholeWordFilter="{Binding UseWholeWordFilter}"
UseRegexFilter="{Binding UseRegexFilter}"/>
<DataGrid Items="{Binding PropertiesView}"
<DataGrid
x:Name="DataGrid"
Items="{Binding PropertiesView}"
Grid.Row="2"
BorderThickness="0"
RowBackground="Transparent"
@ -129,6 +131,26 @@
</Expander.Header>
<ItemsControl Margin="20,0,0,0" Grid.Row="1" Items="{Binding Setters}">
<ItemsControl.Styles>
<Style Selector="TextBlock.property-name">
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="TextBlock.property-name:pointerover">
<Setter Property="TextDecorations" Value="Underline" />
</Style>
<Style Selector="Rectangle.property-inactive">
<Setter Property="IsHitTestVisible" Value="False" />
<Setter Property="Height" Value="1" />
<Setter Property="Fill" Value="#6C6C6C" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</ItemsControl.Styles>
<ItemsControl.DataTemplates>
<DataTemplate DataType="IBrush">
@ -138,6 +160,17 @@
</StackPanel>
</DataTemplate>
<DataTemplate DataType="Color">
<StackPanel Orientation="Horizontal" Spacing="2">
<Border BorderThickness="1" BorderBrush="Black" Width="8" Height="8">
<Border.Background>
<SolidColorBrush Color="{Binding}" />
</Border.Background>
</Border>
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="vm:BindingSetterViewModel">
<Panel Opacity="{Binding IsActive, Converter={StaticResource BoolToOpacity}}" IsVisible="{Binding IsVisible}" HorizontalAlignment="Left">
<Panel.ContextMenu>
@ -147,28 +180,17 @@
</ContextMenu>
</Panel.ContextMenu>
<StackPanel Orientation="Horizontal" Spacing="2">
<TextBlock Text="{Binding Name}" FontWeight="SemiBold" />
<TextBlock Classes="property-name" PointerPressed="PropertyNamePressed" Text="{Binding Name}" />
<TextBlock Text=":" />
<TextBlock>{</TextBlock>
<Rectangle Height="8" Width="8" VerticalAlignment="Center" Fill="{Binding Tint}"/>
<Rectangle Height="8" Width="8" VerticalAlignment="Center" Fill="{Binding Tint}" ToolTip.Tip="{Binding ValueTypeTooltip}"/>
<TextBlock Text="{Binding Path}" />
<TextBlock>}</TextBlock>
</StackPanel>
<Rectangle Height="1" Fill="#6C6C6C" VerticalAlignment="Center" IsVisible="{Binding !IsActive}" />
<Rectangle Classes="property-inactive" IsVisible="{Binding !IsActive}" />
</Panel>
</DataTemplate>
<DataTemplate DataType="Color">
<StackPanel Orientation="Horizontal" Spacing="2">
<Border BorderThickness="1" BorderBrush="Black" Width="8" Height="8">
<Border.Background>
<SolidColorBrush Color="{Binding}" />
</Border.Background>
</Border>
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="vm:ResourceSetterViewModel">
<Panel Opacity="{Binding IsActive, Converter={StaticResource BoolToOpacity}}" IsVisible="{Binding IsVisible}" HorizontalAlignment="Left">
<Panel.ContextMenu>
@ -179,15 +201,15 @@
</ContextMenu>
</Panel.ContextMenu>
<StackPanel Orientation="Horizontal" Spacing="2" HorizontalAlignment="Left">
<TextBlock Text="{Binding Name}" FontWeight="SemiBold" />
<TextBlock Classes="property-name" PointerPressed="PropertyNamePressed" Text="{Binding Name}" />
<TextBlock Text=":" />
<ContentControl Content="{Binding Value}"/>
<TextBlock>(</TextBlock>
<Ellipse Height="8" Width="8" VerticalAlignment="Center" Fill="{Binding Tint}"/>
<Ellipse Height="8" Width="8" VerticalAlignment="Center" Fill="{Binding Tint}" ToolTip.Tip="{Binding ValueTypeTooltip}"/>
<TextBlock FontStyle="Italic" Text="{Binding Key}" />
<TextBlock>)</TextBlock>
</StackPanel>
<Rectangle Height="1" Fill="#6C6C6C" IsVisible="{Binding !IsActive}" />
<Rectangle Classes="property-inactive" IsVisible="{Binding !IsActive}" />
</Panel>
</DataTemplate>
@ -200,11 +222,11 @@
</ContextMenu>
</Panel.ContextMenu>
<StackPanel Orientation="Horizontal" Spacing="2">
<TextBlock Text="{Binding Name}" FontWeight="SemiBold" />
<TextBlock Classes="property-name" PointerPressed="PropertyNamePressed" Text="{Binding Name}" />
<TextBlock Text=":" />
<ContentControl Content="{Binding Value}"/>
</StackPanel>
<Rectangle Height="1" Fill="#6C6C6C" VerticalAlignment="Center" IsVisible="{Binding !IsActive}" />
<Rectangle Classes="property-inactive" IsVisible="{Binding !IsActive}" />
</Panel>
</DataTemplate>

24
src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml.cs

@ -7,9 +7,13 @@ namespace Avalonia.Diagnostics.Views
{
internal class ControlDetailsView : UserControl
{
private DataGrid _dataGrid;
public ControlDetailsView()
{
InitializeComponent();
_dataGrid = this.GetControl<DataGrid>("DataGrid");
}
private void InitializeComponent()
@ -25,5 +29,25 @@ namespace Avalonia.Diagnostics.Views
}
}
private void PropertyNamePressed(object sender, PointerPressedEventArgs e)
{
var mainVm = (ControlDetailsViewModel?) DataContext;
if (mainVm is null)
{
return;
}
if (sender is Control control && control.DataContext is SetterViewModel setterVm)
{
mainVm.SelectProperty(setterVm.Property);
if (mainVm.SelectedProperty is not null)
{
_dataGrid.ScrollIntoView(mainVm.SelectedProperty, null);
}
}
}
}
}

2
src/Avalonia.Diagnostics/Diagnostics/Views/LayoutExplorerView.axaml

@ -15,6 +15,7 @@
<SolidColorBrush x:Key="PaddingHighlightBrush" Color="#CEDA8E" />
<SolidColorBrush x:Key="SizeBackgroundBrush" Color="#88B2BD" />
<SolidColorBrush x:Key="SizeHighlightBrush" Color="#9ED0DC" />
<SolidColorBrush x:Key="ThicknessEditorForeground" Color="Black" />
</UserControl.Resources>
<Grid RowDefinitions="*,Auto">
@ -46,6 +47,7 @@
<controls:ThicknessEditor Grid.Row="0" Grid.Column="0" Header="margin" VerticalAlignment="Top"
HorizontalAlignment="Center"
Foreground="{StaticResource ThicknessEditorForeground}"
Background="{StaticResource MarginBackgroundBrush}"
Highlight="{StaticResource MarginHighlightBrush}"
Thickness="{Binding MarginThickness}">

32
src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs

@ -11,6 +11,7 @@ using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Markup.Xaml;
using Avalonia.Styling;
using Avalonia.Themes.Default;
using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.Views
@ -109,7 +110,7 @@ namespace Avalonia.Diagnostics.Views
{
#pragma warning disable CS0618 // Type or member is obsolete
var point = (topLevel as IInputRoot)?.MouseDevice?.GetPosition(topLevel) ?? default;
#pragma warning restore CS0618 // Type or member is obsolete
#pragma warning restore CS0618 // Type or member is obsolete
return (IControl?)topLevel.GetVisualsAt(point, x =>
{
@ -161,13 +162,18 @@ namespace Avalonia.Diagnostics.Views
return;
}
var root = Root as TopLevel
?? vm.PointerOverRoot as TopLevel;
var root = vm.PointerOverRoot as TopLevel;
if (root is null)
{
return;
}
if (root is PopupRoot pr && pr.ParentTopLevel != null)
{
root = pr.ParentTopLevel;
}
switch (e.Modifiers)
{
case RawInputModifiers.Control when (e.Key == Key.LeftShift || e.Key == Key.RightShift):
@ -242,7 +248,25 @@ namespace Avalonia.Diagnostics.Views
private void RootClosed(object? sender, EventArgs e) => Close();
public void SetOptions(DevToolsOptions options) =>
public void SetOptions(DevToolsOptions options)
{
(DataContext as MainViewModel)?.SetOptions(options);
if (options.UseDarkMode)
{
if (Styles[0] is SimpleTheme st)
{
st.Mode = SimpleThemeMode.Dark;
}
}
}
internal void SelectedControl(IControl? control)
{
if (control is { })
{
(DataContext as MainViewModel)?.SelectControl(control);
}
}
}
}

3
src/Avalonia.Dialogs/ManagedFileChooser.cs

@ -2,6 +2,7 @@ using System;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
@ -9,6 +10,8 @@ using Avalonia.LogicalTree;
namespace Avalonia.Dialogs
{
[TemplatePart("QuickLinks", typeof(Control))]
[TemplatePart("Files", typeof(ListBox))]
public class ManagedFileChooser : TemplatedControl
{
private Control _quickLinksRoot;

7
src/Avalonia.Headless/HeadlessPlatformStubs.cs

@ -133,9 +133,12 @@ namespace Avalonia.Headless
class HeadlessTextShaperStub : ITextShaperImpl
{
public ShapedBuffer ShapeText(ReadOnlySlice<char> text, GlyphTypeface typeface, double fontRenderingEmSize,
CultureInfo culture, sbyte bidiLevel)
public ShapedBuffer ShapeText(ReadOnlySlice<char> text, TextShaperOptions options)
{
var typeface = options.Typeface;
var fontRenderingEmSize = options.FontRenderingEmSize;
var bidiLevel = options.BidLevel;
return new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel);
}
}

2
src/Avalonia.Input/FocusManager.cs

@ -73,7 +73,7 @@ namespace Avalonia.Input
else if (Current != null)
{
// If control is null, set focus to the topmost focus scope.
foreach (var scope in GetFocusScopeAncestors(Current).Reverse().ToList())
foreach (var scope in GetFocusScopeAncestors(Current).Reverse().ToArray())
{
if (scope != Scope &&
_focusScopes.TryGetValue(scope, out var element) &&

2
src/Avalonia.Input/TouchDevice.cs

@ -114,7 +114,7 @@ namespace Avalonia.Input
{
if (_disposed)
return;
var values = _pointers.Values.ToList();
var values = _pointers.Values.ToArray();
_pointers.Clear();
_disposed = true;
foreach (var p in values)

13
src/Avalonia.Styling/Controls/Metadata/PseudoClassesAttribute.cs

@ -5,14 +5,27 @@ using System.Collections.Generic;
namespace Avalonia.Controls.Metadata
{
/// <summary>
/// Defines all pseudoclasses by name referenced and implemented by a control.
/// </summary>
/// <remarks>
/// This is currently used for code-completion in certain IDEs.
/// </remarks>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class PseudoClassesAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="PseudoClassesAttribute"/> class.
/// </summary>
/// <param name="pseudoClasses">The list of pseudoclass names.</param>
public PseudoClassesAttribute(params string[] pseudoClasses)
{
PseudoClasses = pseudoClasses;
}
/// <summary>
/// Gets the list of pseudoclass names.
/// </summary>
public IReadOnlyList<string> PseudoClasses { get; }
}
}

55
src/Avalonia.Styling/Controls/Metadata/TemplatePartAttribute.cs

@ -0,0 +1,55 @@
// This source file is adapted from the Windows Presentation Foundation project.
// (https://github.com/dotnet/wpf/)
//
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
#nullable enable
namespace Avalonia.Controls.Metadata
{
/// <summary>
/// Defines a control template part referenced by name in code.
/// Template part names should begin with the "PART_" prefix.
/// </summary>
/// <remarks>
/// Style authors should be able to identify the part type used for styling the specific control.
/// The part is usually required in the style and should have a specific predefined name.
/// </remarks>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class TemplatePartAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="TemplatePartAttribute"/> class.
/// </summary>
public TemplatePartAttribute()
{
Name = string.Empty;
Type = typeof(object);
}
/// <summary>
/// Initializes a new instance of the <see cref="TemplatePartAttribute"/> class.
/// </summary>
/// <param name="name">The part name used by the class to identify a required element in the style.</param>
/// <param name="type">The type of the element that should be used as a part with name.</param>
public TemplatePartAttribute(string name, Type type)
{
Name = name;
Type = type;
}
/// <summary>
/// Gets or sets the part name used by the class to identify a required element in the style.
/// Template part names should begin with the "PART_" prefix.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the type of the element that should be used as a part with name specified
/// in <see cref="Name"/>.
/// </summary>
public Type Type { get; set; }
}
}

2
src/Avalonia.Themes.Default/Controls/Button.xaml

@ -18,7 +18,7 @@
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"
RecognizesAccessKey="True"
TextBlock.Foreground="{TemplateBinding Foreground}"
TextElement.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>

2
src/Avalonia.Themes.Default/Controls/CaptionButtons.xaml

@ -4,7 +4,7 @@
<Setter Property="MaxHeight" Value="30" />
<Setter Property="Template">
<ControlTemplate>
<StackPanel Spacing="2" VerticalAlignment="Stretch" TextBlock.FontSize="10" Orientation="Horizontal">
<StackPanel Spacing="2" VerticalAlignment="Stretch" TextElement.FontSize="10" Orientation="Horizontal">
<StackPanel.Styles>
<Style Selector="Panel">
<Setter Property="Width" Value="45" />

2
src/Avalonia.Themes.Default/Controls/CheckBox.xaml

@ -37,7 +37,7 @@
</Panel>
</Border>
<ContentPresenter Name="PART_ContentPresenter"
TextBlock.Foreground="{TemplateBinding Foreground}"
TextElement.Foreground="{TemplateBinding Foreground}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"

18
src/Avalonia.Themes.Default/Controls/DatePicker.xaml

@ -36,7 +36,7 @@
</Style>
<Style Selector="ListBoxItem.DateTimePickerItem:selected /template/ ContentPresenter">
<Setter Property="Background" Value="Transparent" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="ListBoxItem.DateTimePickerItem.MonthItem">
<Setter Property="Padding" Value="{DynamicResource DatePickerFlyoutPresenterMonthPadding}"/>
@ -58,7 +58,7 @@
BorderBrush="{DynamicResource ThemeControlTransparentBrush}"
BorderThickness="{DynamicResource DateTimeFlyoutButtonBorderThickness}"
Content="{TemplateBinding Content}"
TextBlock.Foreground="{DynamicResource ThemeForegroundBrush}"
TextElement.Foreground="{DynamicResource ThemeForegroundBrush}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
@ -71,13 +71,13 @@
<Style Selector=":is(Button).DateTimeFlyoutButtonStyle:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightLowBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlTransparentBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector=":is(Button).DateTimeFlyoutButtonStyle:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlTransparentBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
@ -151,7 +151,7 @@
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Content="{TemplateBinding Content}"
TextBlock.Foreground="{TemplateBinding Foreground}"
TextElement.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"/>
</ControlTemplate>
@ -196,7 +196,7 @@
</Setter>
</Style>
<Style Selector="DatePicker /template/ ContentPresenter#HeaderContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="DatePicker:disabled /template/ Rectangle">
<!--<Setter Property="Fill" Value="{DynamicResource DatePickerSpacerFillDisabled}"/>-->
@ -206,7 +206,7 @@
<Style Selector="DatePicker /template/ Button#FlyoutButton:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlHighBrush}"/>
<!--<Setter Property="Background" Value="{DynamicResource DatePickerButtonBackgroundPointerOver}"/>-->
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="DatePicker /template/ Button#FlyoutButton:pressed /template/ ContentPresenter">
@ -214,13 +214,13 @@
<Setter Property="Background">
<SolidColorBrush Color="{DynamicResource ThemeControlMidHighColor}" Opacity="0.6" />
</Setter>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="DatePicker /template/ Button#FlyoutButton:disabled /template/ ContentPresenter">
<!--<Setter Property="BorderBrush" Value="{DynamicResource DatePickerButtonBorderBrushDisabled}"/>
<Setter Property="Background" Value="{DynamicResource DatePickerButtonBackgroundDisabled}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource DatePickerButtonForegroundDisabled}"/>-->
<Setter Property="TextElement.Foreground" Value="{DynamicResource DatePickerButtonForegroundDisabled}"/>-->
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" />
</Style>

67
src/Avalonia.Themes.Default/Controls/DropDownButton.xaml

@ -0,0 +1,67 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="DropDownButton">
<Setter Property="Background" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Name="RootBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
ClipToBounds="True">
<Grid Name="InnerGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Name="PART_ContentPresenter"
Grid.Column="0"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Padding="{TemplateBinding Padding}"
RecognizesAccessKey="True"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
<PathIcon Name="DropDownGlyph"
Grid.Column="1"
UseLayoutRounding="False"
IsHitTestVisible="False"
Height="12"
Width="12"
Margin="0,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style Selector="DropDownButton /template/ PathIcon#DropDownGlyph">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}" />
<Setter Property="Data" Value="M1939 486L2029 576L1024 1581L19 576L109 486L1024 1401L1939 486Z" />
</Style>
<Style Selector="DropDownButton:pointerover /template/ Border#RootBorder">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
</Style>
<Style Selector="DropDownButton:pressed /template/ Border#RootBorder">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighBrush}"/>
</Style>
<Style Selector="DropDownButton:disabled">
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
</Style>
</Styles>

2
src/Avalonia.Themes.Default/Controls/RepeatButton.xaml

@ -24,7 +24,7 @@
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
TextElement.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>

26
src/Avalonia.Themes.Default/Controls/SplitButton.xaml

@ -16,6 +16,7 @@
<x:Double x:Key="SplitButtonPrimaryButtonSize">24</x:Double>
<x:Double x:Key="SplitButtonSecondaryButtonSize">24</x:Double>
<x:Double x:Key="SplitButtonSeparatorWidth">1</x:Double>
<x:Double x:Key="SplitButtonMinHeight">24</x:Double>
<Thickness x:Key="SplitButtonBorderThemeThickness">1</Thickness>
<converters:MarginMultiplierConverter x:Key="PrimaryButtonBorderMultiplier" Left="True" Top="True" Bottom="True" Indent="1" />
@ -59,8 +60,11 @@
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForeground}" />
<Setter Property="BorderBrush" Value="{DynamicResource SplitButtonBorderBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource SplitButtonBorderThemeThickness}" />
<Setter Property="MinHeight" Value="{DynamicResource SplitButtonMinHeight}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<!--<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="FocusVisualMargin" Value="-3" />-->
<Setter Property="KeyboardNavigation.IsTabStop" Value="True" />
@ -146,7 +150,7 @@
SplitButton /template/ Button#PART_SecondaryButton:pointerover /template/ ContentPresenter">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundPointerOver}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundPointerOver}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundPointerOver}" />
</Style>
<Style Selector="SplitButton /template/ Button#PART_SecondaryButton:pointerover PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundPointerOver}" />
@ -157,7 +161,7 @@
SplitButton /template/ Button#PART_SecondaryButton:pressed /template/ ContentPresenter">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundPressed}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" />
</Style>
<Style Selector="SplitButton /template/ Button#PART_SecondaryButton:pressed PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" />
@ -169,7 +173,7 @@
SplitButton:pressed /template/ Border#SeparatorBorder">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundPressed}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" />
</Style>
<Style Selector="SplitButton:pressed /template/ Button#PART_SecondaryButton PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" />
@ -181,7 +185,7 @@
SplitButton:flyout-open /template/ Border#SeparatorBorder">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundPressed}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" />
</Style>
<Style Selector="SplitButton:flyout-open /template/ Button#PART_SecondaryButton PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundPressed}" />
@ -193,7 +197,7 @@
SplitButton:disabled /template/ Border#SeparatorBorder">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundDisabled}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundDisabled}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundDisabled}" />
</Style>
<Style Selector="SplitButton:disabled /template/ Button#PART_SecondaryButton PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundDisabled}" />
@ -205,7 +209,7 @@
SplitButton:checked /template/ Border#SeparatorBorder">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundChecked}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushChecked}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundChecked}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundChecked}" />
</Style>
<Style Selector="SplitButton:checked /template/ Button#PART_SecondaryButton PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundChecked}" />
@ -216,7 +220,7 @@
SplitButton:checked /template/ Button#PART_SecondaryButton:pointerover /template/ ContentPresenter">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundCheckedPointerOver}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushCheckedPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPointerOver}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPointerOver}" />
</Style>
<Style Selector="SplitButton:checked /template/ Button#PART_SecondaryButton:pointerover PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPointerOver}" />
@ -227,7 +231,7 @@
SplitButton:checked /template/ Button#PART_SecondaryButton:pressed /template/ ContentPresenter">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundCheckedPressed}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushCheckedPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" />
</Style>
<Style Selector="SplitButton:checked /template/ Button#PART_SecondaryButton:pressed PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" />
@ -239,7 +243,7 @@
SplitButton:pressed:checked /template/ Border#SeparatorBorder">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundCheckedPressed}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushCheckedPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" />
</Style>
<Style Selector="SplitButton:pressed:checked /template/ Button#PART_SecondaryButton PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" />
@ -251,7 +255,7 @@
SplitButton:checked:flyout-open /template/ Border#SeparatorBorder">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundCheckedPressed}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushCheckedPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" />
</Style>
<Style Selector="SplitButton:checked:flyout-open /template/ Button#PART_SecondaryButton PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundCheckedPressed}" />
@ -263,7 +267,7 @@
SplitButton:checked:disabled /template/ Border#SeparatorBorder">
<Setter Property="Border.Background" Value="{DynamicResource SplitButtonBackgroundCheckedDisabled}" />
<Setter Property="Border.BorderBrush" Value="{DynamicResource SplitButtonBorderBrushCheckedDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedDisabled}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource SplitButtonForegroundCheckedDisabled}" />
</Style>
<Style Selector="SplitButton:checked:disabled /template/ Button#PART_SecondaryButton PathIcon">
<Setter Property="Foreground" Value="{DynamicResource SplitButtonForegroundCheckedDisabled}" />

12
src/Avalonia.Themes.Default/Controls/TimePicker.xaml

@ -48,7 +48,7 @@
ContentTemplate="{TemplateBinding HeaderTemplate}"
Margin="{DynamicResource TimePickerTopHeaderMargin}"
MaxWidth="{DynamicResource TimePickerThemeMaxWidth}"
TextBlock.Foreground="{DynamicResource ThemeForegroundColor}"
TextElement.Foreground="{DynamicResource ThemeForegroundColor}"
HorizontalAlignment="Stretch"
VerticalAlignment="Top" />
@ -74,7 +74,7 @@
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Content="{TemplateBinding Content}"
TextBlock.Foreground="{TemplateBinding Foreground}"
TextElement.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch" />
</ControlTemplate>
@ -135,7 +135,7 @@
</Style>
<Style Selector="TimePicker:disabled /template/ ContentPresenter#HeaderContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="TimePicker:disabled /template/ Rectangle">
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
@ -144,7 +144,7 @@
<Style Selector="TimePicker /template/ Button#FlyoutButton:pointerover /template/ ContentPresenter">
<!--<Setter Property="Background" Value="{DynamicResource TimePickerButtonBackgroundPointerOver}"/>-->
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlHighBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="TimePicker /template/ Button:pressed /template/ ContentPresenter">
@ -152,13 +152,13 @@
<SolidColorBrush Color="{DynamicResource ThemeControlMidHighColor}" Opacity="0.6" />
</Setter>
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlLowBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource ThemeForegroundBrush}"/>
</Style>
<Style Selector="TimePicker /template/ Button:disabled /template/ ContentPresenter">
<!--<Setter Property="Background" Value="{DynamicResource TimePickerButtonBackgroundDisabled}"/>
<Setter Property="BorderBrush" Value="{DynamicResource TimePickerButtonBorderBrushDisabled}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TimePickerButtonForegroundDisabled}"/>-->
<Setter Property="TextElement.Foreground" Value="{DynamicResource TimePickerButtonForegroundDisabled}"/>-->
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" />
</Style>

2
src/Avalonia.Themes.Default/Controls/ToggleButton.xaml

@ -18,7 +18,7 @@
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"
RecognizesAccessKey="True"
TextBlock.Foreground="{TemplateBinding Foreground}"
TextElement.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>

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

@ -3,8 +3,9 @@
x:Class="Avalonia.Themes.Default.DefaultTheme">
<!-- Define ToolTip first so its styles can be overriden by other controls (e.g. TextBox) -->
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/ToolTip.xaml"/>
<!-- PathIcon also needs to be defined early so it can be overriden by other styles (e.g. ComboBox) -->
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/PathIcon.xaml" />
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/DataValidationErrors.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/FocusAdorner.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/Button.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/Carousel.xaml"/>
@ -13,6 +14,7 @@
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/ComboBox.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/ComboBoxItem.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/ContentControl.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/DropDownButton.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/Label.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/GridSplitter.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/ItemsControl.xaml"/>
@ -22,7 +24,6 @@
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/ContextMenu.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/MenuItem.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/OverlayPopupHost.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/PathIcon.xaml" />
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/PopupRoot.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/ProgressBar.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Controls/RadioButton.xaml"/>

28
src/Avalonia.Themes.Fluent/Controls/Button.xaml

@ -4,7 +4,7 @@
<StackPanel Spacing="20">
<Button Content="Click Me!" />
<Button Classes="accent" Content="Click Me!" />
</StackPanel>
</StackPanel>
</Border>
</Design.PreviewWith>
<Styles.Resources>
@ -19,9 +19,7 @@
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
<Setter Property="Padding" Value="{DynamicResource ButtonPadding}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="VerticalAlignment" Value="Center" />
<!--<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />-->
<Setter Property="Template">
@ -45,40 +43,40 @@
<Style Selector="Button:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
</Style>
<Style Selector="Button:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
</Style>
<Style Selector="Button:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
</Style>
<Style Selector="Button.accent /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrush}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource AccentButtonForeground}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource AccentButtonForeground}" />
</Style>
<Style Selector="Button.accent:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource AccentButtonForegroundPointerOver}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource AccentButtonForegroundPointerOver}" />
</Style>
<Style Selector="Button.accent:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPressed}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource AccentButtonForegroundPressed}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource AccentButtonForegroundPressed}" />
</Style>
<Style Selector="Button, RepeatButton, ToggleButton">
<Style Selector="Button, RepeatButton, ToggleButton, DropDownButton">
<Setter Property="RenderTransform" Value="none" />
<Setter Property="Transitions">
<Transitions>
@ -87,13 +85,13 @@
</Setter>
</Style>
<Style Selector="Button:pressed, RepeatButton:pressed, ToggleButton:pressed">
<Style Selector="Button:pressed, RepeatButton:pressed, ToggleButton:pressed, DropDownButton:pressed">
<Setter Property="RenderTransform" Value="scale(0.98)" />
</Style>
<Style Selector="Button.accent:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource AccentButtonForegroundDisabled}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource AccentButtonForegroundDisabled}" />
</Style>
</Styles>

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

Loading…
Cancel
Save