From 5a8a9e7ce2006ea62c28fa466eee7ff4152abc1c Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Wed, 5 Jun 2019 22:13:46 +0800 Subject: [PATCH 01/17] Cleaning up --- src/Avalonia.Controls/ColumnDefinitions.cs | 4 +- src/Avalonia.Controls/DefinitionBase.cs | 273 ++---- src/Avalonia.Controls/DefinitionList.cs | 7 +- src/Avalonia.Controls/Grid.cs | 943 +++------------------ src/Avalonia.Controls/RowDefinitions.cs | 4 +- 5 files changed, 202 insertions(+), 1029 deletions(-) diff --git a/src/Avalonia.Controls/ColumnDefinitions.cs b/src/Avalonia.Controls/ColumnDefinitions.cs index 4f5bbf3bc3..d4fc2ee0a1 100644 --- a/src/Avalonia.Controls/ColumnDefinitions.cs +++ b/src/Avalonia.Controls/ColumnDefinitions.cs @@ -16,10 +16,8 @@ namespace Avalonia.Controls /// /// Initializes a new instance of the class. /// - public ColumnDefinitions() + public ColumnDefinitions() : base () { - ResetBehavior = ResetBehavior.Remove; - CollectionChanged += OnCollectionChanged; } /// diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs index 8899c38bf9..d04578b371 100644 --- a/src/Avalonia.Controls/DefinitionBase.cs +++ b/src/Avalonia.Controls/DefinitionBase.cs @@ -20,49 +20,15 @@ namespace Avalonia.Controls /// public abstract class DefinitionBase : AvaloniaObject { - //------------------------------------------------------ - // - // Constructors - // - //------------------------------------------------------ - - #region Constructors - - /* internal DefinitionBase(bool isColumnDefinition) - { - _isColumnDefinition = isColumnDefinition; - _parentIndex = -1; - }*/ - - #endregion Constructors - - //------------------------------------------------------ - // - // Public Properties - // - //------------------------------------------------------ - - #region Public Properties - /// /// SharedSizeGroup property. /// public string SharedSizeGroup { - get { return (string) GetValue(SharedSizeGroupProperty); } + get { return (string)GetValue(SharedSizeGroupProperty); } set { SetValue(SharedSizeGroupProperty, value); } } - #endregion Public Properties - - //------------------------------------------------------ - // - // Internal Methods - // - //------------------------------------------------------ - - #region Internal Methods - /// /// Callback to notify about entering model tree. /// @@ -91,7 +57,7 @@ namespace Avalonia.Controls if (e.Property.PropertyType == typeof(GridLength) || e.Property.PropertyType == typeof(double)) OnUserSizePropertyChanged(e); - + base.OnPropertyChanged(e); } @@ -139,9 +105,6 @@ namespace Avalonia.Controls _minSize = minSize; } - /// - /// - /// /// /// This method needs to be internal to be accessable from derived classes. /// @@ -166,92 +129,29 @@ namespace Avalonia.Controls } } } - /// - /// - /// - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal static bool IsUserSizePropertyValueValid(object value) - { - return (((GridLength)value).Value >= 0); - } - /// - /// - /// /// /// This method needs to be internal to be accessable from derived classes. /// internal static void OnUserMinSizePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) { - DefinitionBase definition = (DefinitionBase) d; - - if (definition.InParentLogicalTree) - { - Grid parentGrid = (Grid) definition.Parent; - parentGrid.InvalidateMeasure(); - } - } - - /// - /// - /// - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal static bool IsUserMinSizePropertyValueValid(object value) - { - double v = (double)value; - return (!double.IsNaN(v) && v >= 0.0d && !Double.IsPositiveInfinity(v)); - } - - /// - /// - /// - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal static void OnUserMaxSizePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) - { - DefinitionBase definition = (DefinitionBase) d; + DefinitionBase definition = (DefinitionBase)d; if (definition.InParentLogicalTree) { - Grid parentGrid = (Grid) definition.Parent; + Grid parentGrid = (Grid)definition.Parent; parentGrid.InvalidateMeasure(); } } - /// - /// - /// - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal static bool IsUserMaxSizePropertyValueValid(object value) - { - double v = (double)value; - return (!double.IsNaN(v) && v >= 0.0d); - } - - /// - /// - /// /// /// This method reflects Grid.SharedScopeProperty state by setting / clearing /// dynamic property PrivateSharedSizeScopeProperty. Value of PrivateSharedSizeScopeProperty /// is a collection of SharedSizeState objects for the scope. - /// Also PrivateSharedSizeScopeProperty is FrameworkPropertyMetadataOptions.Inherits property. So that all children - /// elements belonging to a certain scope can easily access SharedSizeState collection. As well - /// as been norified about enter / exit a scope. /// internal static void OnIsSharedSizeScopePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) { - // is it possible to optimize here something like this: - // if ((bool)d.GetValue(Grid.IsSharedSizeScopeProperty) == (d.GetLocalValue(PrivateSharedSizeScopeProperty) != null) - // { /* do nothing */ } - if ((bool) e.NewValue) + if ((bool)e.NewValue) { SharedSizeScope sharedStatesCollection = new SharedSizeScope(); d.SetValue(PrivateSharedSizeScopeProperty, sharedStatesCollection); @@ -262,16 +162,6 @@ namespace Avalonia.Controls } } - #endregion Internal Methods - - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - - #region Internal Properties - /// /// Returns true if this definition is a part of shared group. /// @@ -349,8 +239,8 @@ namespace Avalonia.Controls get { double preferredSize = MinSize; - if ( _sizeType != Grid.LayoutTimeSizeType.Auto - && preferredSize < _measureSize ) + if (_sizeType != Grid.LayoutTimeSizeType.Auto + && preferredSize < _measureSize) { preferredSize = _measureSize; } @@ -375,9 +265,9 @@ namespace Avalonia.Controls get { double minSize = _minSize; - if ( UseSharedMinimum - && _sharedState != null - && minSize < _sharedState.MinSize ) + if (UseSharedMinimum + && _sharedState != null + && minSize < _sharedState.MinSize) { minSize = _sharedState.MinSize; } @@ -393,9 +283,9 @@ namespace Avalonia.Controls get { double minSize = _minSize; - if ( _sharedState != null - && (UseSharedMinimum || !LayoutWasUpdated) - && minSize < _sharedState.MinSize ) + if (_sharedState != null + && (UseSharedMinimum || !LayoutWasUpdated) + && minSize < _sharedState.MinSize) { minSize = _sharedState.MinSize; } @@ -426,7 +316,7 @@ namespace Avalonia.Controls /// Internal helper to access up-to-date UserMaxSize property value. /// internal abstract double UserMaxSizeValueCache { get; } - + /// /// Protected. Returns true if this DefinitionBase instance is in parent's logical tree. /// @@ -437,16 +327,6 @@ namespace Avalonia.Controls internal Grid Parent { get; set; } - #endregion Internal Properties - - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - - #region Private Methods - /// /// SetFlags is used to set or unset one or multiple /// flags on the object. @@ -465,16 +345,13 @@ namespace Avalonia.Controls return ((_flags & flags) == flags); } - /// - /// - /// private static void OnSharedSizeGroupPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) { - DefinitionBase definition = (DefinitionBase) d; - + DefinitionBase definition = (DefinitionBase)d; + if (definition.InParentLogicalTree) { - string sharedSizeGroupId = (string) e.NewValue; + string sharedSizeGroupId = (string)e.NewValue; if (definition._sharedState != null) { @@ -483,7 +360,7 @@ namespace Avalonia.Controls definition._sharedState.RemoveMember(definition); definition._sharedState = null; } - + if ((definition._sharedState == null) && (sharedSizeGroupId != null)) { SharedSizeScope privateSharedSizeScope = definition.PrivateSharedSizeScope; @@ -498,9 +375,6 @@ namespace Avalonia.Controls } } - /// - /// - /// /// /// Verifies that Shared Size Group Property string /// a) not empty. @@ -520,10 +394,10 @@ namespace Avalonia.Controls { bool isDigit = Char.IsDigit(id[i]); - if ( (i == 0 && isDigit) - || !( isDigit - || Char.IsLetter(id[i]) - || '_' == id[i] ) ) + if ((i == 0 && isDigit) + || !(isDigit + || Char.IsLetter(id[i]) + || '_' == id[i])) { break; } @@ -535,12 +409,9 @@ namespace Avalonia.Controls } } - throw new ArgumentException("Invalid SharedSizeGroup string."); + throw new ArgumentException("Invalid SharedSizeGroup string."); } - /// - /// - /// /// /// OnPrivateSharedSizeScopePropertyChanged is called when new scope enters or /// existing scope just left. In both cases if the DefinitionBase object is already registered @@ -552,7 +423,7 @@ namespace Avalonia.Controls if (definition.InParentLogicalTree) { - SharedSizeScope privateSharedSizeScope = (SharedSizeScope) e.NewValue; + SharedSizeScope privateSharedSizeScope = (SharedSizeScope)e.NewValue; if (definition._sharedState != null) { @@ -576,22 +447,12 @@ namespace Avalonia.Controls } } - #endregion Private Methods - - //------------------------------------------------------ - // - // Private Properties - // - //------------------------------------------------------ - - #region Private Properties - /// /// Private getter of shared state collection dynamic property. /// private SharedSizeScope PrivateSharedSizeScope { - get { return (SharedSizeScope) GetValue(PrivateSharedSizeScopeProperty); } + get { return (SharedSizeScope)GetValue(PrivateSharedSizeScopeProperty); } } /// @@ -612,16 +473,6 @@ namespace Avalonia.Controls set { SetFlags(value, Flags.LayoutWasUpdated); } } - #endregion Private Properties - - //------------------------------------------------------ - // - // Private Fields - // - //------------------------------------------------------ - - #region Private Fields - private readonly bool _isColumnDefinition; // when "true", this is a ColumnDefinition; when "false" this is a RowDefinition (faster than a type check) private Flags _flags; // flags reflecting various aspects of internal state internal int _parentIndex = -1; // this instance's index in parent's children collection @@ -633,19 +484,6 @@ namespace Avalonia.Controls private double _offset; // offset of the DefinitionBase from left / top corner (assuming LTR case) private SharedSizeState _sharedState; // reference to shared state object this instance is registered with - - internal const bool ThisIsColumnDefinition = true; - internal const bool ThisIsRowDefinition = false; - - #endregion Private Fields - - //------------------------------------------------------ - // - // Private Structures / Classes - // - //------------------------------------------------------ - - #region Private Structures Classes [System.Flags] private enum Flags : byte @@ -653,8 +491,8 @@ namespace Avalonia.Controls // // bool flags // - UseSharedMinimum = 0x00000020, // when "1", definition will take into account shared state's minimum - LayoutWasUpdated = 0x00000040, // set to "1" every time the parent grid is measured + UseSharedMinimum = 0x00000020, // when "1", definition will take into account shared state's minimum + LayoutWasUpdated = 0x00000040, // set to "1" every time the parent grid is measured } /// @@ -799,8 +637,8 @@ namespace Avalonia.Controls for (int i = 0, count = _registry.Count; i < count; ++i) { - Debug.Assert( _userSize.GridUnitType == GridUnitType.Auto - || _userSize.GridUnitType == GridUnitType.Pixel ); + Debug.Assert(_userSize.GridUnitType == GridUnitType.Auto + || _userSize.GridUnitType == GridUnitType.Pixel); GridLength currentGridLength = _registry[i].UserSizeValueCache; if (currentGridLength.GridUnitType == GridUnitType.Pixel) @@ -845,7 +683,7 @@ namespace Avalonia.Controls { DefinitionBase definitionBase = _registry[i]; - if (sharedMinSizeChanged || definitionBase.LayoutWasUpdated) + if (sharedMinSizeChanged || definitionBase.LayoutWasUpdated) { // if definition's min size is different, then need to re-measure if (!MathUtilities.AreClose(sharedMinSize, definitionBase.MinSize)) @@ -857,7 +695,7 @@ namespace Avalonia.Controls else { definitionBase.UseSharedMinimum = false; - + // if measure is valid then also need to check arrange. // Note: definitionBase.SizeCache is volatile but at this point // it contains up-to-date final size @@ -879,27 +717,34 @@ namespace Avalonia.Controls _broadcastInvalidation = true; } - - private readonly SharedSizeScope _sharedSizeScope; // the scope this state belongs to - private readonly string _sharedSizeGroupId; // Id of the shared size group this object is servicing - private readonly List _registry; // registry of participating definitions - private readonly EventHandler _layoutUpdated; // instance event handler for layout updated event - private Control _layoutUpdatedHost; // Control for which layout updated event handler is registered - private bool _broadcastInvalidation; // "true" when broadcasting of invalidation is needed - private bool _userSizeValid; // "true" when _userSize is up to date - private GridLength _userSize; // shared state - private double _minSize; // shared state - } - #endregion Private Structures Classes + // the scope this state belongs to + private readonly SharedSizeScope _sharedSizeScope; + + // Id of the shared size group this object is servicing + private readonly string _sharedSizeGroupId; + + // Registry of participating definitions + private readonly List _registry; + + // Instance event handler for layout updated event + private readonly EventHandler _layoutUpdated; - //------------------------------------------------------ - // - // Properties - // - //------------------------------------------------------ + // Control for which layout updated event handler is registered + private Control _layoutUpdatedHost; - #region Properties + // "true" when broadcasting of invalidation is needed + private bool _broadcastInvalidation; + + // "true" when _userSize is up to date + private bool _userSizeValid; + + // shared state + private GridLength _userSize; + + // shared state + private double _minSize; + } /// /// Private shared size scope property holds a collection of shared state objects for the a given shared size scope. @@ -931,7 +776,7 @@ namespace Avalonia.Controls public static readonly AttachedProperty SharedSizeGroupProperty = AvaloniaProperty.RegisterAttached( "SharedSizeGroup", - validate:SharedSizeGroupPropertyValueValid); + validate: SharedSizeGroupPropertyValueValid); /// /// Static ctor. Used for static registration of properties. @@ -941,7 +786,5 @@ namespace Avalonia.Controls SharedSizeGroupProperty.Changed.AddClassHandler(OnSharedSizeGroupPropertyChanged); PrivateSharedSizeScopeProperty.Changed.AddClassHandler(OnPrivateSharedSizeScopePropertyChanged); } - - #endregion Properties } -} +} \ No newline at end of file diff --git a/src/Avalonia.Controls/DefinitionList.cs b/src/Avalonia.Controls/DefinitionList.cs index b36ca9ce8a..97d92bdcb7 100644 --- a/src/Avalonia.Controls/DefinitionList.cs +++ b/src/Avalonia.Controls/DefinitionList.cs @@ -10,6 +10,12 @@ namespace Avalonia.Controls { public abstract class DefinitionList : AvaloniaList where T : DefinitionBase { + public DefinitionList() + { + ResetBehavior = ResetBehavior.Remove; + CollectionChanged += OnCollectionChanged; + } + internal bool IsDirty = true; private Grid _parent; @@ -19,7 +25,6 @@ namespace Avalonia.Controls set => SetParent(value); } - private void SetParent(Grid value) { _parent = value; diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs index fc61c409f0..5a44b93941 100644 --- a/src/Avalonia.Controls/Grid.cs +++ b/src/Avalonia.Controls/Grid.cs @@ -22,12 +22,6 @@ namespace Avalonia.Controls /// public class Grid : Panel { - //------------------------------------------------------ - // - // Constructors - // - //------------------------------------------------------ - static Grid() { IsSharedSizeScopeProperty.Changed.AddClassHandler(DefinitionBase.OnIsSharedSizeScopePropertyChanged); @@ -47,42 +41,6 @@ namespace Avalonia.Controls { } - //------------------------------------------------------ - // - // Public Methods - // - //------------------------------------------------------ - - - /// - /// - /// - /* protected internal override IEnumerator LogicalChildren - { - get - { - // empty panel or a panel being used as the items - // host has *no* logical children; give empty enumerator - bool noChildren = (base.VisualChildrenCount == 0) || IsItemsHost; - - if (noChildren) - { - ExtendedData extData = ExtData; - - if ( extData == null - || ( (extData.ColumnDefinitions == null || extData.ColumnDefinitions.Count == 0) - && (extData.RowDefinitions == null || extData.RowDefinitions.Count == 0) ) - ) - { - // grid is empty - return EmptyEnumerator.Instance; - } - } - - return (new GridChildrenCollectionEnumeratorSimple(this, !noChildren)); - } - } */ - /// /// Helper for setting Column property on a Control. /// @@ -193,12 +151,6 @@ namespace Avalonia.Controls return element.GetValue(IsSharedSizeScopeProperty); } - //------------------------------------------------------ - // - // Public Properties - // - //------------------------------------------------------ - /// /// ShowGridLines property. /// @@ -248,52 +200,6 @@ namespace Avalonia.Controls } } - //------------------------------------------------------ - // - // Protected Methods - // - //------------------------------------------------------ - - /* /// - /// Derived class must implement to support Visual children. The method must return - /// the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. - /// - /// By default a Visual does not have any children. - /// - /// Remark: - /// During this virtual call it is not valid to modify the Visual tree. - /// - protected override Visual GetVisualChild(int index) - { - // because "base.Count + 1" for GridLinesRenderer - // argument checking done at the base class - if(index == base.VisualChildrenCount) - { - if (_gridLinesRenderer == null) - { - throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); - } - return _gridLinesRenderer; - } - else return base.GetVisualChild(index); - } - - /// - /// Derived classes override this property to enable the Visual code to enumerate - /// the Visual children. Derived classes need to return the number of children - /// from this method. - /// - /// By default a Visual does not have any children. - /// - /// Remark: During this virtual method the Visual tree must not be modified. - /// - protected override int VisualChildrenCount - { - //since GridLinesRenderer has not been added as a child, so we do not subtract - get { return base.VisualChildrenCount + (_gridLinesRenderer != null ? 1 : 0); } - }*/ - - /// /// Content measurement. /// @@ -306,8 +212,6 @@ namespace Avalonia.Controls try { - - ListenToNotifications = true; MeasureOverrideInProgress = true; @@ -550,7 +454,7 @@ namespace Avalonia.Controls // also use a count heuristic to break a loop in case of one. bool hasDesiredSizeUChanged = false; - int cnt=0; + int cnt = 0; // Cache Group2MinWidths & Group3MinHeights double[] group2MinSizes = CacheMinSizes(extData.CellGroup2, false); @@ -582,17 +486,14 @@ namespace Avalonia.Controls MeasureCellsGroup(extData.CellGroup4, constraint, false, false); - gridDesiredSize = new Size( CalculateDesiredSize(DefinitionsU), CalculateDesiredSize(DefinitionsV)); - } } finally { MeasureOverrideInProgress = false; - } return (gridDesiredSize); @@ -606,8 +507,6 @@ namespace Avalonia.Controls { try { - - ArrangeOverrideInProgress = true; if (_data == null) @@ -627,13 +526,9 @@ namespace Avalonia.Controls { Debug.Assert(DefinitionsU.Count > 0 && DefinitionsV.Count > 0); - - SetFinalSize(DefinitionsU, arrangeSize.Width, true); SetFinalSize(DefinitionsV, arrangeSize.Height, false); - - var children = this.Children; for (int currentCell = 0; currentCell < PrivateCells.Length; ++currentCell) @@ -653,11 +548,11 @@ namespace Avalonia.Controls columnIndex == 0 ? 0.0 : DefinitionsU[columnIndex].FinalOffset, rowIndex == 0 ? 0.0 : DefinitionsV[rowIndex].FinalOffset, GetFinalSizeForRange(DefinitionsU, columnIndex, columnSpan), - GetFinalSizeForRange(DefinitionsV, rowIndex, rowSpan) ); + GetFinalSizeForRange(DefinitionsV, rowIndex, rowSpan)); + - cell.Arrange(cellRect); - + } // update render bound on grid lines renderer visual @@ -669,31 +564,12 @@ namespace Avalonia.Controls { SetValid(); ArrangeOverrideInProgress = false; - } return (arrangeSize); } /// - /// - /// - /*protected internal override void OnVisualChildrenChanged( - AvaloniaObject visualAdded, - AvaloniaObject visualRemoved) - { - CellsStructureDirty = true; - - base.OnVisualChildrenChanged(visualAdded, visualRemoved); - }*/ - - //------------------------------------------------------ - // - // Internal Methods - // - //------------------------------------------------------ - - /// - /// Invalidates grid caches and makes the grid dirty for measure. + /// Invalidates grid caches and makes the grid dirty for measure. /// internal void Invalidate() { @@ -702,10 +578,10 @@ namespace Avalonia.Controls } /// - /// Returns final width for a column. + /// Returns final width for a column. /// /// - /// Used from public ColumnDefinition ActualWidth. Calculates final width using offset data. + /// Used from public ColumnDefinition ActualWidth. Calculates final width using offset data. /// internal double GetFinalColumnDefinitionWidth(int columnIndex) { @@ -724,10 +600,10 @@ namespace Avalonia.Controls } /// - /// Returns final height for a row. + /// Returns final height for a row. /// /// - /// Used from public RowDefinition ActualHeight. Calculates final height using offset data. + /// Used from public RowDefinition ActualHeight. Calculates final height using offset data. /// internal double GetFinalRowDefinitionHeight(int rowIndex) { @@ -745,12 +621,6 @@ namespace Avalonia.Controls return (value); } - //------------------------------------------------------ - // - // Internal Properties - // - //------------------------------------------------------ - /// /// Convenience accessor to MeasureOverrideInProgress bit flag. /// @@ -781,32 +651,22 @@ namespace Avalonia.Controls /// /// Convenience accessor to ValidDefinitionsVStructure bit flag. /// - internal bool RowDefinitionsDirty + internal bool RowDefinitionsDirty { get => RowDefinitions?.IsDirty ?? false; set => RowDefinitions.IsDirty = value; } - //------------------------------------------------------ - // - // Private Methods - // - //------------------------------------------------------ - /// /// Lays out cells according to rows and columns, and creates lookup grids. /// private void ValidateCells() { - - if (CellsStructureDirty) { ValidateCellsCore(); CellsStructureDirty = false; } - - } /// @@ -837,11 +697,8 @@ namespace Avalonia.Controls CellCache cell = new CellCache(); - // - // read and cache child positioning properties - // - // read indices from the corresponding properties + // Read indices from the corresponding properties: // clamp to value < number_of_columns // column >= 0 is guaranteed by property value validation callback cell.ColumnIndex = Math.Min(GetColumn((Control)child), DefinitionsU.Count - 1); @@ -849,7 +706,7 @@ namespace Avalonia.Controls // row >= 0 is guaranteed by property value validation callback cell.RowIndex = Math.Min(GetRow((Control)child), DefinitionsV.Count - 1); - // read span properties + // Read span properties: // clamp to not exceed beyond right side of the grid // column_span > 0 is guaranteed by property value validation callback cell.ColumnSpan = Math.Min(GetColumnSpan((Control)child), DefinitionsU.Count - cell.ColumnIndex); @@ -861,9 +718,7 @@ namespace Avalonia.Controls Debug.Assert(0 <= cell.ColumnIndex && cell.ColumnIndex < DefinitionsU.Count); Debug.Assert(0 <= cell.RowIndex && cell.RowIndex < DefinitionsV.Count); - // - // calculate and cache length types for the child - // + // Calculate and cache length types for the child. cell.SizeTypeU = GetLengthTypeForRange(DefinitionsU, cell.ColumnIndex, cell.ColumnSpan); cell.SizeTypeV = GetLengthTypeForRange(DefinitionsV, cell.RowIndex, cell.RowSpan); @@ -871,9 +726,7 @@ namespace Avalonia.Controls hasStarCellsU |= cell.IsStarU; hasStarCellsV |= cell.IsStarV; - // - // distribute cells into four groups. - // + // Distribute cells into four groups. if (!cell.IsStarV) { @@ -887,15 +740,15 @@ namespace Avalonia.Controls cell.Next = extData.CellGroup3; extData.CellGroup3 = i; - // remember if this cell belongs to auto row + // Remember if this cell belongs to auto row hasGroup3CellsInAutoRows |= cell.IsAutoV; } } else { - if ( cell.IsAutoU - // note below: if spans through Star column it is NOT Auto - && !cell.IsStarU ) + if (cell.IsAutoU + // Note below: if spans through Star column it is NOT Auto + && !cell.IsStarU) { cell.Next = extData.CellGroup2; extData.CellGroup2 = i; @@ -986,7 +839,7 @@ namespace Avalonia.Controls extData.DefinitionsV = new DefinitionBase[] { new RowDefinition() { Parent = this } }; } else - { + { extData.DefinitionsV = extData.RowDefinitions; } } @@ -1053,7 +906,7 @@ namespace Avalonia.Controls { double[] minSizes = isRows ? new double[DefinitionsV.Count] : new double[DefinitionsU.Count]; - for (int j=0; j (double)o ) + if (o == null + || value > (double)o) { store[key] = value; } @@ -1235,13 +1088,13 @@ namespace Avalonia.Controls int cell, bool forceInfinityV) { - + double cellMeasureWidth; double cellMeasureHeight; - if ( PrivateCells[cell].IsAutoU - && !PrivateCells[cell].IsStarU ) + if (PrivateCells[cell].IsAutoU + && !PrivateCells[cell].IsStarU) { // if cell belongs to at least one Auto column and not a single Star column // then it should be calculated "to content", thus it is possible to "shortcut" @@ -1261,8 +1114,8 @@ namespace Avalonia.Controls { cellMeasureHeight = double.PositiveInfinity; } - else if ( PrivateCells[cell].IsAutoV - && !PrivateCells[cell].IsStarV ) + else if (PrivateCells[cell].IsAutoV + && !PrivateCells[cell].IsStarV) { // if cell belongs to at least one Auto row and not a single Star row // then it should be calculated "to content", thus it is possible to "shortcut" @@ -1277,19 +1130,18 @@ namespace Avalonia.Controls PrivateCells[cell].RowSpan); } - + var child = this.Children[cell]; if (child != null) { Size childConstraint = new Size(cellMeasureWidth, cellMeasureHeight); child.Measure(childConstraint); } - - - } + } + /// /// Calculates one dimensional measure size for given definitions' range. /// @@ -1393,12 +1245,12 @@ namespace Avalonia.Controls // sanity check: no matter what, but min size must always be the smaller; // max size must be the biggest; and preferred should be in between - Debug.Assert( minSize <= preferredSize - && preferredSize <= maxSize - && rangeMinSize <= rangePreferredSize - && rangePreferredSize <= rangeMaxSize ); + Debug.Assert(minSize <= preferredSize + && preferredSize <= maxSize + && rangeMinSize <= rangePreferredSize + && rangePreferredSize <= rangeMaxSize); - if (maxMaxSize < maxSize) maxMaxSize = maxSize; + if (maxMaxSize < maxSize) maxMaxSize = maxSize; if (definitions[i].UserSize.IsAuto) autoDefinitionsCount++; tempDefinitions[i - start] = definitions[i]; } @@ -1492,8 +1344,8 @@ namespace Avalonia.Controls // double equalSize = requestedSize / count; - if ( equalSize < maxMaxSize - && !_AreClose(equalSize, maxMaxSize) ) + if (equalSize < maxMaxSize + && !_AreClose(equalSize, maxMaxSize)) { // equi-size is less than maximum of maxSizes. // in this case distribute so that smaller definitions grow faster than @@ -1502,12 +1354,12 @@ namespace Avalonia.Controls double sizeToDistribute = requestedSize - rangeMaxSize; // sanity check: totalRemainingSize and sizeToDistribute must be real positive numbers - Debug.Assert( !double.IsInfinity(totalRemainingSize) - && !double.IsNaN(totalRemainingSize) - && totalRemainingSize > 0 - && !double.IsInfinity(sizeToDistribute) - && !double.IsNaN(sizeToDistribute) - && sizeToDistribute > 0 ); + Debug.Assert(!double.IsInfinity(totalRemainingSize) + && !double.IsNaN(totalRemainingSize) + && totalRemainingSize > 0 + && !double.IsInfinity(sizeToDistribute) + && !double.IsNaN(sizeToDistribute) + && sizeToDistribute > 0); for (int i = 0; i < count; ++i) { @@ -1543,105 +1395,10 @@ namespace Avalonia.Controls IReadOnlyList definitions, double availableSize) { - // if (FrameworkAppContextSwitches.GridStarDefinitionsCanExceedAvailableSpace) - // { - // ResolveStarLegacy(definitions, availableSize); - // } - // else - // { - ResolveStarMaxDiscrepancy(definitions, availableSize); - // } + ResolveStarMaxDiscrepancy(definitions, availableSize); } - // original implementation, used from 3.0 through 4.6.2 - private void ResolveStarLegacy( - IReadOnlyList definitions, - double availableSize) - { - DefinitionBase[] tempDefinitions = TempDefinitions; - int starDefinitionsCount = 0; - double takenSize = 0; - - for (int i = 0; i < definitions.Count; ++i) - { - switch (definitions[i].SizeType) - { - case (LayoutTimeSizeType.Auto): - takenSize += definitions[i].MinSize; - break; - case (LayoutTimeSizeType.Pixel): - takenSize += definitions[i].MeasureSize; - break; - case (LayoutTimeSizeType.Star): - { - tempDefinitions[starDefinitionsCount++] = definitions[i]; - - double starValue = definitions[i].UserSize.Value; - - if (_IsZero(starValue)) - { - definitions[i].MeasureSize = 0; - definitions[i].SizeCache = 0; - } - else - { - // clipping by c_starClip guarantees that sum of even a very big number of max'ed out star values - // can be summed up without overflow - starValue = Math.Min(starValue, c_starClip); - - // Note: normalized star value is temporary cached into MeasureSize - definitions[i].MeasureSize = starValue; - double maxSize = Math.Max(definitions[i].MinSize, definitions[i].UserMaxSize); - maxSize = Math.Min(maxSize, c_starClip); - definitions[i].SizeCache = maxSize / starValue; - } - } - break; - } - } - - if (starDefinitionsCount > 0) - { - Array.Sort(tempDefinitions, 0, starDefinitionsCount, s_starDistributionOrderComparer); - - // the 'do {} while' loop below calculates sum of star weights in order to avoid fp overflow... - // partial sum value is stored in each definition's SizeCache member. - // this way the algorithm guarantees (starValue <= definition.SizeCache) and thus - // (starValue / definition.SizeCache) will never overflow due to sum of star weights becoming zero. - // this is an important change from previous implementation where the following was possible: - // ((BigValueStar + SmallValueStar) - BigValueStar) resulting in 0... - double allStarWeights = 0; - int i = starDefinitionsCount - 1; - do - { - allStarWeights += tempDefinitions[i].MeasureSize; - tempDefinitions[i].SizeCache = allStarWeights; - } while (--i >= 0); - - i = 0; - do - { - double resolvedSize; - double starValue = tempDefinitions[i].MeasureSize; - - if (_IsZero(starValue)) - { - resolvedSize = tempDefinitions[i].MinSize; - } - else - { - double userSize = Math.Max(availableSize - takenSize, 0.0) * (starValue / tempDefinitions[i].SizeCache); - resolvedSize = Math.Min(userSize, tempDefinitions[i].UserMaxSize); - resolvedSize = Math.Max(tempDefinitions[i].MinSize, resolvedSize); - } - - tempDefinitions[i].MeasureSize = resolvedSize; - takenSize += resolvedSize; - } while (++i < starDefinitionsCount); - } - } - - // new implementation as of 4.7. Several improvements: + // New implementation as of 4.7. Several improvements: // 1. Allocate to *-defs hitting their min or max constraints, before allocating // to other *-defs. A def that hits its min uses more space than its // proportional share, reducing the space available to everyone else. @@ -1668,7 +1425,7 @@ namespace Avalonia.Controls // Phase 1. Determine the maximum *-weight and prepare to adjust *-weights double maxStar = 0.0; - for (int i=0; i definitions, - double finalSize, - bool columns) - { - int starDefinitionsCount = 0; // traverses form the first entry up - int nonStarIndex = definitions.Count; // traverses from the last entry down - double allPreferredArrangeSize = 0; - bool useLayoutRounding = this.UseLayoutRounding; - int[] definitionIndices = DefinitionIndices; - double[] roundingErrors = null; - - // If using layout rounding, check whether rounding needs to compensate for high DPI - double dpi = 1.0; - - if (useLayoutRounding) - { - // DpiScale dpiScale = GetDpi(); - // dpi = columns ? dpiScale.DpiScaleX : dpiScale.DpiScaleY; - dpi = (VisualRoot as Layout.ILayoutRoot)?.LayoutScaling ?? 1.0; - roundingErrors = RoundingErrors; - } - - for (int i = 0; i < definitions.Count; ++i) - { - // if definition is shared then is cannot be star - Debug.Assert(!definitions[i].IsShared || !definitions[i].UserSize.IsStar); - - if (definitions[i].UserSize.IsStar) - { - double starValue = definitions[i].UserSize.Value; - - if (_IsZero(starValue)) - { - // cach normilized star value temporary into MeasureSize - definitions[i].MeasureSize = 0; - definitions[i].SizeCache = 0; - } - else - { - // clipping by c_starClip guarantees that sum of even a very big number of max'ed out star values - // can be summed up without overflow - starValue = Math.Min(starValue, c_starClip); - - // Note: normalized star value is temporary cached into MeasureSize - definitions[i].MeasureSize = starValue; - double maxSize = Math.Max(definitions[i].MinSizeForArrange, definitions[i].UserMaxSize); - maxSize = Math.Min(maxSize, c_starClip); - definitions[i].SizeCache = maxSize / starValue; - if (useLayoutRounding) - { - roundingErrors[i] = definitions[i].SizeCache; - definitions[i].SizeCache = MathUtilities.RoundLayoutValue(definitions[i].SizeCache, dpi); - } - } - definitionIndices[starDefinitionsCount++] = i; - } - else - { - double userSize = 0; - - switch (definitions[i].UserSize.GridUnitType) - { - case (GridUnitType.Pixel): - userSize = definitions[i].UserSize.Value; - break; - - case (GridUnitType.Auto): - userSize = definitions[i].MinSizeForArrange; - break; - } - - double userMaxSize; - - if (definitions[i].IsShared) - { - // overriding userMaxSize effectively prevents squishy-ness. - // this is a "solution" to avoid shared definitions from been sized to - // different final size at arrange time, if / when different grids receive - // different final sizes. - userMaxSize = userSize; - } - else - { - userMaxSize = definitions[i].UserMaxSize; - } - - definitions[i].SizeCache = Math.Max(definitions[i].MinSizeForArrange, Math.Min(userSize, userMaxSize)); - if (useLayoutRounding) - { - roundingErrors[i] = definitions[i].SizeCache; - definitions[i].SizeCache = MathUtilities.RoundLayoutValue(definitions[i].SizeCache, dpi); - } - - allPreferredArrangeSize += definitions[i].SizeCache; - definitionIndices[--nonStarIndex] = i; - } - } - - // indices should meet - Debug.Assert(nonStarIndex == starDefinitionsCount); - - if (starDefinitionsCount > 0) - { - StarDistributionOrderIndexComparer starDistributionOrderIndexComparer = new StarDistributionOrderIndexComparer(definitions); - Array.Sort(definitionIndices, 0, starDefinitionsCount, starDistributionOrderIndexComparer); - - // the 'do {} while' loop below calculates sum of star weights in order to avoid fp overflow... - // partial sum value is stored in each definition's SizeCache member. - // this way the algorithm guarantees (starValue <= definition.SizeCache) and thus - // (starValue / definition.SizeCache) will never overflow due to sum of star weights becoming zero. - // this is an important change from previous implementation where the following was possible: - // ((BigValueStar + SmallValueStar) - BigValueStar) resulting in 0... - double allStarWeights = 0; - int i = starDefinitionsCount - 1; - do - { - allStarWeights += definitions[definitionIndices[i]].MeasureSize; - definitions[definitionIndices[i]].SizeCache = allStarWeights; - } while (--i >= 0); - - i = 0; - do - { - double resolvedSize; - double starValue = definitions[definitionIndices[i]].MeasureSize; - - if (_IsZero(starValue)) - { - resolvedSize = definitions[definitionIndices[i]].MinSizeForArrange; - } - else - { - double userSize = Math.Max(finalSize - allPreferredArrangeSize, 0.0) * (starValue / definitions[definitionIndices[i]].SizeCache); - resolvedSize = Math.Min(userSize, definitions[definitionIndices[i]].UserMaxSize); - resolvedSize = Math.Max(definitions[definitionIndices[i]].MinSizeForArrange, resolvedSize); - } - - definitions[definitionIndices[i]].SizeCache = resolvedSize; - if (useLayoutRounding) - { - roundingErrors[definitionIndices[i]] = definitions[definitionIndices[i]].SizeCache; - definitions[definitionIndices[i]].SizeCache = MathUtilities.RoundLayoutValue(definitions[definitionIndices[i]].SizeCache, dpi); - } - - allPreferredArrangeSize += definitions[definitionIndices[i]].SizeCache; - } while (++i < starDefinitionsCount); - } - - if ( allPreferredArrangeSize > finalSize - && !_AreClose(allPreferredArrangeSize, finalSize) ) - { - DistributionOrderIndexComparer distributionOrderIndexComparer = new DistributionOrderIndexComparer(definitions); - Array.Sort(definitionIndices, 0, definitions.Count, distributionOrderIndexComparer); - double sizeToDistribute = finalSize - allPreferredArrangeSize; - - for (int i = 0; i < definitions.Count; ++i) - { - int definitionIndex = definitionIndices[i]; - double final = definitions[definitionIndex].SizeCache + (sizeToDistribute / (definitions.Count - i)); - double finalOld = final; - final = Math.Max(final, definitions[definitionIndex].MinSizeForArrange); - final = Math.Min(final, definitions[definitionIndex].SizeCache); - - if (useLayoutRounding) - { - roundingErrors[definitionIndex] = final; - final = MathUtilities.RoundLayoutValue(finalOld, dpi); - final = Math.Max(final, definitions[definitionIndex].MinSizeForArrange); - final = Math.Min(final, definitions[definitionIndex].SizeCache); - } - - sizeToDistribute -= (final - definitions[definitionIndex].SizeCache); - definitions[definitionIndex].SizeCache = final; - } - - allPreferredArrangeSize = finalSize - sizeToDistribute; - } - - if (useLayoutRounding) - { - if (!_AreClose(allPreferredArrangeSize, finalSize)) - { - // Compute deltas - for (int i = 0; i < definitions.Count; ++i) - { - roundingErrors[i] = roundingErrors[i] - definitions[i].SizeCache; - definitionIndices[i] = i; - } - - // Sort rounding errors - RoundingErrorIndexComparer roundingErrorIndexComparer = new RoundingErrorIndexComparer(roundingErrors); - Array.Sort(definitionIndices, 0, definitions.Count, roundingErrorIndexComparer); - double adjustedSize = allPreferredArrangeSize; - double dpiIncrement = MathUtilities.RoundLayoutValue(1.0, dpi); - - if (allPreferredArrangeSize > finalSize) - { - int i = definitions.Count - 1; - while ((adjustedSize > finalSize && !_AreClose(adjustedSize, finalSize)) && i >= 0) - { - DefinitionBase definition = definitions[definitionIndices[i]]; - double final = definition.SizeCache - dpiIncrement; - final = Math.Max(final, definition.MinSizeForArrange); - if (final < definition.SizeCache) - { - adjustedSize -= dpiIncrement; - } - definition.SizeCache = final; - i--; - } - } - else if (allPreferredArrangeSize < finalSize) - { - int i = 0; - while ((adjustedSize < finalSize && !_AreClose(adjustedSize, finalSize)) && i < definitions.Count) - { - DefinitionBase definition = definitions[definitionIndices[i]]; - double final = definition.SizeCache + dpiIncrement; - final = Math.Max(final, definition.MinSizeForArrange); - if (final > definition.SizeCache) - { - adjustedSize += dpiIncrement; - } - definition.SizeCache = final; - i++; - } - } - } - } - - definitions[0].FinalOffset = 0.0; - for (int i = 0; i < definitions.Count; ++i) - { - definitions[(i + 1) % definitions.Count].FinalOffset = definitions[i].FinalOffset + definitions[i].SizeCache; - } + SetFinalSizeMaxDiscrepancy(definitions, finalSize, columns); } // new implementation, as of 4.7. This incorporates the same algorithm @@ -2251,7 +1762,7 @@ namespace Avalonia.Controls // Phase 1. Determine the maximum *-weight and prepare to adjust *-weights double maxStar = 0.0; - for (int i=0; i finalSize) { @@ -2694,9 +2204,9 @@ namespace Avalonia.Controls /// if the max constraint has higher discrepancy /// null if proportion doesn't fail a min or max constraint /// The discrepancy is the ratio of the proportion to the max- or min-ratio. - /// When both ratios hit the constraint, minRatio < proportion < maxRatio, + /// When both ratios hit the constraint, minRatio < proportion < maxRatio, /// and the minRatio has higher discrepancy if - /// (proportion / minRatio) > (maxRatio / proportion) + /// (proportion / minRatio) > (maxRatio / proportion) /// private static bool? Choose(double minRatio, double maxRatio, double proportion) { @@ -2782,8 +2292,8 @@ namespace Avalonia.Controls ExtendedData extData = ExtData; if (extData != null) { -// for (int i = 0; i < PrivateColumnCount; ++i) DefinitionsU[i].SetValid (); -// for (int i = 0; i < PrivateRowCount; ++i) DefinitionsV[i].SetValid (); + // for (int i = 0; i < PrivateColumnCount; ++i) DefinitionsU[i].SetValid (); + // for (int i = 0; i < PrivateRowCount; ++i) DefinitionsV[i].SetValid (); if (extData.TempDefinitions != null) { @@ -2800,9 +2310,9 @@ namespace Avalonia.Controls public bool ShouldSerializeColumnDefinitions() { ExtendedData extData = ExtData; - return ( extData != null - && extData.ColumnDefinitions != null - && extData.ColumnDefinitions.Count > 0 ); + return (extData != null + && extData.ColumnDefinitions != null + && extData.ColumnDefinitions.Count > 0); } /// @@ -2811,9 +2321,9 @@ namespace Avalonia.Controls public bool ShouldSerializeRowDefinitions() { ExtendedData extData = ExtData; - return ( extData != null - && extData.RowDefinitions != null - && extData.RowDefinitions.Count > 0 ); + return (extData != null + && extData.RowDefinitions != null + && extData.RowDefinitions.Count > 0); } /// @@ -2872,25 +2382,19 @@ namespace Avalonia.Controls return (flags == 0 || (_flags & flags) != 0); } - /// - /// - /// private static void OnShowGridLinesPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) { Grid grid = (Grid)d; - if ( grid.ExtData != null // trivial grid is 1 by 1. there is no grid lines anyway - && grid.ListenToNotifications) + if (grid.ExtData != null // trivial grid is 1 by 1. there is no grid lines anyway + && grid.ListenToNotifications) { grid.InvalidateVisual(); } - grid.SetFlags((bool) e.NewValue, Flags.ShowGridLinesPropertyValue); + grid.SetFlags((bool)e.NewValue, Flags.ShowGridLinesPropertyValue); } - /// - /// - /// private static void OnCellAttachedPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) { Visual child = d as Visual; @@ -2898,36 +2402,20 @@ namespace Avalonia.Controls if (child != null) { Grid grid = child.GetVisualParent(); - if ( grid != null - && grid.ExtData != null - && grid.ListenToNotifications ) + if (grid != null + && grid.ExtData != null + && grid.ListenToNotifications) { grid.CellsStructureDirty = true; } } } - /* /// - /// - /// - private static bool IsIntValueNotNegative(object value) - { - return ((int)value >= 0); - } - - /// - /// - /// - private static bool IsIntValueGreaterThanZero(object value) - { - return ((int)value > 0); - }*/ - /// /// Helper for Comparer methods. /// /// - /// true iff one or both of x and y are null, in which case result holds + /// true if one or both of x and y are null, in which case result holds /// the relative sort order. /// private static bool CompareNullRefs(object x, object y, out int result) @@ -2956,12 +2444,6 @@ namespace Avalonia.Controls return (result != 2); } - //------------------------------------------------------ - // - // Private Properties - // - //------------------------------------------------------ - /// /// Private version returning array of column definitions. /// @@ -2988,8 +2470,8 @@ namespace Avalonia.Controls ExtendedData extData = ExtData; int requiredLength = Math.Max(DefinitionsU.Count, DefinitionsV.Count) * 2; - if ( extData.TempDefinitions == null - || extData.TempDefinitions.Length < requiredLength ) + if (extData.TempDefinitions == null + || extData.TempDefinitions.Length < requiredLength) { WeakReference tempDefinitionsWeakRef = (WeakReference)Thread.GetData(s_tempDefinitionsDataSlot); if (tempDefinitionsWeakRef == null) @@ -3000,8 +2482,8 @@ namespace Avalonia.Controls else { extData.TempDefinitions = (DefinitionBase[])tempDefinitionsWeakRef.Target; - if ( extData.TempDefinitions == null - || extData.TempDefinitions.Length < requiredLength ) + if (extData.TempDefinitions == null + || extData.TempDefinitions.Length < requiredLength) { extData.TempDefinitions = new DefinitionBase[requiredLength]; tempDefinitionsWeakRef.Target = extData.TempDefinitions; @@ -3129,7 +2611,7 @@ namespace Avalonia.Controls /// true if d == 0. private static bool _IsZero(double d) { - return (Math.Abs(d) < c_epsilon); + return (Math.Abs(d) < double.Epsilon); } /// @@ -3140,7 +2622,7 @@ namespace Avalonia.Controls /// true if d1 == d2 private static bool _AreClose(double d1, double d2) { - return (Math.Abs(d1 - d2) < c_epsilon); + return (Math.Abs(d1 - d2) < double.Epsilon); } /// @@ -3169,13 +2651,11 @@ namespace Avalonia.Controls } } - //------------------------------------------------------ - // - // Private Fields - // - //------------------------------------------------------ - private ExtendedData _data; // extended data instantiated on demand, for non-trivial case handling only - private Flags _flags; // grid validity / property caches dirtiness flags + // Extended data instantiated on demand, for non-trivial case handling only + private ExtendedData _data; + + // Grid validity / property caches dirtiness flags + private Flags _flags; private GridLinesRenderer _gridLinesRenderer; // Keeps track of definition indices. @@ -3184,29 +2664,16 @@ namespace Avalonia.Controls // Stores unrounded values and rounding errors during layout rounding. double[] _roundingErrors; - //------------------------------------------------------ - // - // Static Fields - // - //------------------------------------------------------ - private const double c_epsilon = 1e-5; // used in fp calculations - private const double c_starClip = 1e298; // used as maximum for clipping star values during normalization - private const int c_layoutLoopMaxCount = 5; // 5 is an arbitrary constant chosen to end the measure loop + // 5 is an arbitrary constant chosen to end the measure loop + private const int c_layoutLoopMaxCount = 5; + private static readonly LocalDataStoreSlot s_tempDefinitionsDataSlot = Thread.AllocateDataSlot(); private static readonly IComparer s_spanPreferredDistributionOrderComparer = new SpanPreferredDistributionOrderComparer(); private static readonly IComparer s_spanMaxDistributionOrderComparer = new SpanMaxDistributionOrderComparer(); - private static readonly IComparer s_starDistributionOrderComparer = new StarDistributionOrderComparer(); - private static readonly IComparer s_distributionOrderComparer = new DistributionOrderComparer(); private static readonly IComparer s_minRatioComparer = new MinRatioComparer(); private static readonly IComparer s_maxRatioComparer = new MaxRatioComparer(); private static readonly IComparer s_starWeightComparer = new StarWeightComparer(); - //------------------------------------------------------ - // - // Private Structures / Classes - // - //------------------------------------------------------ - /// /// Extended data instantiated on demand, when grid handles non-trivial case. /// @@ -3237,34 +2704,28 @@ namespace Avalonia.Controls // * Valid???Layout flags indicate that layout time portion of the information // stored on the objects should be updated. // - ValidDefinitionsUStructure = 0x00000001, - ValidDefinitionsVStructure = 0x00000002, - ValidCellsStructure = 0x00000004, + ValidDefinitionsUStructure = 0x00000001, + ValidDefinitionsVStructure = 0x00000002, + ValidCellsStructure = 0x00000004, // // boolean properties state // - ShowGridLinesPropertyValue = 0x00000100, // show grid lines ? + ShowGridLinesPropertyValue = 0x00000100, // show grid lines ? // // boolean flags // - ListenToNotifications = 0x00001000, // "0" when all notifications are ignored - SizeToContentU = 0x00002000, // "1" if calculating to content in U direction - SizeToContentV = 0x00004000, // "1" if calculating to content in V direction - HasStarCellsU = 0x00008000, // "1" if at least one cell belongs to a Star column - HasStarCellsV = 0x00010000, // "1" if at least one cell belongs to a Star row - HasGroup3CellsInAutoRows = 0x00020000, // "1" if at least one cell of group 3 belongs to an Auto row - MeasureOverrideInProgress = 0x00040000, // "1" while in the context of Grid.MeasureOverride - ArrangeOverrideInProgress = 0x00080000, // "1" while in the context of Grid.ArrangeOverride + ListenToNotifications = 0x00001000, // "0" when all notifications are ignored + SizeToContentU = 0x00002000, // "1" if calculating to content in U direction + SizeToContentV = 0x00004000, // "1" if calculating to content in V direction + HasStarCellsU = 0x00008000, // "1" if at least one cell belongs to a Star column + HasStarCellsV = 0x00010000, // "1" if at least one cell belongs to a Star row + HasGroup3CellsInAutoRows = 0x00020000, // "1" if at least one cell of group 3 belongs to an Auto row + MeasureOverrideInProgress = 0x00040000, // "1" while in the context of Grid.MeasureOverride + ArrangeOverrideInProgress = 0x00080000, // "1" while in the context of Grid.ArrangeOverride } - //------------------------------------------------------ - // - // Properties - // - //------------------------------------------------------ - /// /// ShowGridLines property. This property is used mostly /// for simplification of visual debuggig. When it is set @@ -3289,8 +2750,11 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterAttached( "Column", defaultValue: 0, - validate: (_, v) => { if (v >= 0) return v; - else throw new ArgumentException("Invalid Grid.Column value."); }); + validate: (_, v) => + { + if (v >= 0) return v; + else throw new ArgumentException("Invalid Grid.Column value."); + }); /// /// Row property. This is an attached property. @@ -3307,8 +2771,11 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterAttached( "Row", defaultValue: 0, - validate: (_, v) => { if (v >= 0) return v; - else throw new ArgumentException("Invalid Grid.Row value."); }); + validate: (_, v) => + { + if (v >= 0) return v; + else throw new ArgumentException("Invalid Grid.Row value."); + }); /// /// ColumnSpan property. This is an attached property. @@ -3324,8 +2791,11 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterAttached( "ColumnSpan", defaultValue: 1, - validate: (_, v) => { if (v >= 1) return v; - else throw new ArgumentException("Invalid Grid.ColumnSpan value."); }); + validate: (_, v) => + { + if (v >= 1) return v; + else throw new ArgumentException("Invalid Grid.ColumnSpan value."); + }); /// /// RowSpan property. This is an attached property. @@ -3341,8 +2811,11 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterAttached( "RowSpan", defaultValue: 1, - validate: (_, v) => { if (v >= 1) return v; - else throw new ArgumentException("Invalid Grid.RowSpan value."); }); + validate: (_, v) => + { + if (v >= 1) return v; + else throw new ArgumentException("Invalid Grid.RowSpan value."); + }); /// /// IsSharedSizeScope property marks scoping element for shared size. @@ -3351,30 +2824,18 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterAttached( "IsSharedSizeScope"); - //------------------------------------------------------ - // - // Internal Structures / Classes - // - //------------------------------------------------------ - /// /// LayoutTimeSizeType is used internally and reflects layout-time size type. /// [System.Flags] internal enum LayoutTimeSizeType : byte { - None = 0x00, - Pixel = 0x01, - Auto = 0x02, - Star = 0x04, + None = 0x00, + Pixel = 0x01, + Auto = 0x02, + Star = 0x04, } - //------------------------------------------------------ - // - // Private Structures / Classes - // - //------------------------------------------------------ - /// /// CellCache stored calculated values of /// 1. attached cell positioning properties; @@ -3422,7 +2883,7 @@ namespace Avalonia.Controls int hash = (_start ^ (_count << 2)); if (_u) hash &= 0x7ffffff; - else hash |= 0x8000000; + else hash |= 0x8000000; return (hash); } @@ -3433,10 +2894,10 @@ namespace Avalonia.Controls public override bool Equals(object obj) { SpanKey sk = obj as SpanKey; - return ( sk != null - && sk._start == _start - && sk._count == _count - && sk._u == _u ); + return (sk != null + && sk._start == _start + && sk._count == _count + && sk._u == _u); } /// @@ -3544,51 +3005,6 @@ namespace Avalonia.Controls } } - /// - /// StarDistributionOrderComparer. - /// - private class StarDistributionOrderComparer : IComparer - { - public int Compare(object x, object y) - { - DefinitionBase definitionX = x as DefinitionBase; - DefinitionBase definitionY = y as DefinitionBase; - - int result; - - if (!CompareNullRefs(definitionX, definitionY, out result)) - { - result = definitionX.SizeCache.CompareTo(definitionY.SizeCache); - } - - return result; - } - } - - /// - /// DistributionOrderComparer. - /// - private class DistributionOrderComparer: IComparer - { - public int Compare(object x, object y) - { - DefinitionBase definitionX = x as DefinitionBase; - DefinitionBase definitionY = y as DefinitionBase; - - int result; - - if (!CompareNullRefs(definitionX, definitionY, out result)) - { - double xprime = definitionX.SizeCache - definitionX.MinSizeForArrange; - double yprime = definitionY.SizeCache - definitionY.MinSizeForArrange; - result = xprime.CompareTo(yprime); - } - - return result; - } - } - - /// /// StarDistributionOrderIndexComparer. /// @@ -3895,94 +3311,8 @@ namespace Avalonia.Controls } } - /* /// - /// Implementation of a simple enumerator of grid's logical children - /// - private class GridChildrenCollectionEnumeratorSimple : IEnumerator - { - internal GridChildrenCollectionEnumeratorSimple(Grid grid, bool includeChildren) - { - Debug.Assert(grid != null); - _currentEnumerator = -1; - _enumerator0 = new ColumnDefinitions.Enumerator(grid.ExtData != null ? grid.ExtData.ColumnDefinitions : null); - _enumerator1 = new RowDefinitions.Enumerator(grid.ExtData != null ? grid.ExtData.RowDefinitions : null); - // GridLineRenderer is NOT included into this enumerator. - _enumerator2Index = 0; - if (includeChildren) - { - _enumerator2Collection = grid.Children; - _enumerator2Count = _enumerator2Collection.Count; - } - else - { - _enumerator2Collection = null; - _enumerator2Count = 0; - } - } - - public bool MoveNext() - { - while (_currentEnumerator < 3) - { - if (_currentEnumerator >= 0) - { - switch (_currentEnumerator) - { - case (0): if (_enumerator0.MoveNext()) { _currentChild = _enumerator0.Current; return (true); } break; - case (1): if (_enumerator1.MoveNext()) { _currentChild = _enumerator1.Current; return (true); } break; - case (2): if (_enumerator2Index < _enumerator2Count) - { - _currentChild = _enumerator2Collection[_enumerator2Index]; - _enumerator2Index++; - return (true); - } - break; - } - } - _currentEnumerator++; - } - return (false); - } - - public Object Current - { - get - { - if (_currentEnumerator == -1) - { - throw new InvalidOperationException(SR.Get(SRID.EnumeratorNotStarted)); - } - if (_currentEnumerator >= 3) - { - throw new InvalidOperationException(SR.Get(SRID.EnumeratorReachedEnd)); - } - - // assert below is not true anymore since Controls allowes for null children - //Debug.Assert(_currentChild != null); - return (_currentChild); - } - } - - public void Reset() - { - _currentEnumerator = -1; - _currentChild = null; - _enumerator0.Reset(); - _enumerator1.Reset(); - _enumerator2Index = 0; - } - - private int _currentEnumerator; - private Object _currentChild; - private ColumnDefinitions.Enumerator _enumerator0; - private RowDefinitions.Enumerator _enumerator1; - private Controls _enumerator2Collection; - private int _enumerator2Index; - private int _enumerator2Count; - }*/ - /// - /// Helper to render grid lines. + /// Helper for rendering grid lines. /// internal class GridLinesRenderer : Control { @@ -3995,15 +3325,15 @@ namespace Avalonia.Controls var ds1 = new DashStyle(dashArray, 0); _oddDashPen = new Pen(Brushes.Blue, - _penWidth, - lineCap: PenLineCap.Flat, - dashStyle: ds1); + _penWidth, + lineCap: PenLineCap.Flat, + dashStyle: ds1); var ds2 = new DashStyle(dashArray, _dashLength); _evenDashPen = new Pen(Brushes.Yellow, - _penWidth, - lineCap: PenLineCap.Flat, - dashStyle: ds2); + _penWidth, + lineCap: PenLineCap.Flat, + dashStyle: ds2); } /// @@ -4052,7 +3382,6 @@ namespace Avalonia.Controls internal void UpdateRenderBounds(Size arrangeSize) { _lastArrangeSize = arrangeSize; - this.InvalidateMeasure(); this.InvalidateVisual(); } @@ -4061,6 +3390,6 @@ namespace Avalonia.Controls private const double _penWidth = 1.0; // private static readonly Pen _oddDashPen; // first pen to draw dash private static readonly Pen _evenDashPen; // second pen to draw dash - } + } } } \ No newline at end of file diff --git a/src/Avalonia.Controls/RowDefinitions.cs b/src/Avalonia.Controls/RowDefinitions.cs index 3090844251..cf72cc8ba3 100644 --- a/src/Avalonia.Controls/RowDefinitions.cs +++ b/src/Avalonia.Controls/RowDefinitions.cs @@ -14,10 +14,8 @@ namespace Avalonia.Controls /// /// Initializes a new instance of the class. /// - public RowDefinitions() + public RowDefinitions() : base() { - ResetBehavior = ResetBehavior.Remove; - CollectionChanged += OnCollectionChanged; } /// From 354a21fddb02b3f4614ae4c2acd58773f32d96c6 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 8 Jun 2019 20:50:49 +0800 Subject: [PATCH 02/17] Fix null checking --- src/Avalonia.Controls/DefinitionBase.cs | 34 +++++-------------------- src/Avalonia.Controls/Grid.cs | 28 +++----------------- 2 files changed, 9 insertions(+), 53 deletions(-) diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs index d04578b371..dd97e7ea1e 100644 --- a/src/Avalonia.Controls/DefinitionBase.cs +++ b/src/Avalonia.Controls/DefinitionBase.cs @@ -110,11 +110,11 @@ namespace Avalonia.Controls /// internal void OnUserSizePropertyChanged(AvaloniaPropertyChangedEventArgs e) { - if (InParentLogicalTree) + if (Parent != null) { if (_sharedState != null) { - _sharedState.Invalidate(); + _sharedState?.Invalidate(); } else { @@ -129,21 +129,7 @@ namespace Avalonia.Controls } } } - - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal static void OnUserMinSizePropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) - { - DefinitionBase definition = (DefinitionBase)d; - - if (definition.InParentLogicalTree) - { - Grid parentGrid = (Grid)definition.Parent; - parentGrid.InvalidateMeasure(); - } - } - + /// /// This method reflects Grid.SharedScopeProperty state by setting / clearing /// dynamic property PrivateSharedSizeScopeProperty. Value of PrivateSharedSizeScopeProperty @@ -317,14 +303,6 @@ namespace Avalonia.Controls /// internal abstract double UserMaxSizeValueCache { get; } - /// - /// Protected. Returns true if this DefinitionBase instance is in parent's logical tree. - /// - internal bool InParentLogicalTree - { - get { return (_parentIndex != -1); } - } - internal Grid Parent { get; set; } /// @@ -349,7 +327,7 @@ namespace Avalonia.Controls { DefinitionBase definition = (DefinitionBase)d; - if (definition.InParentLogicalTree) + if (definition.Parent != null) { string sharedSizeGroupId = (string)e.NewValue; @@ -421,7 +399,7 @@ namespace Avalonia.Controls { DefinitionBase definition = (DefinitionBase)d; - if (definition.InParentLogicalTree) + if (definition.Parent != null) { SharedSizeScope privateSharedSizeScope = (SharedSizeScope)e.NewValue; @@ -787,4 +765,4 @@ namespace Avalonia.Controls PrivateSharedSizeScopeProperty.Changed.AddClassHandler(OnPrivateSharedSizeScopePropertyChanged); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs index 5a44b93941..519732e36a 100644 --- a/src/Avalonia.Controls/Grid.cs +++ b/src/Avalonia.Controls/Grid.cs @@ -1726,7 +1726,7 @@ namespace Avalonia.Controls /// /// Array of definitions to process. /// Final size to lay out to. - /// True if sizing row definitions, false for columns + /// True if sizing row definitions, false for columns private void SetFinalSize( IReadOnlyList definitions, double finalSize, @@ -2303,29 +2303,7 @@ namespace Avalonia.Controls } } } - - /// - /// Returns true if ColumnDefinitions collection is not empty - /// - public bool ShouldSerializeColumnDefinitions() - { - ExtendedData extData = ExtData; - return (extData != null - && extData.ColumnDefinitions != null - && extData.ColumnDefinitions.Count > 0); - } - - /// - /// Returns true if RowDefinitions collection is not empty - /// - public bool ShouldSerializeRowDefinitions() - { - ExtendedData extData = ExtData; - return (extData != null - && extData.RowDefinitions != null - && extData.RowDefinitions.Count > 0); - } - + /// /// Synchronized ShowGridLines property with the state of the grid's visual collection /// by adding / removing GridLinesRenderer visual. @@ -3392,4 +3370,4 @@ namespace Avalonia.Controls private static readonly Pen _evenDashPen; // second pen to draw dash } } -} \ No newline at end of file +} From a249ff324e1e0b4f2397cbd39985ec2ec65a595e Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Tue, 11 Jun 2019 01:13:49 +0800 Subject: [PATCH 03/17] Eliminate OnUserSizePropertyChanged --- src/Avalonia.Controls/DefinitionBase.cs | 34 ------------------------- 1 file changed, 34 deletions(-) diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs index dd97e7ea1e..a68fe1265f 100644 --- a/src/Avalonia.Controls/DefinitionBase.cs +++ b/src/Avalonia.Controls/DefinitionBase.cs @@ -52,15 +52,6 @@ namespace Avalonia.Controls } } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e) - { - if (e.Property.PropertyType == typeof(GridLength) - || e.Property.PropertyType == typeof(double)) - OnUserSizePropertyChanged(e); - - base.OnPropertyChanged(e); - } - /// /// Callback to notify about exitting model tree. /// @@ -105,31 +96,6 @@ namespace Avalonia.Controls _minSize = minSize; } - /// - /// This method needs to be internal to be accessable from derived classes. - /// - internal void OnUserSizePropertyChanged(AvaloniaPropertyChangedEventArgs e) - { - if (Parent != null) - { - if (_sharedState != null) - { - _sharedState?.Invalidate(); - } - else - { - if (((GridLength)e.OldValue).GridUnitType != ((GridLength)e.NewValue).GridUnitType) - { - Parent.Invalidate(); - } - else - { - Parent.InvalidateMeasure(); - } - } - } - } - /// /// This method reflects Grid.SharedScopeProperty state by setting / clearing /// dynamic property PrivateSharedSizeScopeProperty. Value of PrivateSharedSizeScopeProperty From 44d467ba980fdb84a829925942de2c977eb984e7 Mon Sep 17 00:00:00 2001 From: FoggyFinder Date: Tue, 11 Jun 2019 18:28:55 +0300 Subject: [PATCH 04/17] fix and test --- src/Avalonia.Controls/TextBox.cs | 2 - .../TextBoxTests.cs | 47 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index d43957313e..fafbf50a07 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -287,8 +287,6 @@ namespace Avalonia.Controls { DecideCaretVisibility(); } - - e.Handled = true; } private void DecideCaretVisibility() diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 9b62509138..bb1d031692 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -401,6 +401,53 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void TextBox_GotFocus_And_LostFocus_Work_Properly() + { + using (UnitTestApplication.Start(FocusServices)) + { + var target1 = new TextBox + { + Template = CreateTemplate(), + Text = "1234" + }; + var target2 = new TextBox + { + Template = CreateTemplate(), + Text = "5678" + }; + var sp = new StackPanel(); + sp.Children.Add(target1); + sp.Children.Add(target2); + + var root = new TestRoot { Child = sp }; + + var gfcount = 0; + var lfcount = 0; + + target1.GotFocus += (s, e) => gfcount++; + target2.LostFocus += (s, e) => lfcount++; + + target2.Focus(); + Assert.False(target1.IsFocused); + Assert.True(target2.IsFocused); + + target1.Focus(); + Assert.False(target2.IsFocused); + Assert.True(target1.IsFocused); + + Assert.Equal(1, gfcount); + Assert.Equal(1, lfcount); + } + } + + private static TestServices FocusServices => TestServices.MockThreadingInterface.With( + focusManager: new FocusManager(), + keyboardDevice: () => new KeyboardDevice(), + keyboardNavigation: new KeyboardNavigationHandler(), + inputManager: new InputManager(), + standardCursorFactory: Mock.Of()); + private static TestServices Services => TestServices.MockThreadingInterface.With( standardCursorFactory: Mock.Of()); From 434af7d56db1d1ca0e91762c5e4f05fc3df1c57f Mon Sep 17 00:00:00 2001 From: Abdulbaqi Alshareef Date: Tue, 11 Jun 2019 13:58:50 +0200 Subject: [PATCH 05/17] Add CaretBrush property to Textbox --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 1 + .../Presenters/TextPresenter.cs | 32 +++++++++++++------ src/Avalonia.Controls/TextBox.cs | 9 ++++++ src/Avalonia.Themes.Default/TextBox.xaml | 3 +- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 0c0a4d705b..877875a2e1 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -26,6 +26,7 @@ + diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index fbdf885709..2626b67bfc 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -19,6 +19,9 @@ namespace Avalonia.Controls.Presenters public static readonly StyledProperty PasswordCharProperty = AvaloniaProperty.Register(nameof(PasswordChar)); + public static readonly StyledProperty CaretBrushProperty = + AvaloniaProperty.Register(nameof(CaretBrushProperty)); + public static readonly DirectProperty SelectionStartProperty = TextBox.SelectionStartProperty.AddOwner( o => o.SelectionStart, @@ -35,7 +38,7 @@ namespace Avalonia.Controls.Presenters private int _selectionEnd; private bool _caretBlink; private IBrush _highlightBrush; - + static TextPresenter() { AffectsRender(PasswordCharProperty); @@ -79,6 +82,12 @@ namespace Avalonia.Controls.Presenters set => SetValue(PasswordCharProperty, value); } + public IBrush CaretBrush + { + get => GetValue(CaretBrushProperty); + set => SetValue(CaretBrushProperty, value); + } + public int SelectionStart { get @@ -144,16 +153,21 @@ namespace Avalonia.Controls.Presenters if (selectionStart == selectionEnd) { - var backgroundColor = (((Control)TemplatedParent).GetValue(BackgroundProperty) as SolidColorBrush)?.Color; - var caretBrush = Brushes.Black; + var caretBrush = CaretBrush; - if (backgroundColor.HasValue) + if (caretBrush is null) { - byte red = (byte)~(backgroundColor.Value.R); - byte green = (byte)~(backgroundColor.Value.G); - byte blue = (byte)~(backgroundColor.Value.B); - - caretBrush = new SolidColorBrush(Color.FromRgb(red, green, blue)); + var backgroundColor = (((Control)TemplatedParent).GetValue(BackgroundProperty) as SolidColorBrush)?.Color; + if (backgroundColor.HasValue) + { + byte red = (byte)~(backgroundColor.Value.R); + byte green = (byte)~(backgroundColor.Value.G); + byte blue = (byte)~(backgroundColor.Value.B); + + caretBrush = new SolidColorBrush(Color.FromRgb(red, green, blue)); + } + else + caretBrush = Brushes.Black; } if (_caretBlink) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index d43957313e..f67b6e54a5 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -38,6 +38,9 @@ namespace Avalonia.Controls public static readonly StyledProperty PasswordCharProperty = AvaloniaProperty.Register(nameof(PasswordChar)); + public static readonly StyledProperty CaretBrushProperty = + AvaloniaProperty.Register(nameof(CaretBrushProperty)); + public static readonly DirectProperty SelectionStartProperty = AvaloniaProperty.RegisterDirect( nameof(SelectionStart), @@ -169,6 +172,12 @@ namespace Avalonia.Controls set => SetValue(PasswordCharProperty, value); } + public IBrush CaretBrush + { + get => GetValue(CaretBrushProperty); + set => SetValue(CaretBrushProperty, value); + } + public int SelectionStart { get diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index 6741bdc7d9..a82ea1289b 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -44,7 +44,8 @@ SelectionEnd="{TemplateBinding SelectionEnd}" TextAlignment="{TemplateBinding TextAlignment}" TextWrapping="{TemplateBinding TextWrapping}" - PasswordChar="{TemplateBinding PasswordChar}"/> + PasswordChar="{TemplateBinding PasswordChar}" + CaretBrush="{TemplateBinding CaretBrush}"/> From c67e4057384ba3a515ab42cd195be7a6b61297ee Mon Sep 17 00:00:00 2001 From: Abdulbaqi Alshareef Date: Wed, 12 Jun 2019 14:33:57 +0200 Subject: [PATCH 06/17] Add SelectionBrush and SelectionForegroundBrush Feature --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 3 ++ .../Presenters/TextPresenter.cs | 30 ++++++++++++++----- src/Avalonia.Controls/TextBox.cs | 22 ++++++++++++-- src/Avalonia.Themes.Default/TextBox.xaml | 5 +++- 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml index 0c0a4d705b..49f2eea636 100644 --- a/samples/ControlCatalog/Pages/TextBoxPage.xaml +++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml @@ -26,6 +26,9 @@ + diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index fbdf885709..94d9c2d7c5 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -19,6 +19,12 @@ namespace Avalonia.Controls.Presenters public static readonly StyledProperty PasswordCharProperty = AvaloniaProperty.Register(nameof(PasswordChar)); + public static readonly StyledProperty SelectionBrushProperty = + AvaloniaProperty.Register(nameof(SelectionBrushProperty)); + + public static readonly StyledProperty SelectionForegroundBrushProperty = + AvaloniaProperty.Register(nameof(SelectionForegroundBrushProperty)); + public static readonly DirectProperty SelectionStartProperty = TextBox.SelectionStartProperty.AddOwner( o => o.SelectionStart, @@ -34,7 +40,7 @@ namespace Avalonia.Controls.Presenters private int _selectionStart; private int _selectionEnd; private bool _caretBlink; - private IBrush _highlightBrush; + private IBrush _selectionBrush; static TextPresenter() { @@ -79,6 +85,18 @@ namespace Avalonia.Controls.Presenters set => SetValue(PasswordCharProperty, value); } + public IBrush SelectionBrush + { + get => GetValue(SelectionBrushProperty); + set => SetValue(SelectionBrushProperty, value); + } + + public IBrush SelectionForegroundBrush + { + get => GetValue(SelectionForegroundBrushProperty); + set => SetValue(SelectionForegroundBrushProperty, value); + } + public int SelectionStart { get @@ -129,14 +147,11 @@ namespace Avalonia.Controls.Presenters var rects = FormattedText.HitTestTextRange(start, length); - if (_highlightBrush == null) - { - _highlightBrush = (IBrush)this.FindResource("HighlightBrush"); - } + _selectionBrush = SelectionBrush; foreach (var rect in rects) { - context.FillRectangle(_highlightBrush, rect); + context.FillRectangle(_selectionBrush, rect); } } @@ -247,12 +262,13 @@ namespace Avalonia.Controls.Presenters var selectionEnd = SelectionEnd; var start = Math.Min(selectionStart, selectionEnd); var length = Math.Max(selectionStart, selectionEnd) - start; + var selectionForegroundBrush = SelectionForegroundBrush ?? Brushes.White; if (length > 0) { result.Spans = new[] { - new FormattedTextStyleSpan(start, length, foregroundBrush: Brushes.White), + new FormattedTextStyleSpan(start, length, foregroundBrush: selectionForegroundBrush), }; } diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index d43957313e..0d39458a5d 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -38,6 +38,12 @@ namespace Avalonia.Controls public static readonly StyledProperty PasswordCharProperty = AvaloniaProperty.Register(nameof(PasswordChar)); + public static readonly StyledProperty SelectionBrushProperty = + AvaloniaProperty.Register(nameof(SelectionBrushProperty)); + + public static readonly StyledProperty SelectionForegroundBrushProperty = + AvaloniaProperty.Register(nameof(SelectionForegroundBrushProperty)); + public static readonly DirectProperty SelectionStartProperty = AvaloniaProperty.RegisterDirect( nameof(SelectionStart), @@ -169,6 +175,18 @@ namespace Avalonia.Controls set => SetValue(PasswordCharProperty, value); } + public IBrush SelectionBrush + { + get => GetValue(SelectionBrushProperty); + set => SetValue(SelectionBrushProperty, value); + } + + public IBrush SelectionForegroundBrush + { + get => GetValue(SelectionForegroundBrushProperty); + set => SetValue(SelectionForegroundBrushProperty, value); + } + public int SelectionStart { get @@ -456,7 +474,7 @@ namespace Avalonia.Controls movement = true; selection = false; handled = true; - + } else if (Match(keymap.MoveCursorToTheEndOfLine)) { @@ -485,7 +503,7 @@ namespace Avalonia.Controls movement = true; selection = true; handled = true; - + } else if (Match(keymap.MoveCursorToTheEndOfLineWithSelection)) { diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index 6741bdc7d9..e286e513e0 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -3,6 +3,7 @@ + @@ -44,7 +45,9 @@ SelectionEnd="{TemplateBinding SelectionEnd}" TextAlignment="{TemplateBinding TextAlignment}" TextWrapping="{TemplateBinding TextWrapping}" - PasswordChar="{TemplateBinding PasswordChar}"/> + PasswordChar="{TemplateBinding PasswordChar}" + SelectionBrush="{TemplateBinding SelectionBrush}" + SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"/> From e02de6cbb6988784f030b62d54501978ebebc312 Mon Sep 17 00:00:00 2001 From: Abdulbaqi Alshareef Date: Wed, 12 Jun 2019 21:50:43 +0200 Subject: [PATCH 07/17] Fix the indentation --- src/Avalonia.Controls/Presenters/TextPresenter.cs | 2 +- src/Avalonia.Controls/TextBox.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 2626b67bfc..854a4dc07a 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -20,7 +20,7 @@ namespace Avalonia.Controls.Presenters AvaloniaProperty.Register(nameof(PasswordChar)); public static readonly StyledProperty CaretBrushProperty = - AvaloniaProperty.Register(nameof(CaretBrushProperty)); + AvaloniaProperty.Register(nameof(CaretBrushProperty)); public static readonly DirectProperty SelectionStartProperty = TextBox.SelectionStartProperty.AddOwner( diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index f67b6e54a5..ec2909288f 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -39,7 +39,7 @@ namespace Avalonia.Controls AvaloniaProperty.Register(nameof(PasswordChar)); public static readonly StyledProperty CaretBrushProperty = - AvaloniaProperty.Register(nameof(CaretBrushProperty)); + AvaloniaProperty.Register(nameof(CaretBrushProperty)); public static readonly DirectProperty SelectionStartProperty = AvaloniaProperty.RegisterDirect( From 185511d7e0b80e9c9bfb29a34b62b8d88b1b94d8 Mon Sep 17 00:00:00 2001 From: Abdulbaqi Alshareef Date: Thu, 13 Jun 2019 09:53:55 +0200 Subject: [PATCH 08/17] Set default SelectionForegroundBrush in default style resource instead of code --- src/Avalonia.Controls/Presenters/TextPresenter.cs | 3 +-- src/Avalonia.Themes.Default/Accents/BaseDark.xaml | 2 ++ src/Avalonia.Themes.Default/Accents/BaseLight.xaml | 2 ++ src/Avalonia.Themes.Default/TextBox.xaml | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 94d9c2d7c5..dd36f3da4c 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -262,13 +262,12 @@ namespace Avalonia.Controls.Presenters var selectionEnd = SelectionEnd; var start = Math.Min(selectionStart, selectionEnd); var length = Math.Max(selectionStart, selectionEnd) - start; - var selectionForegroundBrush = SelectionForegroundBrush ?? Brushes.White; if (length > 0) { result.Spans = new[] { - new FormattedTextStyleSpan(start, length, foregroundBrush: selectionForegroundBrush), + new FormattedTextStyleSpan(start, length, SelectionForegroundBrush), }; } diff --git a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml index 8f7d56dbc6..0ed17fae76 100644 --- a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml +++ b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml @@ -22,6 +22,7 @@ #FF808080 #FF119EDA + #FFFFFFFF #FFFF0000 #10FF0000 @@ -39,6 +40,7 @@ + diff --git a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml index 666596d710..3a8a8ec446 100644 --- a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml +++ b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml @@ -22,6 +22,7 @@ #FF808080 #FF086F9E + #FFFFFFFF #FFFF0000 #10FF0000 @@ -39,6 +40,7 @@ + diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml index e286e513e0..9aba2275bf 100644 --- a/src/Avalonia.Themes.Default/TextBox.xaml +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -4,6 +4,7 @@ + From 0760d805b9ed49485b5d4c0b5dc882aab809e278 Mon Sep 17 00:00:00 2001 From: Abdulbaqi Alshareef Date: Thu, 13 Jun 2019 10:06:36 +0200 Subject: [PATCH 09/17] Remove unneeded variable --- src/Avalonia.Controls/Presenters/TextPresenter.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index dd36f3da4c..c499ea0e0b 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -40,7 +40,6 @@ namespace Avalonia.Controls.Presenters private int _selectionStart; private int _selectionEnd; private bool _caretBlink; - private IBrush _selectionBrush; static TextPresenter() { @@ -147,11 +146,9 @@ namespace Avalonia.Controls.Presenters var rects = FormattedText.HitTestTextRange(start, length); - _selectionBrush = SelectionBrush; - foreach (var rect in rects) { - context.FillRectangle(_selectionBrush, rect); + context.FillRectangle(SelectionBrush, rect); } } From 85fe3f23f479738dfaedcb034c649507003e77a0 Mon Sep 17 00:00:00 2001 From: Abdulbaqi Alshareef Date: Thu, 13 Jun 2019 19:03:59 +0200 Subject: [PATCH 10/17] Fix the indentation --- src/Avalonia.Controls/Presenters/TextPresenter.cs | 4 ++-- src/Avalonia.Controls/TextBox.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index c499ea0e0b..2c8da58b44 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -20,10 +20,10 @@ namespace Avalonia.Controls.Presenters AvaloniaProperty.Register(nameof(PasswordChar)); public static readonly StyledProperty SelectionBrushProperty = - AvaloniaProperty.Register(nameof(SelectionBrushProperty)); + AvaloniaProperty.Register(nameof(SelectionBrushProperty)); public static readonly StyledProperty SelectionForegroundBrushProperty = - AvaloniaProperty.Register(nameof(SelectionForegroundBrushProperty)); + AvaloniaProperty.Register(nameof(SelectionForegroundBrushProperty)); public static readonly DirectProperty SelectionStartProperty = TextBox.SelectionStartProperty.AddOwner( diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 0d39458a5d..0a64c99a66 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -39,10 +39,10 @@ namespace Avalonia.Controls AvaloniaProperty.Register(nameof(PasswordChar)); public static readonly StyledProperty SelectionBrushProperty = - AvaloniaProperty.Register(nameof(SelectionBrushProperty)); + AvaloniaProperty.Register(nameof(SelectionBrushProperty)); public static readonly StyledProperty SelectionForegroundBrushProperty = - AvaloniaProperty.Register(nameof(SelectionForegroundBrushProperty)); + AvaloniaProperty.Register(nameof(SelectionForegroundBrushProperty)); public static readonly DirectProperty SelectionStartProperty = AvaloniaProperty.RegisterDirect( From 7c9f46d815a130ec900ecc6972ad9e541c76b08c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 13 Jun 2019 21:29:25 +0300 Subject: [PATCH 11/17] Mark TextPresenter's selection properties as AffectsRender --- src/Avalonia.Controls/Presenters/TextPresenter.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 6b5391454f..b3345ec101 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -46,7 +46,9 @@ namespace Avalonia.Controls.Presenters static TextPresenter() { - AffectsRender(PasswordCharProperty); + AffectsRender(PasswordCharProperty, + SelectionBrushProperty, SelectionForegroundBrushProperty, + SelectionStartProperty, SelectionEndProperty); } public TextPresenter() From 9dad3f265b0a47bc80d87a7bf91eff8a0d9c9dc6 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 13 Jun 2019 21:29:55 +0300 Subject: [PATCH 12/17] Show caret even for ReadOnly textboxes, since keyboard selection works anyway --- src/Avalonia.Controls/TextBox.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 876e6a66a7..870c88c210 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -320,10 +320,7 @@ namespace Avalonia.Controls private void DecideCaretVisibility() { - if (!IsReadOnly) - _presenter?.ShowCaret(); - else - _presenter?.HideCaret(); + _presenter.ShowCaret(); } protected override void OnLostFocus(RoutedEventArgs e) From ebc52dd6da956cf1a9dab7a0e025bbb53f28623f Mon Sep 17 00:00:00 2001 From: Abdulbaqi Alshareef Date: Fri, 14 Jun 2019 12:18:06 +0200 Subject: [PATCH 13/17] Improve Button and ToggleButton styling --- src/Avalonia.Themes.Default/Button.xaml | 6 +++--- src/Avalonia.Themes.Default/ToggleButton.xaml | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Themes.Default/Button.xaml b/src/Avalonia.Themes.Default/Button.xaml index 698ddec2a8..6ed1f6d8fc 100644 --- a/src/Avalonia.Themes.Default/Button.xaml +++ b/src/Avalonia.Themes.Default/Button.xaml @@ -22,13 +22,13 @@ - - - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/ToggleButton.xaml b/src/Avalonia.Themes.Default/ToggleButton.xaml index 9e05c38eef..41f366fdf9 100644 --- a/src/Avalonia.Themes.Default/ToggleButton.xaml +++ b/src/Avalonia.Themes.Default/ToggleButton.xaml @@ -22,17 +22,17 @@ - - - - \ No newline at end of file + From d1f2b941fb17337b0ded5e50146e00ac975cc16d Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 14 Jun 2019 21:49:08 +0300 Subject: [PATCH 14/17] Apply template before touching the textbox --- tests/Avalonia.Controls.UnitTests/TextBoxTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index bb1d031692..932aada64e 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -420,6 +420,9 @@ namespace Avalonia.Controls.UnitTests sp.Children.Add(target1); sp.Children.Add(target2); + target1.ApplyTemplate(); + target2.ApplyTemplate(); + var root = new TestRoot { Child = sp }; var gfcount = 0; From 1451a7ed406a397cdbda894e493c8df6172d4cf1 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Sun, 16 Jun 2019 15:16:24 +0200 Subject: [PATCH 15/17] Make sure System font can be used with all face variations --- src/Skia/Avalonia.Skia/FormattedTextImpl.cs | 4 ++-- .../Avalonia.Skia/SKTypefaceCollection.cs | 2 +- src/Skia/Avalonia.Skia/TypefaceCache.cs | 23 ++++++++++--------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index b701e60660..eb7b65cdce 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -28,7 +28,7 @@ namespace Avalonia.Skia // Replace 0 characters with zero-width spaces (200B) Text = Text.Replace((char)0, (char)0x200B); - SKTypeface skiaTypeface = TypefaceCache.Default; + SKTypeface skiaTypeface = null; if (typeface.FontFamily.Key != null) { @@ -45,7 +45,7 @@ namespace Avalonia.Skia familyName, typeface.Style, typeface.Weight); - if (skiaTypeface != TypefaceCache.Default) break; + if (skiaTypeface.FamilyName != TypefaceCache.DefaultFamilyName) break; } } else diff --git a/src/Skia/Avalonia.Skia/SKTypefaceCollection.cs b/src/Skia/Avalonia.Skia/SKTypefaceCollection.cs index 17c51dbb6e..17448127b0 100644 --- a/src/Skia/Avalonia.Skia/SKTypefaceCollection.cs +++ b/src/Skia/Avalonia.Skia/SKTypefaceCollection.cs @@ -47,7 +47,7 @@ namespace Avalonia.Skia if (!_fontFamilies.TryGetValue(typeface.FontFamily.Name, out var fontFamily)) { - return TypefaceCache.Default; + return TypefaceCache.GetTypeface(TypefaceCache.DefaultFamilyName, typeface.Style, typeface.Weight); } var weight = (SKFontStyleWeight)typeface.Weight; diff --git a/src/Skia/Avalonia.Skia/TypefaceCache.cs b/src/Skia/Avalonia.Skia/TypefaceCache.cs index 94b9e89962..9e270114d2 100644 --- a/src/Skia/Avalonia.Skia/TypefaceCache.cs +++ b/src/Skia/Avalonia.Skia/TypefaceCache.cs @@ -12,8 +12,10 @@ namespace Avalonia.Skia /// internal static class TypefaceCache { - public static SKTypeface Default = CreateDefaultTypeface(); - static readonly Dictionary> Cache = new Dictionary>(); + public static readonly string DefaultFamilyName = CreateDefaultFamilyName(); + + private static readonly Dictionary> s_cache = + new Dictionary>(); struct FontKey { @@ -49,26 +51,26 @@ namespace Avalonia.Skia // Equals and GetHashCode ommitted } - private static SKTypeface CreateDefaultTypeface() + private static string CreateDefaultFamilyName() { - var defaultTypeface = SKTypeface.FromFamilyName(FontFamily.Default.Name) ?? SKTypeface.FromFamilyName(null); + var defaultTypeface = SKTypeface.CreateDefault(); - return defaultTypeface; + return defaultTypeface.FamilyName; } private static SKTypeface GetTypeface(string name, FontKey key) { var familyKey = name; - if (!Cache.TryGetValue(familyKey, out var entry)) + if (!s_cache.TryGetValue(familyKey, out var entry)) { - Cache[familyKey] = entry = new Dictionary(); + s_cache[familyKey] = entry = new Dictionary(); } if (!entry.TryGetValue(key, out var typeface)) { - typeface = SKTypeface.FromFamilyName(familyKey, key.Weight, SKFontStyleWidth.Normal, key.Slant) - ?? Default; + typeface = SKTypeface.FromFamilyName(familyKey, key.Weight, SKFontStyleWidth.Normal, key.Slant) ?? + GetTypeface(DefaultFamilyName, key); entry[key] = typeface; } @@ -78,7 +80,7 @@ namespace Avalonia.Skia public static SKTypeface GetTypeface(string name, FontStyle style, FontWeight weight) { - SKFontStyleSlant skStyle = SKFontStyleSlant.Upright; + var skStyle = SKFontStyleSlant.Upright; switch (style) { @@ -93,6 +95,5 @@ namespace Avalonia.Skia return GetTypeface(name, new FontKey((SKFontStyleWeight)weight, skStyle)); } - } } From 5c698d8fb5d95dd27a93e6185cca4518f6f109de Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 17 Jun 2019 17:28:51 +0300 Subject: [PATCH 16/17] Removed old Rider hack --- src/Avalonia.Native/Avalonia.Native.csproj | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Avalonia.Native/Avalonia.Native.csproj b/src/Avalonia.Native/Avalonia.Native.csproj index c8ee73ad5d..35e50b1b36 100644 --- a/src/Avalonia.Native/Avalonia.Native.csproj +++ b/src/Avalonia.Native/Avalonia.Native.csproj @@ -1,4 +1,4 @@ - + false @@ -7,8 +7,6 @@ /usr/bin/castxml /usr/local/bin/castxml true - - $(MSBuildThisFileDirectory)/Generated From 628e6778b3ea32948ce11c38b3337aa365a8e22e Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 17 Jun 2019 17:29:03 +0300 Subject: [PATCH 17/17] Removed Splat.props --- Avalonia.sln | 1 - 1 file changed, 1 deletion(-) diff --git a/Avalonia.sln b/Avalonia.sln index 484d7a4cde..f86c18ba1e 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -146,7 +146,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1 build\Serilog.props = build\Serilog.props build\SharpDX.props = build\SharpDX.props build\SkiaSharp.props = build\SkiaSharp.props - build\Splat.props = build\Splat.props build\System.Memory.props = build\System.Memory.props build\XUnit.props = build\XUnit.props EndProjectSection