Browse Source

Merge pull request #5767 from MarchingCube/fix-grid-splitter-resize

Fix GridSplitter not resizing correctly
pull/5818/head
Max Katz 5 years ago
committed by GitHub
parent
commit
e2f618dcb9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      src/Avalonia.Base/Utilities/MathUtilities.cs
  2. 22
      src/Avalonia.Controls/GridSplitter.cs
  3. 14
      src/Avalonia.Controls/Presenters/ContentPresenter.cs
  4. 25
      src/Avalonia.Layout/LayoutHelper.cs
  5. 16
      src/Avalonia.Layout/Layoutable.cs

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

@ -30,6 +30,21 @@ namespace Avalonia.Utilities
return (-eps < delta) && (eps > delta);
}
/// <summary>
/// AreClose - Returns whether or not two doubles are "close". That is, whether or
/// not they are within epsilon of each other.
/// </summary>
/// <param name="value1"> The first double to compare. </param>
/// <param name="value2"> The second double to compare. </param>
/// <param name="eps"> The fixed epsilon value used to compare.</param>
public static bool AreClose(double value1, double value2, double eps)
{
//in case they are Infinities (then epsilon check does not work)
if (value1 == value2) return true;
double delta = value1 - value2;
return (-eps < delta) && (eps > delta);
}
/// <summary>
/// AreClose - Returns whether or not two floats are "close". That is, whether or
/// not they are within epsilon of each other.

22
src/Avalonia.Controls/GridSplitter.cs

@ -609,10 +609,20 @@ namespace Avalonia.Controls
private void MoveSplitter(double horizontalChange, double verticalChange)
{
Debug.Assert(_resizeData != null, "_resizeData should not be null when calling MoveSplitter");
// Calculate the offset to adjust the splitter.
var delta = _resizeData.ResizeDirection == GridResizeDirection.Columns ? horizontalChange : verticalChange;
// Calculate the offset to adjust the splitter. If layout rounding is enabled, we
// need to round to an integer physical pixel value to avoid round-ups of children that
// expand the bounds of the Grid. In practice this only happens in high dpi because
// horizontal/vertical offsets here are never fractional (they correspond to mouse movement
// across logical pixels). Rounding error only creeps in when converting to a physical
// display with something other than the logical 96 dpi.
double delta = _resizeData.ResizeDirection == GridResizeDirection.Columns ? horizontalChange : verticalChange;
if (UseLayoutRounding)
{
delta = LayoutHelper.RoundLayoutValue(delta, LayoutHelper.GetLayoutScale(this));
}
DefinitionBase definition1 = _resizeData.Definition1;
DefinitionBase definition2 = _resizeData.Definition2;
@ -622,11 +632,11 @@ namespace Avalonia.Controls
double actualLength2 = GetActualLength(definition2);
// When splitting, Check to see if the total pixels spanned by the definitions
// is the same asbefore starting resize. If not cancel the drag
// is the same as before starting resize. If not cancel the drag.
if (_resizeData.SplitBehavior == SplitBehavior.Split &&
!MathUtilities.AreClose(
actualLength1 + actualLength2,
_resizeData.OriginalDefinition1ActualLength + _resizeData.OriginalDefinition2ActualLength))
_resizeData.OriginalDefinition1ActualLength + _resizeData.OriginalDefinition2ActualLength, LayoutHelper.LayoutEpsilon))
{
CancelResize();

14
src/Avalonia.Controls/Presenters/ContentPresenter.cs

@ -378,7 +378,7 @@ namespace Avalonia.Controls.Presenters
var useLayoutRounding = UseLayoutRounding;
var availableSize = finalSize;
var sizeForChild = availableSize;
var scale = GetLayoutScale();
var scale = LayoutHelper.GetLayoutScale(this);
var originX = offset.X;
var originY = offset.Y;
@ -462,18 +462,6 @@ namespace Avalonia.Controls.Presenters
PseudoClasses.Set(":empty", Content is null);
}
private double GetLayoutScale()
{
var result = (VisualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0;
if (result == 0 || double.IsNaN(result) || double.IsInfinity(result))
{
throw new Exception($"Invalid LayoutScaling returned from {VisualRoot.GetType()}");
}
return result;
}
private void TemplatedParentChanged(AvaloniaPropertyChangedEventArgs e)
{
var host = e.NewValue as IContentPresenterHost;

25
src/Avalonia.Layout/LayoutHelper.cs

@ -9,6 +9,12 @@ namespace Avalonia.Layout
/// </summary>
public static class LayoutHelper
{
/// <summary>
/// Epsilon value used for certain layout calculations.
/// Based on the value in WPF LayoutDoubleUtil.
/// </summary>
public static double LayoutEpsilon { get; } = 0.00000153;
/// <summary>
/// Calculates a control's size based on its <see cref="ILayoutable.Width"/>,
/// <see cref="ILayoutable.Height"/>, <see cref="ILayoutable.MinWidth"/>,
@ -82,6 +88,25 @@ namespace Avalonia.Layout
InnerInvalidateMeasure(control);
}
/// <summary>
/// Obtains layout scale of the given control.
/// </summary>
/// <param name="control">The control.</param>
/// <exception cref="Exception">Thrown when control has no root or returned layout scaling is invalid.</exception>
public static double GetLayoutScale(ILayoutable control)
{
var visualRoot = control.VisualRoot;
var result = (visualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0;
if (result == 0 || double.IsNaN(result) || double.IsInfinity(result))
{
throw new Exception($"Invalid LayoutScaling returned from {visualRoot.GetType()}");
}
return result;
}
/// <summary>
/// Rounds a size to integer values for layout purposes, compensating for high DPI screen
/// coordinates.

16
src/Avalonia.Layout/Layoutable.cs

@ -590,7 +590,7 @@ namespace Avalonia.Layout
if (UseLayoutRounding)
{
var scale = GetLayoutScale();
var scale = LayoutHelper.GetLayoutScale(this);
width = LayoutHelper.RoundLayoutValue(width, scale);
height = LayoutHelper.RoundLayoutValue(height, scale);
}
@ -652,7 +652,7 @@ namespace Avalonia.Layout
var horizontalAlignment = HorizontalAlignment;
var verticalAlignment = VerticalAlignment;
var size = availableSizeMinusMargins;
var scale = GetLayoutScale();
var scale = LayoutHelper.GetLayoutScale(this);
var useLayoutRounding = UseLayoutRounding;
if (horizontalAlignment != HorizontalAlignment.Stretch)
@ -833,17 +833,5 @@ namespace Avalonia.Layout
{
return new Size(Math.Max(size.Width, 0), Math.Max(size.Height, 0));
}
private double GetLayoutScale()
{
var result = (VisualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0;
if (result == 0 || double.IsNaN(result) || double.IsInfinity(result))
{
throw new Exception($"Invalid LayoutScaling returned from {VisualRoot.GetType()}");
}
return result;
}
}
}

Loading…
Cancel
Save