Browse Source

Initial implementation of Descendent selector.

pull/4/head
Steven Kirk 12 years ago
parent
commit
afdc1e0c42
  1. 20
      Perspex.UnitTests/Styling/SelectorTests_Descendent.cs
  2. 24
      Perspex/Styling/Selector.cs
  3. 50
      Perspex/Styling/Selectors.cs

20
Perspex.UnitTests/Styling/SelectorTests_Descendent.cs

@ -23,10 +23,7 @@ namespace Perspex.UnitTests.Styling
var parent = new Mock<TestLogical1>(); var parent = new Mock<TestLogical1>();
var child = new Mock<TestLogical2>(); var child = new Mock<TestLogical2>();
parent.Setup(x => x.LogicalChildren).Returns(new[] child.Setup(x => x.LogicalParent).Returns(parent.Object);
{
child.Object,
});
var selector = new Selector().OfType<TestLogical1>().Descendent().OfType<TestLogical2>(); var selector = new Selector().OfType<TestLogical1>().Descendent().OfType<TestLogical2>();
@ -36,7 +33,16 @@ namespace Perspex.UnitTests.Styling
[TestMethod] [TestMethod]
public void Descendent_Matches_Control_When_It_Is_Descendent_OfType() public void Descendent_Matches_Control_When_It_Is_Descendent_OfType()
{ {
Assert.Fail(); var grandparent = new Mock<TestLogical1>();
var parent = new Mock<TestLogical2>();
var child = new Mock<TestLogical3>();
parent.Setup(x => x.LogicalParent).Returns(grandparent.Object);
child.Setup(x => x.LogicalParent).Returns(parent.Object);
var selector = new Selector().OfType<TestLogical1>().Descendent().OfType<TestLogical3>();
Assert.AreEqual(true, ActivatorValue(selector, child.Object));
} }
private static bool ActivatorValue(Match selector, IStyleable control) private static bool ActivatorValue(Match selector, IStyleable control)
@ -51,5 +57,9 @@ namespace Perspex.UnitTests.Styling
public abstract class TestLogical2 : TestLogical public abstract class TestLogical2 : TestLogical
{ {
} }
public abstract class TestLogical3 : TestLogical
{
}
} }
} }

24
Perspex/Styling/Selector.cs

@ -15,15 +15,18 @@ namespace Perspex.Styling
public class Selector public class Selector
{ {
private bool stopTraversal;
private Func<IStyleable, IObservable<bool>> observable; private Func<IStyleable, IObservable<bool>> observable;
public Selector() public Selector()
{ {
} }
public Selector(Selector previous) public Selector(Selector previous, bool stopTraversal = false)
{ {
this.Previous = previous; this.Previous = previous;
this.stopTraversal = stopTraversal;
} }
public Func<IStyleable, IObservable<bool>> Observable public Func<IStyleable, IObservable<bool>> Observable
@ -42,7 +45,7 @@ namespace Perspex.Styling
public Selector Previous public Selector Previous
{ {
get; get;
set; private set;
} }
public string SelectorString public string SelectorString
@ -51,6 +54,11 @@ namespace Perspex.Styling
set; set;
} }
public Selector MovePrevious()
{
return this.stopTraversal ? null : this.Previous;
}
public Activator GetActivator(IStyleable control) public Activator GetActivator(IStyleable control)
{ {
List<IObservable<bool>> inputs = new List<IObservable<bool>>(); List<IObservable<bool>> inputs = new List<IObservable<bool>>();
@ -63,7 +71,7 @@ namespace Perspex.Styling
inputs.Add(selector.Observable(control)); inputs.Add(selector.Observable(control));
} }
selector = selector.Previous; selector = selector.MovePrevious();
} }
return new Activator(inputs); return new Activator(inputs);
@ -71,16 +79,14 @@ namespace Perspex.Styling
public override string ToString() public override string ToString()
{ {
Selector match = this; string result = string.Empty;
StringBuilder b = new StringBuilder();
while (match != null) if (this.Previous != null)
{ {
b.Append(match.SelectorString); result = this.Previous.ToString();
match = match.Previous;
} }
return b.ToString(); return result + this.SelectorString;
} }
} }
} }

50
Perspex/Styling/Selectors.cs

@ -7,17 +7,18 @@
namespace Perspex.Styling namespace Perspex.Styling
{ {
using System; using System;
using System.Collections.Generic;
using System.Reactive.Linq; using System.Reactive.Linq;
using Perspex.Controls; using Perspex.Controls;
public static class Selectors public static class Selectors
{ {
public static Selector Class(this Selector match, string name) public static Selector Class(this Selector previous, string name)
{ {
Contract.Requires<ArgumentNullException>(match != null); Contract.Requires<ArgumentNullException>(previous != null);
Contract.Requires<ArgumentNullException>(name != null); Contract.Requires<ArgumentNullException>(name != null);
return new Selector(match) return new Selector(previous)
{ {
Observable = control => Observable Observable = control => Observable
.Return(control.Classes.Contains(name)) .Return(control.Classes.Contains(name))
@ -26,39 +27,60 @@ namespace Perspex.Styling
}; };
} }
public static Selector Descendent(this Selector match) public static Selector Descendent(this Selector previous)
{ {
throw new NotImplementedException(); return new Selector(previous, stopTraversal: true)
{
SelectorString = " ",
Observable = control =>
{
ILogical c = (ILogical)control;
List<IObservable<bool>> descendentMatches = new List<IObservable<bool>>();
while (c != null)
{
c = c.LogicalParent;
if (c is IStyleable)
{
descendentMatches.Add(previous.Observable((IStyleable)c));
}
}
return new Activator(descendentMatches, ActivatorMode.Or);
},
};
} }
public static Selector Id(this Selector match, string id) public static Selector Id(this Selector previous, string id)
{ {
Contract.Requires<ArgumentNullException>(match != null); Contract.Requires<ArgumentNullException>(previous != null);
return new Selector(match) return new Selector(previous)
{ {
Observable = control => Observable.Return(control.Id == id), Observable = control => Observable.Return(control.Id == id),
SelectorString = '#' + id, SelectorString = '#' + id,
}; };
} }
public static Selector OfType<T>(this Selector match) where T : IStyleable public static Selector OfType<T>(this Selector previous) where T : IStyleable
{ {
Contract.Requires<ArgumentNullException>(match != null); Contract.Requires<ArgumentNullException>(previous != null);
return new Selector(match) return new Selector(previous)
{ {
Observable = control => Observable.Return(control is T), Observable = control => Observable.Return(control is T),
SelectorString = typeof(T).Name, SelectorString = typeof(T).Name,
}; };
} }
public static Selector Template(this Selector match) public static Selector Template(this Selector previous)
{ {
Contract.Requires<ArgumentNullException>(match != null); Contract.Requires<ArgumentNullException>(previous != null);
return new Selector(match) return new Selector(previous)
{ {
Observable = control => Observable.Return(control.TemplatedParent != null),
SelectorString = " $ ", SelectorString = " $ ",
}; };
} }

Loading…
Cancel
Save