Browse Source

add is-os selector

pull/7938/head
Emmanuel Hansen 3 years ago
parent
commit
4370484bd8
  1. 24
      samples/ControlCatalog/MainView.xaml
  2. 5
      src/Android/Avalonia.Android/Platform/AndroidMediaProvider.cs
  3. 1
      src/Avalonia.Base/Platform/IMediaProvider.cs
  4. 13
      src/Avalonia.Base/Platform/VisualMediaProvider.cs
  5. 14
      src/Avalonia.Base/Styling/Activators/DeviceActivator.cs
  6. 2
      src/Avalonia.Base/Styling/Activators/MediaQueryActivatorBase.cs
  7. 45
      src/Avalonia.Base/Styling/DeviceMediaSelector.cs
  8. 5
      src/Avalonia.Base/Styling/Selectors.cs
  9. 21
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs
  10. 24
      src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs
  11. 3
      src/Markup/Avalonia.Markup/Markup/Parsers/SelectorParser.cs

24
samples/ControlCatalog/MainView.xaml

@ -26,6 +26,25 @@
<Style Selector=":orientation(portrait) TextBlock#Portrait">
<Setter Property="Foreground" Value="Red" />
</Style>
<Style Selector=":is-os(windows) TextBlock#Windows">
<Setter Property="Foreground" Value="Red" />
</Style>
<Style Selector=":is-os(linux) TextBlock#Linux">
<Setter Property="Foreground"
Value="Red" />
</Style>
<Style Selector=":is-os(osx) TextBlock#OSX">
<Setter Property="Foreground"
Value="Red" />
</Style>
<Style Selector=":is-os(android) TextBlock#Android">
<Setter Property="Foreground"
Value="Red" />
</Style>
<Style Selector=":is-os(ios) TextBlock#iOS">
<Setter Property="Foreground"
Value="Red" />
</Style>
</Grid.Styles>
<StackPanel Spacing="10">
<TextBlock Name="MinWidth" Classes="h2" Text="min-width" />
@ -34,6 +53,11 @@
<TextBlock Name="MaxHeight" Classes="h2" Text="max-height" />
<TextBlock Name="Landscape" Classes="h2" Text="orientation(landscape)" />
<TextBlock Name="Portrait" Classes="h2" Text="orientation(portrait)" />
<TextBlock Name="Windows" Classes="h2" Text="is-os(windows)" />
<TextBlock Name="Linux" Classes="h2" Text="is-os(linux)" />
<TextBlock Name="OSX" Classes="h2" Text="is-os(osx)" />
<TextBlock Name="Android" Classes="h2" Text="is-os(android)" />
<TextBlock Name="iOS" Classes="h2" Text="is-os(ios)" />
</StackPanel>
</Grid>
</UserControl>

5
src/Android/Avalonia.Android/Platform/AndroidMediaProvider.cs

@ -51,5 +51,10 @@ namespace Avalonia.Android.Platform
_ => DeviceOrientation.Portrait,
};
}
public string GetPlatform()
{
return "android";
}
}
}

1
src/Avalonia.Base/Platform/IMediaProvider.cs

@ -4,6 +4,7 @@ namespace Avalonia.Platform
{
public interface IMediaProvider
{
string GetPlatform();
double GetScreenWidth();
double GetScreenHeight();

13
src/Avalonia.Base/Platform/VisualMediaProvider.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Reactive;
@ -53,5 +54,17 @@ namespace Avalonia.Platform
return DeviceOrientation.Square;
}
public string GetPlatform()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return "windows";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return "linux";
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return "osx";
return "";
}
}
}

14
src/Avalonia.Base/Styling/Activators/DeviceActivator.cs

@ -0,0 +1,14 @@
namespace Avalonia.Styling.Activators
{
internal sealed class IsOsActivator : MediaQueryActivatorBase
{
private readonly string _argument;
public IsOsActivator(Visual visual, string argument) : base(visual)
{
_argument = argument;
}
protected override bool EvaluateIsActive() => CurrentMediaInfoProvider != null && IsOsMediaSelector.Evaluate(CurrentMediaInfoProvider, _argument).IsMatch;
}
}

2
src/Avalonia.Base/Styling/Activators/MediaQueryActivatorBase.cs

@ -55,7 +55,7 @@ namespace Avalonia.Styling.Activators
ReevaluateIsActive();
}
private void OrientationChanged(object sender, EventArgs e)
private void OrientationChanged(object? sender, EventArgs e)
{
ReevaluateIsActive();
}

45
src/Avalonia.Base/Styling/DeviceMediaSelector.cs

@ -0,0 +1,45 @@
using System;
using Avalonia.Platform;
using Avalonia.Styling.Activators;
namespace Avalonia.Styling
{
internal sealed class IsOsMediaSelector : MediaSelector<string>
{
public IsOsMediaSelector(Selector? previous, string argument) : base(previous, argument)
{
}
private protected override SelectorMatch Evaluate(StyledElement control, IStyle? parent, bool subscribe)
{
if (!(control is Visual visual))
{
return SelectorMatch.NeverThisType;
}
if (subscribe)
{
return new SelectorMatch(new IsOsActivator(visual, Argument));
}
if (visual.VisualRoot is IMediaProviderHost mediaProviderHost && mediaProviderHost.MediaProvider is { } mediaProvider)
{
return Evaluate(mediaProvider, Argument);
}
return SelectorMatch.NeverThisInstance;
}
internal static SelectorMatch Evaluate(IMediaProvider mediaProvider, string argument)
{
return mediaProvider.GetPlatform() == argument ? SelectorMatch.AlwaysThisInstance : SelectorMatch.NeverThisInstance;
}
public override string ToString() => "is-os";
public override string ToString(Style? owner)
{
throw new NotImplementedException();
}
}
}

5
src/Avalonia.Base/Styling/Selectors.cs

@ -221,6 +221,11 @@ namespace Avalonia.Styling
{
return new OrientationMediaSelector(previous, (DeviceOrientation)argument);
}
public static Selector IsOs(this Selector? previous, string argument)
{
return new IsOsMediaSelector(previous, argument);
}
/// <summary>
/// Returns a selector which matches a control with the specified property value.

21
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs

@ -162,6 +162,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
case SelectorGrammar.OrientationSyntax orientation:
result = new XamlIlOrientationSelector(result, orientation.Argument);
break;
case SelectorGrammar.IsOsSyntax isOs:
result = new XamlIlIsOsSelector(result, isOs.Argument);
break;
case SelectorGrammar.CommaSyntax comma:
if (results == null)
results = new XamlIlOrSelectorNode(node, selectorType);
@ -490,6 +493,24 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
m => m.Name == "Orientation" && m.Parameters.Count == 2);
}
}
class XamlIlIsOsSelector : XamlIlSelectorNode
{
private string _argument;
public XamlIlIsOsSelector(XamlIlSelectorNode previous, string argument) : base(previous)
{
_argument = argument;
}
public override IXamlType TargetType => Previous?.TargetType;
protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
codeGen.Ldstr(_argument);
EmitCall(context, codeGen,
m => m.Name == "IsOs" && m.Parameters.Count == 2);
}
}
class XamlIlPropertyEqualsSelector : XamlIlSelectorNode
{

24
src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs

@ -183,6 +183,7 @@ namespace Avalonia.Markup.Parsers
const string NthChildKeyword = "nth-child";
const string NthLastChildKeyword = "nth-last-child";
const string OrientationKeyword = "orientation";
const string IsOsKeyword = "is-os";
if (identifier.SequenceEqual(IsKeyword.AsSpan()) && r.TakeIf('('))
{
@ -253,6 +254,14 @@ namespace Avalonia.Markup.Parsers
var syntax = new OrientationSyntax { Argument = argument };
return (State.Middle, syntax);
}
if (identifier.SequenceEqual(IsOsKeyword.AsSpan()) && r.TakeIf('('))
{
var argument = ParseString(ref r);
Expect(ref r, ')');
var syntax = new IsOsSyntax { Argument = argument };
return (State.Middle, syntax);
}
else
{
return (
@ -341,6 +350,11 @@ namespace Avalonia.Markup.Parsers
throw new ExpressionParseException(r.Position, $"Expected a {typeof(T)} after.");
}
private static string ParseString(ref CharacterReader r)
{
return r.ParseIdentifier().ToString();
}
private static (State, ISyntax) ParseTypeName(ref CharacterReader r)
{
@ -763,6 +777,16 @@ namespace Avalonia.Markup.Parsers
}
}
public class IsOsSyntax : ISyntax
{
public string Argument { get; set; } = string.Empty;
public override bool Equals(object? obj)
{
return (obj is IsOsSyntax orientation) && orientation.Argument == Argument;
}
}
public class CommaSyntax : ISyntax
{
public override bool Equals(object? obj)

3
src/Markup/Avalonia.Markup/Markup/Parsers/SelectorParser.cs

@ -173,6 +173,9 @@ namespace Avalonia.Markup.Parsers
case SelectorGrammar.OrientationSyntax orientation:
result = result.Orientation(orientation.Argument);
break;
case SelectorGrammar.IsOsSyntax isOs:
result = result.IsOs(isOs.Argument);
break;
case SelectorGrammar.CommaSyntax comma:
if (results == null)
{

Loading…
Cancel
Save