Browse Source

Add Boxshadow(s) Documentation Comments (#19644)

* Fix formatting errors/warnings in BoxShadow

* Fix formatting errors/warnings in BoxShadows

* Add documentation comments to BoxShadow

* Add documentation comments to BoxShadows
pull/19650/head
robloo 8 months ago
committed by GitHub
parent
commit
8a444ef3f0
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 142
      src/Avalonia.Base/Media/BoxShadow.cs
  2. 118
      src/Avalonia.Base/Media/BoxShadows.cs

142
src/Avalonia.Base/Media/BoxShadow.cs

@ -6,25 +6,90 @@ using Avalonia.Utilities;
namespace Avalonia.Media
{
/// <summary>
/// Represents a box shadow which can be attached to an element or control.
/// </summary>
public struct BoxShadow
{
private readonly static char[] s_Separator = new char[] { ' ', '\t' };
/// <summary>
/// Gets or sets the horizontal offset (distance) of the shadow.
/// </summary>
/// <remarks>
/// Positive values place the shadow to the right of the element while
/// negative values place the shadow to the left.
/// </remarks>
public double OffsetX { get; set; }
/// <summary>
/// Gets or sets the vertical offset (distance) of the shadow.
/// </summary>
/// <remarks>
/// Positive values place the shadow below the element while
/// negative values place the shadow above.
/// </remarks>
public double OffsetY { get; set; }
/// <summary>
/// Gets or sets the blur radius.
/// This is used to control the amount of blurring.
/// </summary>
/// <remarks>
/// The larger this value, the bigger the blur effect, so the shadow becomes larger and more transparent.
/// Negative values are not allowed. If not specified, the default (zero) is used and the shadow edge is sharp.
/// </remarks>
public double Blur { get; set; }
/// <summary>
/// Gets or sets the spread radius.
/// This is used to control the overall size of the shadow.
/// </summary>
/// <remarks>
/// Positive values will cause the shadow to expand and grow larger, negative values will cause the shadow to shrink.
/// If not specified, the default (zero) is used and the shadow will be the same size as the element.
/// </remarks>
public double Spread { get; set; }
/// <summary>
/// Gets or sets the color of the shadow.
/// </summary>
public Color Color { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the shadow is inset and drawn within the element rather than outside of it.
/// </summary>
/// <remarks>
/// Inset changes the shadow to inside the element (as if the content was depressed inside the box).
/// If false (the default), the shadow is assumed to be a drop shadow (as if the box were raised above the content).
/// <br/><br/>
/// Inset shadows are drawn inside the element, above the background (even when it's transparent), but below any content.
/// </remarks>
public bool IsInset { get; set; }
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// <c>true</c> if the current object is equal to the other parameter; otherwise, <c>false</c>.
/// </returns>
public bool Equals(in BoxShadow other)
{
return OffsetX.Equals(other.OffsetX) && OffsetY.Equals(other.OffsetY) && Blur.Equals(other.Blur) && Spread.Equals(other.Spread) && Color.Equals(other.Color);
return OffsetX.Equals(other.OffsetX)
&& OffsetY.Equals(other.OffsetY)
&& Blur.Equals(other.Blur)
&& Spread.Equals(other.Spread)
&& Color.Equals(other.Color);
}
/// <inheritdoc/>
public override bool Equals(object? obj)
{
return obj is BoxShadow other && Equals(other);
}
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
@ -38,8 +103,6 @@ namespace Avalonia.Media
}
}
private readonly static char[] s_Separator = new char[] { ' ', '\t' };
struct ArrayReader
{
private int _index;
@ -55,20 +118,28 @@ namespace Avalonia.Media
{
s = null;
if (_index >= _arr.Length)
{
return false;
}
s = _arr[_index];
_index++;
return true;
}
public string ReadString()
{
if(!TryReadString(out var rv))
if (!TryReadString(out var rv))
{
throw new FormatException();
}
return rv;
}
}
/// <inheritdoc/>
public override string ToString()
{
var sb = StringBuilderCache.Acquire();
@ -106,20 +177,45 @@ namespace Avalonia.Media
Color.ToString(sb);
}
/// <summary>
/// Parses a <see cref="BoxShadow"/> string.
/// </summary>
/// <remarks>
/// A box shadow may be specified in multiple formats with separate components:
/// <list type="bullet">
/// <item>Two, three, or four length values.</item>
/// <item>A color value.</item>
/// <item>An optional inset keyword.</item>
/// </list>
/// If only two length values are given they will be interpreted as <see cref="OffsetX"/> and <see cref="OffsetY"/>.
/// If a third value is given, it is interpreted as a <see cref="Blur"/>, and if a fourth value is given,
/// it is interpreted as <see cref="Spread"/>.
/// </remarks>
/// <param name="s">The input string to parse.</param>
/// <returns>A new <see cref="BoxShadow"/></returns>
public static unsafe BoxShadow Parse(string s)
{
if(s == null)
if (s == null)
{
throw new ArgumentNullException();
}
if (s.Length == 0)
{
throw new FormatException();
}
var p = s.Split(s_Separator, StringSplitOptions.RemoveEmptyEntries);
if (p.Length == 1 && p[0] == "none")
{
return default;
}
if (p.Length < 3 || p.Length > 6)
{
throw new FormatException();
}
bool inset = false;
var tokenizer = new ArrayReader(p);
@ -135,16 +231,20 @@ namespace Avalonia.Media
var offsetY = double.Parse(tokenizer.ReadString(), CultureInfo.InvariantCulture);
double blur = 0;
double spread = 0;
tokenizer.TryReadString(out var token3);
tokenizer.TryReadString(out var token4);
tokenizer.TryReadString(out var token5);
if (token4 != null)
if (token4 != null)
{
blur = double.Parse(token3!, CultureInfo.InvariantCulture);
}
if (token5 != null)
{
spread = double.Parse(token4!, CultureInfo.InvariantCulture);
}
var color = Color.Parse(token5 ?? token4 ?? token3!);
return new BoxShadow
@ -158,12 +258,36 @@ namespace Avalonia.Media
};
}
/// <summary>
/// Transforms the specified bounding rectangle to account for the shadow's offset, spread, and blur.
/// </summary>
/// <param name="rect">The original bounding <see cref="Rect"/> to transform.</param>
/// <returns>
/// A new <see cref="Rect"/> that includes the shadow's offset, spread, and blur if the shadow is not inset;
/// otherwise, the original rectangle.
/// </returns>
public Rect TransformBounds(in Rect rect)
=> IsInset ? rect : rect.Translate(new Vector(OffsetX, OffsetY)).Inflate(Spread + Blur);
/// <summary>
/// Determines whether two <see cref="BoxShadow"/> values are equal.
/// </summary>
/// <param name="left">The first <see cref="BoxShadow"/> to compare.</param>
/// <param name="right">The second <see cref="BoxShadow"/> to compare.</param>
/// <returns>
/// <c>true</c> if the two <see cref="BoxShadow"/> values are equal; otherwise, <c>false</c>.
/// </returns>
public static bool operator ==(BoxShadow left, BoxShadow right) =>
left.Equals(right);
/// <summary>
/// Determines whether two <see cref="BoxShadow"/> values are not equal.
/// </summary>
/// <param name="left">The first <see cref="BoxShadow"/> to compare.</param>
/// <param name="right">The second <see cref="BoxShadow"/> to compare.</param>
/// <returns>
/// <c>true</c> if the two <see cref="BoxShadow"/> values are not equal; otherwise, <c>false</c>.
/// </returns>
public static bool operator !=(BoxShadow left, BoxShadow right) =>
!(left == right);
}

118
src/Avalonia.Base/Media/BoxShadows.cs

@ -1,16 +1,28 @@
using System;
using System.ComponentModel;
using Avalonia.Animation.Animators;
using Avalonia.Utilities;
namespace Avalonia.Media
{
/// <summary>
/// Represents a collection of <see cref="BoxShadow"/>s.
/// </summary>
public struct BoxShadows
{
private static readonly char[] s_Separators = new[] { ',' };
private readonly BoxShadow _first;
private readonly BoxShadow[]? _list;
/// <summary>
/// Gets the number of <see cref="BoxShadow"/>s in the collection.
/// </summary>
public int Count { get; }
/// <summary>
/// Initializes a new instance of the <see cref="BoxShadows"/> struct.
/// </summary>
/// <param name="shadow">The first <see cref="BoxShadow"/> to add to the collection.</param>
public BoxShadows(BoxShadow shadow)
{
_first = shadow;
@ -18,6 +30,11 @@ namespace Avalonia.Media
Count = _first == default ? 0 : 1;
}
/// <summary>
/// Initializes a new instance of the <see cref="BoxShadows"/> struct.
/// </summary>
/// <param name="first">The first <see cref="BoxShadow"/> to add to the collection.</param>
/// <param name="rest">All remaining <see cref="BoxShadow"/>s to add to the collection.</param>
public BoxShadows(BoxShadow first, BoxShadow[] rest)
{
_first = first;
@ -25,18 +42,33 @@ namespace Avalonia.Media
Count = 1 + (rest?.Length ?? 0);
}
public BoxShadow this[int c]
/// <summary>
/// Gets the <see cref="BoxShadow"/> at the specified index.
/// </summary>
/// <param name="index">The index of the <see cref="BoxShadow"/> to return.</param>
/// <returns>The <see cref="BoxShadow"/> at the specified index.</returns>
/// <exception cref="IndexOutOfRangeException">
/// Thrown when index less than 0 or index greater than or equal to <see cref="Count"/>.
/// </exception>
public BoxShadow this[int index]
{
get
{
if (c< 0 || c >= Count)
if (index < 0 || index >= Count)
{
throw new IndexOutOfRangeException();
if (c == 0)
}
if (index == 0)
{
return _first;
return _list![c - 1];
}
return _list![index - 1];
}
}
/// <inheritdoc/>
public override string ToString()
{
if (Count == 0)
@ -81,7 +113,11 @@ namespace Avalonia.Media
[EditorBrowsable(EditorBrowsableState.Never)]
public BoxShadowsEnumerator GetEnumerator() => new BoxShadowsEnumerator(this);
private static readonly char[] s_Separators = new[] { ',' };
/// <summary>
/// Parses a <see cref="BoxShadows"/> string representing one or more <see cref="BoxShadow"/>s.
/// </summary>
/// <param name="s">The input string to parse.</param>
/// <returns>A new <see cref="BoxShadows"/> collection.</returns>
public static BoxShadows Parse(string s)
{
var sp = s.Split(s_Separators, StringSplitOptions.RemoveEmptyEntries);
@ -89,66 +125,128 @@ namespace Avalonia.Media
|| (sp.Length == 1 &&
(string.IsNullOrWhiteSpace(sp[0])
|| sp[0] == "none")))
{
return new BoxShadows();
}
var first = BoxShadow.Parse(sp[0]);
if (sp.Length == 1)
{
return new BoxShadows(first);
}
var rest = new BoxShadow[sp.Length - 1];
for (var c = 0; c < rest.Length; c++)
{
rest[c] = BoxShadow.Parse(sp[c + 1]);
}
return new BoxShadows(first, rest);
}
/// <summary>
/// Transforms the specified bounding rectangle to account for all shadow's offset, spread, and blur.
/// </summary>
/// <param name="rect">The original bounding <see cref="Rect"/> to transform.</param>
/// <returns>
/// A new <see cref="Rect"/> that includes all shadow's offset, spread, and blur in the collection.
/// </returns>
public Rect TransformBounds(in Rect rect)
{
var final = rect;
foreach (var shadow in this)
{
final = final.Union(shadow.TransformBounds(rect));
}
return final;
}
/// <summary>
/// Gets a value indicating whether any <see cref="BoxShadow"/> in the collection has
/// <see cref="BoxShadow.IsInset"/> set to <c>true</c>.
/// </summary>
public bool HasInsetShadows
{
get
{
foreach(var boxShadow in this)
{
if (boxShadow != default && boxShadow.IsInset)
{
return true;
}
}
return false;
}
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// <c>true</c> if the current object is equal to the other parameter; otherwise, <c>false</c>.
/// </returns>
public bool Equals(BoxShadows other)
{
if (other.Count != Count)
{
return false;
for(var c=0; c<Count ; c++)
}
for (var c = 0; c < Count; c++)
{
if (!this[c].Equals(other[c]))
{
return false;
}
}
return true;
}
/// <inheritdoc/>
public override bool Equals(object? obj)
{
return obj is BoxShadows other && Equals(other);
}
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
int hashCode = 0;
foreach (var s in this)
{
hashCode = (hashCode * 397) ^ s.GetHashCode();
}
return hashCode;
}
}
/// <summary>
/// Determines whether two <see cref="BoxShadows"/> collections are equal.
/// </summary>
/// <param name="left">The first <see cref="BoxShadows"/> collection to compare.</param>
/// <param name="right">The second <see cref="BoxShadows"/> collection to compare.</param>
/// <returns>
/// <c>true</c> if the two <see cref="BoxShadows"/> collections are equal; otherwise, <c>false</c>.
/// </returns>
public static bool operator ==(BoxShadows left, BoxShadows right) =>
left.Equals(right);
/// <summary>
/// Determines whether two <see cref="BoxShadows"/> collections are not equal.
/// </summary>
/// <param name="left">The first <see cref="BoxShadows"/> collection to compare.</param>
/// <param name="right">The second <see cref="BoxShadows"/> collection to compare.</param>
/// <returns>
/// <c>true</c> if the two <see cref="BoxShadows"/> collections are not equal; otherwise, <c>false</c>.
/// </returns>
public static bool operator !=(BoxShadows left, BoxShadows right) =>
!(left == right);
}

Loading…
Cancel
Save