committed by
GitHub
31 changed files with 1202 additions and 156 deletions
@ -0,0 +1,131 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Avalonia.Styling |
|||
{ |
|||
/// <summary>
|
|||
/// The OR style selector.
|
|||
/// </summary>
|
|||
internal class OrSelector : Selector |
|||
{ |
|||
private readonly IReadOnlyList<Selector> _selectors; |
|||
private string _selectorString; |
|||
private Type _targetType; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="OrSelector"/> class.
|
|||
/// </summary>
|
|||
/// <param name="selectors">The selectors to OR.</param>
|
|||
public OrSelector(IReadOnlyList<Selector> selectors) |
|||
{ |
|||
Contract.Requires<ArgumentNullException>(selectors != null); |
|||
Contract.Requires<ArgumentException>(selectors.Count > 1); |
|||
|
|||
_selectors = selectors; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool InTemplate => false; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool IsCombinator => false; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override Type TargetType |
|||
{ |
|||
get |
|||
{ |
|||
if (_targetType == null) |
|||
{ |
|||
_targetType = EvaluateTargetType(); |
|||
} |
|||
|
|||
return _targetType; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
if (_selectorString == null) |
|||
{ |
|||
_selectorString = string.Join(", ", _selectors); |
|||
} |
|||
|
|||
return _selectorString; |
|||
} |
|||
|
|||
protected override SelectorMatch Evaluate(IStyleable control, bool subscribe) |
|||
{ |
|||
var activators = new List<IObservable<bool>>(); |
|||
var neverThisInstance = false; |
|||
|
|||
foreach (var selector in _selectors) |
|||
{ |
|||
var match = selector.Match(control, subscribe); |
|||
|
|||
switch (match.Result) |
|||
{ |
|||
case SelectorMatchResult.AlwaysThisType: |
|||
case SelectorMatchResult.AlwaysThisInstance: |
|||
return match; |
|||
case SelectorMatchResult.NeverThisInstance: |
|||
neverThisInstance = true; |
|||
break; |
|||
case SelectorMatchResult.Sometimes: |
|||
activators.Add(match.Activator); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (activators.Count > 1) |
|||
{ |
|||
return new SelectorMatch(StyleActivator.Or(activators)); |
|||
} |
|||
else if (activators.Count == 1) |
|||
{ |
|||
return new SelectorMatch(activators[0]); |
|||
} |
|||
else if (neverThisInstance) |
|||
{ |
|||
return SelectorMatch.NeverThisInstance; |
|||
} |
|||
else |
|||
{ |
|||
return SelectorMatch.NeverThisType; |
|||
} |
|||
} |
|||
|
|||
protected override Selector MovePrevious() => null; |
|||
|
|||
private Type EvaluateTargetType() |
|||
{ |
|||
var result = default(Type); |
|||
|
|||
foreach (var selector in _selectors) |
|||
{ |
|||
if (selector.TargetType == null) |
|||
{ |
|||
return null; |
|||
} |
|||
else if (result == null) |
|||
{ |
|||
result = selector.TargetType; |
|||
} |
|||
else |
|||
{ |
|||
while (!result.IsAssignableFrom(selector.TargetType)) |
|||
{ |
|||
result = result.BaseType; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,106 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Styling.UnitTests |
|||
{ |
|||
public class SelectorTests_Or |
|||
{ |
|||
[Fact] |
|||
public void Or_Selector_Should_Have_Correct_String_Representation() |
|||
{ |
|||
var target = Selectors.Or( |
|||
default(Selector).OfType<Control1>().Class("foo"), |
|||
default(Selector).OfType<Control2>().Class("bar")); |
|||
|
|||
Assert.Equal("Control1.foo, Control2.bar", target.ToString()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Or_Selector_Matches_Control_Of_Correct_Type() |
|||
{ |
|||
var target = Selectors.Or( |
|||
default(Selector).OfType<Control1>(), |
|||
default(Selector).OfType<Control2>().Class("bar")); |
|||
var control = new Control1(); |
|||
|
|||
Assert.Equal(SelectorMatchResult.AlwaysThisType, target.Match(control).Result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Or_Selector_Matches_Control_Of_Correct_Type_With_Class() |
|||
{ |
|||
var target = Selectors.Or( |
|||
default(Selector).OfType<Control1>(), |
|||
default(Selector).OfType<Control2>().Class("bar")); |
|||
var control = new Control2(); |
|||
|
|||
Assert.Equal(SelectorMatchResult.Sometimes, target.Match(control).Result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Or_Selector_Doesnt_Match_Control_Of_Incorrect_Type() |
|||
{ |
|||
var target = Selectors.Or( |
|||
default(Selector).OfType<Control1>(), |
|||
default(Selector).OfType<Control2>().Class("bar")); |
|||
var control = new Control3(); |
|||
|
|||
Assert.Equal(SelectorMatchResult.NeverThisType, target.Match(control).Result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Or_Selector_Doesnt_Match_Control_With_Incorrect_Name() |
|||
{ |
|||
var target = Selectors.Or( |
|||
default(Selector).OfType<Control1>().Name("foo"), |
|||
default(Selector).OfType<Control2>().Name("foo")); |
|||
var control = new Control1 { Name = "bar" }; |
|||
|
|||
Assert.Equal(SelectorMatchResult.NeverThisInstance, target.Match(control).Result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Returns_Correct_TargetType_When_Types_Same() |
|||
{ |
|||
var target = Selectors.Or( |
|||
default(Selector).OfType<Control1>().Class("foo"), |
|||
default(Selector).OfType<Control1>().Class("bar")); |
|||
|
|||
Assert.Equal(typeof(Control1), target.TargetType); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Returns_Common_TargetType() |
|||
{ |
|||
var target = Selectors.Or( |
|||
default(Selector).OfType<Control1>().Class("foo"), |
|||
default(Selector).OfType<Control2>().Class("bar")); |
|||
|
|||
Assert.Equal(typeof(TestControlBase), target.TargetType); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Returns_Null_TargetType_When_A_Selector_Has_No_TargetType() |
|||
{ |
|||
var target = Selectors.Or( |
|||
default(Selector).OfType<Control1>().Class("foo"), |
|||
default(Selector).Class("bar")); |
|||
|
|||
Assert.Equal(null, target.TargetType); |
|||
} |
|||
|
|||
public class Control1 : TestControlBase |
|||
{ |
|||
} |
|||
|
|||
public class Control2 : TestControlBase |
|||
{ |
|||
} |
|||
|
|||
public class Control3 : TestControlBase |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 610 B |
|
After Width: | Height: | Size: 610 B |
Loading…
Reference in new issue