Browse Source

Merge remote-tracking branch 'origin/master' into features/managed-notifications

pull/2453/head
Dan Walmsley 7 years ago
parent
commit
f222830bdc
  1. 4
      samples/ControlCatalog/SideBar.xaml
  2. 10
      src/Avalonia.Themes.Default/TabItem.xaml
  3. 110
      src/Avalonia.Visuals/Media/FontFamily.cs
  4. 35
      src/Avalonia.Visuals/Media/Fonts/FamilyNameCollection.cs
  5. 2
      src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs
  6. 48
      tests/Avalonia.Visuals.UnitTests/Media/FontFamilyTests.cs
  7. 11
      tests/Avalonia.Visuals.UnitTests/Media/Fonts/FamilyNameCollectionTests.cs

4
samples/ControlCatalog/SideBar.xaml

@ -63,13 +63,13 @@
<Style Selector="TabControl.sidebar > TabItem:pointerover">
<Setter Property="Opacity" Value="1"/>
</Style>
<Style Selector="TabControl.sidebar > TabItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Style Selector="TabControl.sidebar > TabItem:pointerover">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="TabControl.sidebar > TabItem:selected">
<Setter Property="Opacity" Value="1"/>
</Style>
<Style Selector="TabControl.sidebar > TabItem:selected /template/ ContentPresenter#PART_ContentPresenter">
<Style Selector="TabControl.sidebar > TabItem:selected">
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}"/>
</Style>
</Styles>

10
src/Avalonia.Themes.Default/TabItem.xaml

@ -24,19 +24,19 @@
<Style Selector="TabItem:disabled">
<Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
</Style>
<Style Selector="TabItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Style Selector="TabItem:pointerover">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
</Style>
<Style Selector="TabItem:selected /template/ ContentPresenter#PART_ContentPresenter">
<Style Selector="TabItem:selected">
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
</Style>
<Style Selector="TabItem:selected:focus /template/ ContentPresenter#PART_ContentPresenter">
<Style Selector="TabItem:selected:focus">
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush3}"/>
</Style>
<Style Selector="TabItem:selected:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Style Selector="TabItem:selected:pointerover">
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush3}"/>
</Style>
<Style Selector="TabItem:selected:focus:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Style Selector="TabItem:selected:focus:pointerover">
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}"/>
</Style>
<Style Selector="TabItem[TabStripPlacement=Right]">

110
src/Avalonia.Visuals/Media/FontFamily.cs

@ -11,46 +11,49 @@ namespace Avalonia.Media
{
public class FontFamily
{
/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="T:Avalonia.Media.FontFamily" /> class.
/// </summary>
/// <param name="name">The name of the <see cref="FontFamily"/>.</param>
/// <exception cref="T:System.ArgumentNullException">name</exception>
public FontFamily(string name)
/// <param name="name">The name of the <see cref="T:Avalonia.Media.FontFamily" />.</param>
public FontFamily(string name) : this(null, name)
{
Contract.Requires<ArgumentNullException>(name != null);
FamilyNames = new FamilyNameCollection(new[] { name });
}
/// <summary>
/// Initializes a new instance of the <see cref="T:Avalonia.Media.FontFamily" /> class.
/// </summary>
/// <param name="names">The names of the <see cref="FontFamily"/>.</param>
/// <exception cref="T:System.ArgumentNullException">name</exception>
public FontFamily(IEnumerable<string> names)
/// <param name="baseUri">Specifies the base uri that is used to resolve font family assets.</param>
/// <param name="name">The name of the <see cref="T:Avalonia.Media.FontFamily" />.</param>
/// <exception cref="T:System.ArgumentException">Base uri must be an absolute uri.</exception>
public FontFamily(Uri baseUri, string name)
{
Contract.Requires<ArgumentNullException>(names != null);
if (string.IsNullOrEmpty(name))
{
FamilyNames = new FamilyNameCollection(string.Empty);
FamilyNames = new FamilyNameCollection(names);
}
return;
}
/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="T:Avalonia.Media.FontFamily" /> class.
/// </summary>
/// <param name="name">The name of the <see cref="T:Avalonia.Media.FontFamily" />.</param>
/// <param name="source">The source of font resources.</param>
/// <param name="baseUri"></param>
public FontFamily(string name, Uri source, Uri baseUri = null) : this(name)
{
Key = new FontFamilyKey(source, baseUri);
var fontFamilySegment = GetFontFamilyIdentifier(name);
if (fontFamilySegment.Source != null)
{
if (baseUri != null && !baseUri.IsAbsoluteUri)
{
throw new ArgumentException("Base uri must be an absolute uri.", nameof(baseUri));
}
Key = new FontFamilyKey(fontFamilySegment.Source, baseUri);
}
FamilyNames = new FamilyNameCollection(fontFamilySegment.Name);
}
/// <summary>
/// Represents the default font family
/// </summary>
public static FontFamily Default => new FontFamily(String.Empty);
public static FontFamily Default => new FontFamily(string.Empty);
/// <summary>
/// Represents all font families in the system. This can be an expensive call depending on platform implementation.
@ -88,46 +91,40 @@ namespace Avalonia.Media
/// <param name="s"></param>
public static implicit operator FontFamily(string s)
{
return Parse(s);
return new FontFamily(s);
}
/// <summary>
/// Parses a <see cref="T:Avalonia.Media.FontFamily"/> string.
/// </summary>
/// <param name="s">The <see cref="T:Avalonia.Media.FontFamily"/> string.</param>
/// <param name="baseUri"></param>
/// <returns></returns>
/// <exception cref="ArgumentException">
/// Specified family is not supported.
/// </exception>
public static FontFamily Parse(string s, Uri baseUri = null)
private struct FontFamilyIdentifier
{
if (string.IsNullOrEmpty(s))
public FontFamilyIdentifier(string name, Uri source)
{
throw new ArgumentException("Specified family is not supported.");
Name = name;
Source = source;
}
var segments = s.Split('#');
public string Name { get; }
public Uri Source { get; }
}
private static FontFamilyIdentifier GetFontFamilyIdentifier(string name)
{
var segments = name.Split('#');
switch (segments.Length)
{
case 1:
{
var names = segments[0].Split(',')
.Select(x => x.Trim())
.Where(x => !string.IsNullOrWhiteSpace(x));
return new FontFamily(names);
return new FontFamilyIdentifier(segments[0], null);
}
case 2:
{
var uri = segments[0].StartsWith("/")
? new Uri(segments[0], UriKind.Relative)
: new Uri(segments[0], UriKind.RelativeOrAbsolute);
var source = segments[0].StartsWith("/")
? new Uri(segments[0], UriKind.Relative)
: new Uri(segments[0], UriKind.RelativeOrAbsolute);
return uri.IsAbsoluteUri
? new FontFamily(segments[1], uri)
: new FontFamily(segments[1], uri, baseUri);
return new FontFamilyIdentifier(segments[1], source);
}
default:
@ -137,6 +134,25 @@ namespace Avalonia.Media
}
}
/// <summary>
/// Parses a <see cref="T:Avalonia.Media.FontFamily"/> string.
/// </summary>
/// <param name="s">The <see cref="T:Avalonia.Media.FontFamily"/> string.</param>
/// <param name="baseUri">Specifies the base uri that is used to resolve font family assets.</param>
/// <returns></returns>
/// <exception cref="ArgumentException">
/// Specified family is not supported.
/// </exception>
public static FontFamily Parse(string s, Uri baseUri = null)
{
if (string.IsNullOrEmpty(s))
{
throw new ArgumentException("Specified family is not supported.", nameof(s));
}
return new FontFamily(baseUri, s);
}
/// <summary>
/// Returns a <see cref="string" /> that represents this instance.
/// </summary>

35
src/Avalonia.Visuals/Media/Fonts/FamilyNameCollection.cs

@ -4,31 +4,28 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
namespace Avalonia.Media.Fonts
{
using System.Text;
public class FamilyNameCollection : IEnumerable<string>
{
{
/// <summary>
/// Initializes a new instance of the <see cref="FamilyNameCollection"/> class.
/// </summary>
/// <param name="familyNames">The family names.</param>
/// <exception cref="ArgumentException">familyNames</exception>
public FamilyNameCollection(IEnumerable<string> familyNames)
public FamilyNameCollection(string familyNames)
{
Contract.Requires<ArgumentNullException>(familyNames != null);
var names = new List<string>(familyNames);
if (names.Count == 0) throw new ArgumentException($"{nameof(familyNames)} must not be empty.");
if (familyNames == null)
{
throw new ArgumentNullException(nameof(familyNames));
}
Names = new ReadOnlyCollection<string>(names);
Names = familyNames.Split(',').Select(x => x.Trim()).ToArray();
PrimaryFamilyName = Names.First();
PrimaryFamilyName = Names[0];
HasFallbacks = Names.Count > 1;
}
@ -55,7 +52,7 @@ namespace Avalonia.Media.Fonts
/// <value>
/// The names.
/// </value>
internal ReadOnlyCollection<string> Names { get; }
internal IReadOnlyList<string> Names { get; }
/// <inheritdoc />
/// <summary>
@ -95,7 +92,10 @@ namespace Avalonia.Media.Fonts
{
builder.Append(Names[index]);
if (index == Names.Count - 1) break;
if (index == Names.Count - 1)
{
break;
}
builder.Append(", ");
}
@ -123,9 +123,12 @@ namespace Avalonia.Media.Fonts
/// </returns>
public override bool Equals(object obj)
{
if (!(obj is FamilyNameCollection other)) return false;
if (!(obj is FamilyNameCollection other))
{
return false;
}
return other.ToString().Equals(ToString());
}
}
}
}

2
src/Avalonia.Visuals/Media/Fonts/FontFamilyKey.cs

@ -95,7 +95,7 @@ namespace Avalonia.Media.Fonts
{
if (!Source.IsAbsoluteUri && BaseUri != null)
{
return BaseUri.Authority + Source;
return BaseUri.AbsoluteUri + Source.OriginalString;
}
return Source.ToString();

48
tests/Avalonia.Visuals.UnitTests/Media/FontFamilyTests.cs

@ -2,7 +2,6 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Media;
using Avalonia.Media.Fonts;
@ -12,18 +11,6 @@ namespace Avalonia.Visuals.UnitTests.Media
{
public class FontFamilyTests
{
[Fact]
public void Exception_Should_Be_Thrown_If_Name_Is_Null()
{
Assert.Throws<ArgumentNullException>(() => new FontFamily((string)null));
}
[Fact]
public void Exception_Should_Be_Thrown_If_Names_Is_Null()
{
Assert.Throws<ArgumentNullException>(() => new FontFamily((IEnumerable<string>)null));
}
[Fact]
public void Should_Implicitly_Convert_String_To_FontFamily()
{
@ -41,7 +28,7 @@ namespace Avalonia.Visuals.UnitTests.Media
}
[Fact]
public void Parse_Parses_FontFamily_With_Name()
public void Should_Parse_FontFamily_With_SystemFont_Name()
{
var fontFamily = FontFamily.Parse("Courier New");
@ -49,7 +36,7 @@ namespace Avalonia.Visuals.UnitTests.Media
}
[Fact]
public void Parse_Parses_FontFamily_With_Names()
public void Should_Parse_FontFamily_With_Fallbacks()
{
var fontFamily = FontFamily.Parse("Courier New, Times New Roman");
@ -61,7 +48,7 @@ namespace Avalonia.Visuals.UnitTests.Media
}
[Fact]
public void Parse_Parses_FontFamily_With_Resource_Folder()
public void Should_Parse_FontFamily_With_Resource_Folder()
{
var source = new Uri("resm:Avalonia.Visuals.UnitTests#MyFont");
@ -75,7 +62,7 @@ namespace Avalonia.Visuals.UnitTests.Media
}
[Fact]
public void Parse_Parses_FontFamily_With_Resource_Filename()
public void Should_Parse_FontFamily_With_Resource_Filename()
{
var source = new Uri("resm:Avalonia.Visuals.UnitTests.MyFont.ttf#MyFont");
@ -87,5 +74,32 @@ namespace Avalonia.Visuals.UnitTests.Media
Assert.Equal(key, fontFamily.Key);
}
[Theory]
[InlineData("resm:Avalonia.Visuals.UnitTests/Assets/Fonts#MyFont")]
[InlineData("avares://Avalonia.Visuals.UnitTests/Assets/Fonts#MyFont")]
public void Should_Create_FontFamily_From_Uri(string name)
{
var fontFamily = new FontFamily(name);
Assert.Equal("MyFont", fontFamily.Name);
Assert.NotNull(fontFamily.Key);
}
[Theory]
[InlineData("resm:Avalonia.Visuals.UnitTests.Assets.Fonts", "#MyFont")]
[InlineData("avares://Avalonia.Visuals.UnitTests/Assets/Fonts", "#MyFont")]
[InlineData("avares://Avalonia.Visuals.UnitTests", "/Assets/Fonts#MyFont")]
public void Should_Create_FontFamily_From_Uri_With_Base_Uri(string @base, string name)
{
var baseUri = new Uri(@base);
var fontFamily = new FontFamily(baseUri, name);
Assert.Equal("MyFont", fontFamily.Name);
Assert.NotNull(fontFamily.Key);
}
}
}

11
tests/Avalonia.Visuals.UnitTests/Media/Fonts/FamilyNameCollectionTests.cs

@ -2,7 +2,6 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Linq;
using Avalonia.Media.Fonts;
using Xunit;
@ -16,18 +15,12 @@ namespace Avalonia.Visuals.UnitTests.Media.Fonts
Assert.Throws<ArgumentNullException>(() => new FamilyNameCollection(null));
}
[Fact]
public void Exception_Should_Be_Thrown_If_Names_Is_Empty()
{
Assert.Throws<ArgumentException>(() => new FamilyNameCollection(Enumerable.Empty<string>()));
}
[Fact]
public void Should_Be_Equal()
{
var familyNames = new FamilyNameCollection(new[] { "Arial", "Times New Roman" });
var familyNames = new FamilyNameCollection("Arial, Times New Roman");
Assert.Equal(new FamilyNameCollection(new[] { "Arial", "Times New Roman" }), familyNames);
Assert.Equal(new FamilyNameCollection("Arial, Times New Roman"), familyNames);
}
}
}

Loading…
Cancel
Save