Browse Source

Merge branch 'master' into features/focus-manager-remove-window-from-focus-scopes-when-closing

pull/6811/head
Dan Walmsley 5 years ago
committed by GitHub
parent
commit
52b474ee8e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      readme.md
  2. 6
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  3. 2
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/HtmlTransport.cs
  4. 4
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs
  5. 4
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs
  6. 141
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs
  7. 1
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs
  8. 17
      src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml
  9. 11
      src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml.cs
  10. 2
      src/Avalonia.Headless/HeadlessWindowImpl.cs
  11. 2
      src/Avalonia.Input/InputElement.cs
  12. 9
      src/Avalonia.Layout/ElementManager.cs
  13. 4
      src/Avalonia.Themes.Fluent/Controls/NumericUpDown.xaml
  14. 2
      src/Avalonia.X11/X11Window.Ime.cs
  15. 2
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs
  16. 17
      tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs

3
readme.md

@ -93,7 +93,8 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
<a href="https://opencollective.com/Avalonia/sponsor/6/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/Avalonia/sponsor/7/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/Avalonia/sponsor/8/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/Avalonia/sponsor/9/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/9/avatar.svg"></a>
<a href="https://opencollective.com/Avalonia/sponsor/9/website" target="_blank"><img src="https://opencollective.com/Avalonia/sponsor/9/avatar.svg"></a>
<a href="https://baseheadinc.com/" target="_blank"><img height="50" src="https://baseheadinc.com/wp-content/uploads/2020/09/BH-Logo-for-Site-Header-New.png"></a>
## .NET Foundation

6
src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Interactivity;
@ -376,7 +377,10 @@ namespace Avalonia.Controls.Platform
{
if (item.IsSubMenuOpen)
{
if (item.IsTopLevel)
// PointerPressed events may bubble from disabled items in sub-menus. In this case,
// keep the sub-menu open.
var popup = (e.Source as ILogical)?.FindLogicalAncestorOfType<Popup>();
if (item.IsTopLevel && popup == null)
{
CloseMenu(item);
}

2
src/Avalonia.DesignerSupport/Remote/HtmlTransport/HtmlTransport.cs

@ -25,7 +25,6 @@ namespace Avalonia.DesignerSupport.Remote.HtmlTransport
private AutoResetEvent _wakeup = new AutoResetEvent(false);
private FrameMessage _lastFrameMessage = null;
private FrameMessage _lastSentFrameMessage = null;
private RequestViewportResizeMessage _lastViewportRequest;
private Action<IAvaloniaRemoteTransportConnection, object> _onMessage;
private Action<IAvaloniaRemoteTransportConnection, Exception> _onException;
@ -177,6 +176,7 @@ namespace Avalonia.DesignerSupport.Remote.HtmlTransport
public void Dispose()
{
_disposed = true;
_pendingSocket?.Dispose();
_simpleServer.Dispose();
}

4
src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs

@ -19,7 +19,7 @@ namespace Avalonia.Diagnostics.ViewModels
Name = property.IsAttached ?
$"[{property.OwnerType.Name}.{property.Name}]" :
property.Name;
DeclaringType = property.OwnerType;
Update();
}
@ -50,6 +50,8 @@ namespace Avalonia.Diagnostics.ViewModels
public override string Group => _group;
public override System.Type? DeclaringType { get; }
// [MemberNotNull(nameof(_type), nameof(_group), nameof(_priority))]
public override void Update()
{

4
src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs

@ -24,7 +24,7 @@ namespace Avalonia.Diagnostics.ViewModels
{
Name = property.DeclaringType.Name + '.' + property.Name;
}
DeclaringType = property.DeclaringType;
Update();
}
@ -55,6 +55,8 @@ namespace Avalonia.Diagnostics.ViewModels
public override bool? IsAttached =>
default;
public override System.Type? DeclaringType { get; }
// [MemberNotNull(nameof(_type))]
public override void Update()
{

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

@ -17,42 +17,26 @@ namespace Avalonia.Diagnostics.ViewModels
internal class ControlDetailsViewModel : ViewModelBase, IDisposable
{
private readonly IVisual _control;
private readonly IDictionary<object, List<PropertyViewModel>> _propertyIndex;
private IDictionary<object, List<PropertyViewModel>> _propertyIndex;
private PropertyViewModel? _selectedProperty;
private DataGridCollectionView _propertiesView;
private bool _snapshotStyles;
private bool _showInactiveStyles;
private string? _styleStatus;
private object _selectedEntity;
private readonly Stack<(string Name,object Entry)> _selectedEntitiesStack = new();
private string _selectedEntityName;
private string _selectedEntityType;
public ControlDetailsViewModel(TreePageViewModel treePage, IVisual control)
{
_control = control;
TreePage = treePage;
var properties = GetAvaloniaProperties(control)
.Concat(GetClrProperties(control))
.OrderBy(x => x, PropertyComparer.Instance)
.ThenBy(x => x.Name)
.ToList();
_propertyIndex = properties.GroupBy(x => x.Key).ToDictionary(x => x.Key, x => x.ToList());
var view = new DataGridCollectionView(properties);
view.GroupDescriptions.Add(new DataGridPathGroupDescription(nameof(AvaloniaPropertyViewModel.Group)));
view.Filter = FilterProperty;
PropertiesView = view;
Layout = new ControlLayoutViewModel(control);
if (control is INotifyPropertyChanged inpc)
{
inpc.PropertyChanged += ControlPropertyChanged;
}
if (control is AvaloniaObject ao)
{
ao.PropertyChanged += ControlPropertyChanged;
}
NavigateToProperty(control, (control as IControl)?.Name ?? control.ToString());
AppliedStyles = new ObservableCollection<StyleViewModel>();
PseudoClasses = new ObservableCollection<PseudoClassViewModel>();
@ -133,12 +117,46 @@ namespace Avalonia.Diagnostics.ViewModels
public TreePageViewModel TreePage { get; }
public DataGridCollectionView PropertiesView { get; }
public DataGridCollectionView PropertiesView
{
get => _propertiesView;
private set => RaiseAndSetIfChanged(ref _propertiesView, value);
}
public ObservableCollection<StyleViewModel> AppliedStyles { get; }
public ObservableCollection<PseudoClassViewModel> PseudoClasses { get; }
public object SelectedEntity
{
get => _selectedEntity;
set
{
RaiseAndSetIfChanged(ref _selectedEntity, value);
}
}
public string SelectedEntityName
{
get => _selectedEntityName;
set
{
RaiseAndSetIfChanged(ref _selectedEntityName, value);
}
}
public string SelectedEntityType
{
get => _selectedEntityType;
set
{
RaiseAndSetIfChanged(ref _selectedEntityType, value);
}
}
public PropertyViewModel? SelectedProperty
{
get => _selectedProperty;
@ -378,5 +396,78 @@ namespace Avalonia.Diagnostics.ViewModels
}
}
}
public void ApplySelectedProperty()
{
var selectedProperty = SelectedProperty;
var selectedEntity = SelectedEntity;
var selectedEntityName = SelectedEntityName;
if (selectedProperty == null)
return;
object? property;
if (selectedProperty.Key is AvaloniaProperty avaloniaProperty)
{
property = (_selectedEntity as IControl)?.GetValue(avaloniaProperty);
}
else
{
property = selectedEntity.GetType().GetProperties()
.FirstOrDefault(pi => pi.Name == selectedProperty.Name
&& pi.DeclaringType == selectedProperty.DeclaringType
&& pi.PropertyType.Name == selectedProperty.Type)
?.GetValue(selectedEntity);
}
if (property == null) return;
_selectedEntitiesStack.Push((Name:selectedEntityName,Entry:selectedEntity));
NavigateToProperty(property, selectedProperty.Name);
}
public void ApplyParentProperty()
{
if (_selectedEntitiesStack.Any())
{
var property = _selectedEntitiesStack.Pop();
NavigateToProperty(property.Entry, property.Name);
}
}
protected void NavigateToProperty(object o, string entityName)
{
var oldSelectedEntity = SelectedEntity;
if (oldSelectedEntity is IAvaloniaObject ao1)
{
ao1.PropertyChanged -= ControlPropertyChanged;
}
else if (oldSelectedEntity is INotifyPropertyChanged inpc1)
{
inpc1.PropertyChanged -= ControlPropertyChanged;
}
SelectedEntity = o;
SelectedEntityName = entityName;
SelectedEntityType = o.ToString();
var properties = GetAvaloniaProperties(o)
.Concat(GetClrProperties(o))
.OrderBy(x => x, PropertyComparer.Instance)
.ThenBy(x => x.Name)
.ToList();
_propertyIndex = properties.GroupBy(x => x.Key).ToDictionary(x => x.Key, x => x.ToList());
var view = new DataGridCollectionView(properties);
view.GroupDescriptions.Add(new DataGridPathGroupDescription(nameof(AvaloniaPropertyViewModel.Group)));
view.Filter = FilterProperty;
PropertiesView = view;
if (o is IAvaloniaObject ao2)
{
ao2.PropertyChanged += ControlPropertyChanged;
}
else if (o is INotifyPropertyChanged inpc2)
{
inpc2.PropertyChanged += ControlPropertyChanged;
}
}
}
}

1
src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs

@ -15,6 +15,7 @@ namespace Avalonia.Diagnostics.ViewModels
public abstract string Name { get; }
public abstract string Group { get; }
public abstract string Type { get; }
public abstract Type? DeclaringType { get; }
public abstract string Value { get; set; }
public abstract string Priority { get; }
public abstract bool? IsAttached { get; }

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

@ -13,23 +13,30 @@
<Grid ColumnDefinitions="*,Auto,320">
<Grid Grid.Column="0" RowDefinitions="Auto,*">
<Grid Grid.Column="0" RowDefinitions="Auto,Auto,*">
<controls:FilterTextBox Grid.Row="0"
<Grid ColumnDefinitions="Auto, *" RowDefinitions="Auto, Auto">
<Button Grid.Column="0" Grid.RowSpan="2" Content="^" Command="{Binding ApplyParentProperty}" />
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding SelectedEntityName}" FontWeight="Bold" />
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding SelectedEntityType}" FontStyle="Italic" />
</Grid>
<controls:FilterTextBox Grid.Row="1"
BorderThickness="0"
DataContext="{Binding TreePage.PropertiesFilter}"
Text="{Binding FilterString}"
Watermark="Filter properties"
UseCaseSensitiveFilter="{Binding UseCaseSensitiveFilter}"
UseWholeWordFilter="{Binding UseWholeWordFilter}"
UseRegexFilter="{Binding UseRegexFilter}" />
UseRegexFilter="{Binding UseRegexFilter}"/>
<DataGrid Items="{Binding PropertiesView}"
Grid.Row="1"
Grid.Row="2"
BorderThickness="0"
RowBackground="Transparent"
SelectedItem="{Binding SelectedProperty, Mode=TwoWay}"
CanUserResizeColumns="true">
CanUserResizeColumns="true"
DoubleTapped="PropertiesGrid_OnDoubleTapped">
<DataGrid.Columns>
<DataGridTextColumn Header="Property" Binding="{Binding Name}" IsReadOnly="True" />
<DataGridTextColumn Header="Value" Binding="{Binding Value}" />

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

@ -1,4 +1,6 @@
using Avalonia.Controls;
using Avalonia.Diagnostics.ViewModels;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
namespace Avalonia.Diagnostics.Views
@ -14,5 +16,14 @@ namespace Avalonia.Diagnostics.Views
{
AvaloniaXamlLoader.Load(this);
}
private void PropertiesGrid_OnDoubleTapped(object sender, TappedEventArgs e)
{
if (sender is DataGrid grid && grid.DataContext is ControlDetailsViewModel controlDetails)
{
controlDetails.ApplySelectedProperty();
}
}
}
}

2
src/Avalonia.Headless/HeadlessWindowImpl.cs

@ -199,7 +199,7 @@ namespace Avalonia.Headless
public ILockedFramebuffer Lock()
{
var bmp = new WriteableBitmap(PixelSize.FromSize(ClientSize, RenderScaling), new Vector(96, 96) * RenderScaling);
var bmp = new WriteableBitmap(PixelSize.FromSize(ClientSize, RenderScaling), new Vector(96, 96) * RenderScaling, PixelFormat.Rgba8888, AlphaFormat.Premul);
var fb = bmp.Lock();
return new FramebufferProxy(fb, () =>
{

2
src/Avalonia.Input/InputElement.cs

@ -16,7 +16,7 @@ namespace Avalonia.Input
/// <summary>
/// Implements input-related functionality for a control.
/// </summary>
[PseudoClasses(":disabled", ":focus", ":focus-visible", ":pointerover")]
[PseudoClasses(":disabled", ":focus", ":focus-visible", ":focus-within", ":pointerover")]
public class InputElement : Interactive, IInputElement
{
/// <summary>

9
src/Avalonia.Layout/ElementManager.cs

@ -314,12 +314,11 @@ namespace Avalonia.Layout
}
break;
// Remove clear all realized elements just to align the begavior
// with ViewManager which resets realized item indices to defaults.
// Freeing only removed items causes wrong indices to be stored
// in virtualized info of items under some circumstances.
case NotifyCollectionChangedAction.Remove:
{
OnItemsRemoved(args.OldStartingIndex, args.OldItems.Count);
}
break;
case NotifyCollectionChangedAction.Reset:
ClearRealizedRange();
break;

4
src/Avalonia.Themes.Fluent/Controls/NumericUpDown.xaml

@ -38,6 +38,7 @@
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="{TemplateBinding CornerRadius}"
Padding="0"
MinWidth="{TemplateBinding MinWidth}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
AllowSpin="{TemplateBinding AllowSpin}"
@ -49,6 +50,9 @@
BorderBrush="Transparent"
Margin="-1"
Padding="{TemplateBinding Padding}"
MinWidth="{TemplateBinding MinWidth}"
Foreground="{TemplateBinding Foreground}"
FontSize="{TemplateBinding FontSize}"
Watermark="{TemplateBinding Watermark}"
IsReadOnly="{TemplateBinding IsReadOnly}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"

2
src/Avalonia.X11/X11Window.Ime.cs

@ -33,8 +33,6 @@ namespace Avalonia.X11
&& ((int)(style & XIMProperties.XIMStatusNothing) != 0))
{
XPoint spot = default;
XRectangle area = default;
//using var areaS = new Utf8Buffer("area");
using var spotS = new Utf8Buffer("spotLocation");

2
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs

@ -66,7 +66,7 @@ namespace Avalonia.Skia
_canCreateSurfaces = true;
return surface;
}
catch (Exception e)
catch (Exception)
{
Logger.TryGet(LogEventLevel.Error, "OpenGL")
?.Log(this, "Unable to create a Skia-compatible FBO manually");

17
tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs

@ -1,5 +1,6 @@
using System;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
@ -540,6 +541,22 @@ namespace Avalonia.Controls.UnitTests.Platform
Mock.Get(item).Verify(x => x.MoveSelection(NavigationDirection.First, true), Times.Never);
Assert.True(e.Handled);
}
[Fact]
public void PointerPressed_On_Disabled_Item_Doesnt_Close_SubMenu()
{
var target = new DefaultMenuInteractionHandler(false);
var menu = Mock.Of<IMenu>();
var parentItem = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.HasSubMenu == true && x.IsSubMenuOpen == true && x.Parent == menu);
var popup = new Popup();
var e = CreatePressed(popup);
((ISetLogicalParent)popup).SetParent(parentItem);
target.PointerPressed(parentItem, e);
Mock.Get(parentItem).Verify(x => x.Close(), Times.Never);
Assert.True(e.Handled);
}
}
public class ContextMenu

Loading…
Cancel
Save