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] [TestClass]
public class SelectorTests 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] [TestMethod]
public void OfType_Matches_Control_Of_Correct_Type() public void OfType_Matches_Control_Of_Correct_Type()
{ {
var control = new Class1(); var control = new Control1();
var target = control.Select().OfType<Class1>(); var target = control.Select().OfType<Control1>();
CollectionAssert.AreEqual(new[] { true }, target.GetActivator().Take(1).ToEnumerable().ToArray()); CollectionAssert.AreEqual(new[] { true }, target.GetActivator().Take(1).ToEnumerable().ToArray());
} }
@ -29,8 +124,8 @@ namespace Perspex.UnitTests.Styling
[TestMethod] [TestMethod]
public void OfType_Doesnt_Match_Control_Of_Wrong_Type() public void OfType_Doesnt_Match_Control_Of_Wrong_Type()
{ {
var control = new Class2(); var control = new Control2();
var target = control.Select().OfType<Class1>(); var target = control.Select().OfType<Control1>();
CollectionAssert.AreEqual(new[] { false }, target.GetActivator().Take(1).ToEnumerable().ToArray()); CollectionAssert.AreEqual(new[] { false }, target.GetActivator().Take(1).ToEnumerable().ToArray());
} }
@ -38,8 +133,8 @@ namespace Perspex.UnitTests.Styling
[TestMethod] [TestMethod]
public void When_OfType_Matches_Control_Other_Selectors_Are_Subscribed() public void When_OfType_Matches_Control_Other_Selectors_Are_Subscribed()
{ {
var control = new Class1(); var control = new Control1();
var target = control.Select().OfType<Class1>().SubscribeCheck(); var target = control.Select().OfType<Control1>().SubscribeCheck();
var result = target.GetActivator().ToEnumerable().Take(1).ToArray(); var result = target.GetActivator().ToEnumerable().Take(1).ToArray();
@ -49,19 +144,19 @@ namespace Perspex.UnitTests.Styling
[TestMethod] [TestMethod]
public void When_OfType_Doesnt_Match_Control_Other_Selectors_Are_Not_Subscribed() public void When_OfType_Doesnt_Match_Control_Other_Selectors_Are_Not_Subscribed()
{ {
var control = new Class1(); var control = new Control1();
var target = control.Select().OfType<Class2>().SubscribeCheck(); var target = control.Select().OfType<Control2>().SubscribeCheck();
var result = target.GetActivator().ToEnumerable().Take(1).ToArray(); var result = target.GetActivator().ToEnumerable().Take(1).ToArray();
Assert.AreEqual(0, control.SubscribeCheckObservable.SubscribedCount); 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;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Perspex.Controls;
using Perspex.Styling; using Perspex.Styling;
using Match = Perspex.Styling.Match; using Match = Perspex.Styling.Match;
@ -27,20 +28,20 @@ namespace Perspex.UnitTests.Styling
{ {
public SubscribeCheck() public SubscribeCheck()
{ {
this.Classes = Classes; this.Classes = new Classes();
this.SubscribeCheckObservable = new TestObservable(); this.SubscribeCheckObservable = new TestObservable();
} }
public Classes Classes public string Id { get; set; }
{
get; public Classes Classes { get; set; }
private set;
} public TestObservable SubscribeCheckObservable { get; private set; }
public TestObservable SubscribeCheckObservable public TemplatedControl TemplatedParent
{ {
get; get;
private set; set;
} }
public virtual void SetValue(PerspexProperty property, object value, IObservable<bool> activator) 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;
using System.Diagnostics.Contracts;
using System.Linq;
using Perspex.Controls; using Perspex.Controls;
public class ControlTemplate public class ControlTemplate
{ {
private Func<TemplatedControl, Control> build;
public ControlTemplate(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; Contract.Requires<NullReferenceException>(templatedParent != null);
private set;
Control root = this.build(templatedParent);
this.SetTemplatedParent(root, templatedParent);
return root;
} }
public static ControlTemplate Create<TControl>(Func<TControl, Control> build) public static ControlTemplate Create<TControl>(Func<TControl, Control> build)
where TControl : TemplatedControl where TControl : TemplatedControl
{ {
Contract.Requires<NullReferenceException>(build != null);
return new ControlTemplate(c => build((TControl)c)); 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 = internal static readonly PerspexProperty<Control> ParentPropertyRW =
PerspexProperty.Register<Control, Control>("Parent"); PerspexProperty.Register<Control, Control>("Parent");
private Classes classes;
private Styles styles; private Styles styles;
public Control() public Control()
{ {
this.Classes = new Classes(); this.classes = new Classes();
this.Classes.BeforeChanged.Subscribe(x => this.BeginDeferStyleChanges()); this.classes.BeforeChanged.Subscribe(x => this.BeginDeferStyleChanges());
this.Classes.AfterChanged.Subscribe(x => this.EndDeferStyleChanges()); this.classes.AfterChanged.Subscribe(x => this.EndDeferStyleChanges());
this.GetObservableWithHistory(ParentPropertyRW).Subscribe(this.ParentChanged); this.GetObservableWithHistory(ParentPropertyRW).Subscribe(this.ParentChanged);
@ -145,8 +147,21 @@ namespace Perspex.Controls
public Classes Classes public Classes Classes
{ {
get; get
private set; {
return this.classes;
}
set
{
if (this.classes != value)
{
this.BeginDeferStyleChanges();
this.classes.Clear();
this.classes.Add(value);
this.EndDeferStyleChanges();
}
}
} }
public Brush Foreground public Brush Foreground
@ -203,6 +218,12 @@ namespace Perspex.Controls
} }
} }
public TemplatedControl TemplatedParent
{
get;
internal set;
}
public VerticalAlignment VerticalAlignment public VerticalAlignment VerticalAlignment
{ {
get { return this.GetValue(VerticalAlignmentProperty); } get { return this.GetValue(VerticalAlignmentProperty); }

10
Perspex/Styling/IStyleable.cs

@ -19,6 +19,16 @@ namespace Perspex.Styling
/// </summary> /// </summary>
Classes Classes { get; } 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> /// <summary>
/// Binds a <see cref="PerspexProperty"/> to a style. /// Binds a <see cref="PerspexProperty"/> to a style.
/// </summary> /// </summary>

6
Perspex/Styling/Match.cs

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

31
Perspex/Styling/Selectors.cs

@ -38,6 +38,37 @@ namespace Perspex.Styling
return match; 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) public static Match OfType<T>(this Match match)
{ {
Contract.Requires<ArgumentNullException>(match != null); Contract.Requires<ArgumentNullException>(match != null);

25
Perspex/Visual.cs

@ -14,6 +14,8 @@ namespace Perspex
public abstract class Visual : PerspexObject public abstract class Visual : PerspexObject
{ {
private string id;
private Visual visualParent; private Visual visualParent;
public Rect Bounds public Rect Bounds
@ -22,6 +24,29 @@ namespace Perspex
protected set; 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 public virtual IEnumerable<Visual> VisualChildren
{ {
get { return Enumerable.Empty<Visual>(); } get { return Enumerable.Empty<Visual>(); }

Loading…
Cancel
Save