Browse Source

Style away the hours.

pull/4/head
grokys 12 years ago
parent
commit
ac659701b8
  1. 115
      Perspex.UnitTests/Styling/SelectorTests.cs
  2. 17
      Perspex.UnitTests/Styling/SubscribeCheck.cs
  3. 40
      Perspex/ControlTemplate.cs
  4. 31
      Perspex/Controls/Control.cs
  5. 10
      Perspex/Styling/IStyleable.cs
  6. 6
      Perspex/Styling/Match.cs
  7. 31
      Perspex/Styling/Selectors.cs
  8. 25
      Perspex/Visual.cs

115
Perspex.UnitTests/Styling/SelectorTests.cs

@ -17,11 +17,106 @@ namespace Perspex.UnitTests.Styling
[TestClass]
public class SelectorTests
{
[TestMethod]
public void Class_Matches_Control_With_Class()
{
var control = new Control1
{
Classes = new Classes { "foo" },
};
var target = control.Select().Class("foo");
CollectionAssert.AreEqual(new[] { true }, target.GetActivator().Take(1).ToEnumerable().ToArray());
}
[TestMethod]
public void Class_Doesnt_Match_Control_Without_Class()
{
var control = new Control1
{
Classes = new Classes { "bar" },
};
var target = control.Select().Class("foo");
CollectionAssert.AreEqual(new[] { false }, target.GetActivator().Take(1).ToEnumerable().ToArray());
}
[TestMethod]
public void Class_Tracks_Additions()
{
var control = new Control1();
var target = control.Select().Class("foo");
var activator = target.GetActivator();
CollectionAssert.AreEqual(new[] { false }, activator.Take(1).ToEnumerable().ToArray());
control.Classes.Add("foo");
CollectionAssert.AreEqual(new[] { true }, activator.Take(1).ToEnumerable().ToArray());
}
[TestMethod]
public void Class_Tracks_Removals()
{
var control = new Control1
{
Classes = new Classes { "foo" },
};
var target = control.Select().Class("foo");
var activator = target.GetActivator();
CollectionAssert.AreEqual(new[] { true }, activator.Take(1).ToEnumerable().ToArray());
control.Classes.Remove("foo");
CollectionAssert.AreEqual(new[] { false }, activator.Take(1).ToEnumerable().ToArray());
}
[TestMethod]
public void Id_Matches_Control_With_Correct_Id()
{
var control = new Control1 { Id = "foo" };
var target = control.Select().Id("foo");
CollectionAssert.AreEqual(new[] { true }, target.GetActivator().Take(1).ToEnumerable().ToArray());
}
[TestMethod]
public void Id_Doesnt_Match_Control_Of_Wrong_Id()
{
var control = new Control1 { Id = "foo" };
var target = control.Select().Id("bar");
CollectionAssert.AreEqual(new[] { false }, target.GetActivator().Take(1).ToEnumerable().ToArray());
}
[TestMethod]
public void When_Id_Matches_Control_Other_Selectors_Are_Subscribed()
{
var control = new Control1 { Id = "foo" };
var target = control.Select().Id("foo").SubscribeCheck();
var result = target.GetActivator().ToEnumerable().Take(1).ToArray();
Assert.AreEqual(1, control.SubscribeCheckObservable.SubscribedCount);
}
[TestMethod]
public void When_Id_Doesnt_Match_Control_Other_Selectors_Are_Not_Subscribed()
{
var control = new Control1 { Id = "foo" };
var target = control.Select().Id("bar").SubscribeCheck();
var result = target.GetActivator().ToEnumerable().Take(1).ToArray();
Assert.AreEqual(0, control.SubscribeCheckObservable.SubscribedCount);
}
[TestMethod]
public void OfType_Matches_Control_Of_Correct_Type()
{
var control = new Class1();
var target = control.Select().OfType<Class1>();
var control = new Control1();
var target = control.Select().OfType<Control1>();
CollectionAssert.AreEqual(new[] { true }, target.GetActivator().Take(1).ToEnumerable().ToArray());
}
@ -29,8 +124,8 @@ namespace Perspex.UnitTests.Styling
[TestMethod]
public void OfType_Doesnt_Match_Control_Of_Wrong_Type()
{
var control = new Class2();
var target = control.Select().OfType<Class1>();
var control = new Control2();
var target = control.Select().OfType<Control1>();
CollectionAssert.AreEqual(new[] { false }, target.GetActivator().Take(1).ToEnumerable().ToArray());
}
@ -38,8 +133,8 @@ namespace Perspex.UnitTests.Styling
[TestMethod]
public void When_OfType_Matches_Control_Other_Selectors_Are_Subscribed()
{
var control = new Class1();
var target = control.Select().OfType<Class1>().SubscribeCheck();
var control = new Control1();
var target = control.Select().OfType<Control1>().SubscribeCheck();
var result = target.GetActivator().ToEnumerable().Take(1).ToArray();
@ -49,19 +144,19 @@ namespace Perspex.UnitTests.Styling
[TestMethod]
public void When_OfType_Doesnt_Match_Control_Other_Selectors_Are_Not_Subscribed()
{
var control = new Class1();
var target = control.Select().OfType<Class2>().SubscribeCheck();
var control = new Control1();
var target = control.Select().OfType<Control2>().SubscribeCheck();
var result = target.GetActivator().ToEnumerable().Take(1).ToArray();
Assert.AreEqual(0, control.SubscribeCheckObservable.SubscribedCount);
}
public class Class1 : SubscribeCheck
public class Control1 : SubscribeCheck
{
}
public class Class2 : SubscribeCheck
public class Control2 : SubscribeCheck
{
}
}

17
Perspex.UnitTests/Styling/SubscribeCheck.cs

@ -8,6 +8,7 @@ namespace Perspex.UnitTests.Styling
{
using System;
using System.Reactive.Disposables;
using Perspex.Controls;
using Perspex.Styling;
using Match = Perspex.Styling.Match;
@ -27,20 +28,20 @@ namespace Perspex.UnitTests.Styling
{
public SubscribeCheck()
{
this.Classes = Classes;
this.Classes = new Classes();
this.SubscribeCheckObservable = new TestObservable();
}
public Classes Classes
{
get;
private set;
}
public string Id { get; set; }
public Classes Classes { get; set; }
public TestObservable SubscribeCheckObservable { get; private set; }
public TestObservable SubscribeCheckObservable
public TemplatedControl TemplatedParent
{
get;
private set;
set;
}
public virtual void SetValue(PerspexProperty property, object value, IObservable<bool> activator)

40
Perspex/ControlTemplate.cs

@ -1,25 +1,55 @@
namespace Perspex
// -----------------------------------------------------------------------
// <copyright file="ControlTemplate.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex
{
using System;
using System.Diagnostics.Contracts;
using System.Linq;
using Perspex.Controls;
public class ControlTemplate
{
private Func<TemplatedControl, Control> build;
public ControlTemplate(Func<TemplatedControl, Control> build)
{
this.Build = build;
Contract.Requires<NullReferenceException>(build != null);
this.build = build;
}
public Func<TemplatedControl, Control> Build
public Control Build(TemplatedControl templatedParent)
{
get;
private set;
Contract.Requires<NullReferenceException>(templatedParent != null);
Control root = this.build(templatedParent);
this.SetTemplatedParent(root, templatedParent);
return root;
}
public static ControlTemplate Create<TControl>(Func<TControl, Control> build)
where TControl : TemplatedControl
{
Contract.Requires<NullReferenceException>(build != null);
return new ControlTemplate(c => build((TControl)c));
}
private void SetTemplatedParent(Control control, TemplatedControl templatedParent)
{
Contract.Requires<NullReferenceException>(control != null);
Contract.Requires<NullReferenceException>(templatedParent != null);
control.TemplatedParent = templatedParent;
foreach (Control child in control.VisualChildren.OfType<Control>())
{
this.SetTemplatedParent(child, templatedParent);
}
}
}
}

31
Perspex/Controls/Control.cs

@ -70,13 +70,15 @@ namespace Perspex.Controls
internal static readonly PerspexProperty<Control> ParentPropertyRW =
PerspexProperty.Register<Control, Control>("Parent");
private Classes classes;
private Styles styles;
public Control()
{
this.Classes = new Classes();
this.Classes.BeforeChanged.Subscribe(x => this.BeginDeferStyleChanges());
this.Classes.AfterChanged.Subscribe(x => this.EndDeferStyleChanges());
this.classes = new Classes();
this.classes.BeforeChanged.Subscribe(x => this.BeginDeferStyleChanges());
this.classes.AfterChanged.Subscribe(x => this.EndDeferStyleChanges());
this.GetObservableWithHistory(ParentPropertyRW).Subscribe(this.ParentChanged);
@ -145,8 +147,21 @@ namespace Perspex.Controls
public Classes Classes
{
get;
private set;
get
{
return this.classes;
}
set
{
if (this.classes != value)
{
this.BeginDeferStyleChanges();
this.classes.Clear();
this.classes.Add(value);
this.EndDeferStyleChanges();
}
}
}
public Brush Foreground
@ -203,6 +218,12 @@ namespace Perspex.Controls
}
}
public TemplatedControl TemplatedParent
{
get;
internal set;
}
public VerticalAlignment VerticalAlignment
{
get { return this.GetValue(VerticalAlignmentProperty); }

10
Perspex/Styling/IStyleable.cs

@ -19,6 +19,16 @@ namespace Perspex.Styling
/// </summary>
Classes Classes { get; }
/// <summary>
/// Gets the ID of the control.
/// </summary>
string Id { get; }
/// <summary>
/// Gets the template parent of this element if the control comes from a template.
/// </summary>
TemplatedControl TemplatedParent { get; }
/// <summary>
/// Binds a <see cref="PerspexProperty"/> to a style.
/// </summary>

6
Perspex/Styling/Match.cs

@ -26,6 +26,12 @@ namespace Perspex.Styling
private set;
}
public bool InTemplate
{
get;
set;
}
public List<IObservable<bool>> Observables
{
get;

31
Perspex/Styling/Selectors.cs

@ -38,6 +38,37 @@ namespace Perspex.Styling
return match;
}
public static Match Id(this Match match, string id)
{
Contract.Requires<ArgumentNullException>(match != null);
if (!match.InTemplate)
{
match.Observables.Add(Observable.Return(
match.Control.TemplatedParent == null &&
match.Control.Id == id));
}
else
{
match.Observables.Add(Observable.Return(
match.Control.TemplatedParent != null &&
match.Control.Id == id));
}
match.SelectorString += '#' + id;
return match;
}
public static Match InTemplateOf<T>(this Match match)
{
Contract.Requires<ArgumentNullException>(match != null);
match.Observables.Add(Observable.Return(match.Control.TemplatedParent is T));
match.InTemplate = true;
match.SelectorString += '%' + typeof(T).Name;
return match;
}
public static Match OfType<T>(this Match match)
{
Contract.Requires<ArgumentNullException>(match != null);

25
Perspex/Visual.cs

@ -14,6 +14,8 @@ namespace Perspex
public abstract class Visual : PerspexObject
{
private string id;
private Visual visualParent;
public Rect Bounds
@ -22,6 +24,29 @@ namespace Perspex
protected set;
}
public string Id
{
get
{
return this.id;
}
set
{
if (this.id != null)
{
throw new InvalidOperationException("ID already set.");
}
if (this.visualParent != null)
{
throw new InvalidOperationException("Cannot set ID : control already added to tree.");
}
this.id = value;
}
}
public virtual IEnumerable<Visual> VisualChildren
{
get { return Enumerable.Empty<Visual>(); }

Loading…
Cancel
Save