Browse Source

Style council.

pull/4/head
grokys 12 years ago
parent
commit
581a037cb8
  1. 2
      Perspex.UnitTests/Perspex.UnitTests.csproj
  2. 8
      Perspex.UnitTests/StyleTests.cs
  3. 68
      Perspex.UnitTests/Styling/SelectorTests.cs
  4. 59
      Perspex.UnitTests/Styling/SubscribeCheck.cs
  5. 1
      Perspex/Perspex.csproj
  6. 89
      Perspex/Styling/Activator.cs
  7. 36
      Perspex/Styling/Match.cs
  8. 50
      Perspex/Styling/Selectors.cs
  9. 6
      Perspex/Themes/Default/ButtonStyle.cs

2
Perspex.UnitTests/Perspex.UnitTests.csproj

@ -69,6 +69,8 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PerspexObjectTests.cs" />
<Compile Include="StyleTests.cs" />
<Compile Include="Styling\SelectorTests.cs" />
<Compile Include="Styling\SubscribeCheck.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Perspex\Perspex.csproj">

8
Perspex.UnitTests/StyleTests.cs

@ -18,7 +18,7 @@ namespace Perspex.UnitTests
[TestMethod]
public void Style_With_Only_Type_Selector_Should_Update_Value()
{
Style style = new Style(x => x.Select<TextBlock>())
Style style = new Style(x => x.Select().OfType<TextBlock>())
{
Setters = new[]
{
@ -38,7 +38,7 @@ namespace Perspex.UnitTests
[TestMethod]
public void Style_With_Class_Selector_Should_Update_And_Restore_Value()
{
Style style = new Style(x => x.Select<TextBlock>().Class("foo"))
Style style = new Style(x => x.Select().OfType<TextBlock>().Class("foo"))
{
Setters = new[]
{
@ -62,7 +62,7 @@ namespace Perspex.UnitTests
[TestMethod]
public void Later_Styles_Should_Override_Earlier()
{
Style style1 = new Style(x => x.Select<TextBlock>().Class("foo"))
Style style1 = new Style(x => x.Select().OfType<TextBlock>().Class("foo"))
{
Setters = new[]
{
@ -70,7 +70,7 @@ namespace Perspex.UnitTests
},
};
Style style2 = new Style(x => x.Select<TextBlock>().Class("foo"))
Style style2 = new Style(x => x.Select().OfType<TextBlock>().Class("foo"))
{
Setters = new[]
{

68
Perspex.UnitTests/Styling/SelectorTests.cs

@ -0,0 +1,68 @@
// -----------------------------------------------------------------------
// <copyright file="SelectorTests.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.UnitTests.Styling
{
using System;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Perspex.Styling;
using Match = Perspex.Styling.Match;
[TestClass]
public class SelectorTests
{
[TestMethod]
public void OfType_Matches_Control_Of_Correct_Type()
{
var control = new Class1();
var target = control.Select().OfType<Class1>();
CollectionAssert.AreEqual(new[] { true }, target.GetActivator().Take(1).ToEnumerable().ToArray());
}
[TestMethod]
public void OfType_Doesnt_Match_Control_Of_Wrong_Type()
{
var control = new Class2();
var target = control.Select().OfType<Class1>();
CollectionAssert.AreEqual(new[] { false }, target.GetActivator().Take(1).ToEnumerable().ToArray());
}
[TestMethod]
public void When_OfType_Matches_Control_Other_Selectors_Are_Subscribed()
{
var control = new Class1();
var target = control.Select().OfType<Class1>().SubscribeCheck();
var result = target.GetActivator().ToEnumerable().Take(1).ToArray();
Assert.AreEqual(1, control.SubscribeCheckObservable.SubscribedCount);
}
[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 result = target.GetActivator().ToEnumerable().Take(1).ToArray();
Assert.AreEqual(0, control.SubscribeCheckObservable.SubscribedCount);
}
public class Class1 : SubscribeCheck
{
}
public class Class2 : SubscribeCheck
{
}
}
}

59
Perspex.UnitTests/Styling/SubscribeCheck.cs

@ -0,0 +1,59 @@
// -----------------------------------------------------------------------
// <copyright file="SubscribeCheck.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.UnitTests.Styling
{
using System;
using System.Reactive.Disposables;
using Perspex.Styling;
using Match = Perspex.Styling.Match;
public class TestObservable : IObservable<bool>
{
public int SubscribedCount { get; private set; }
public IDisposable Subscribe(IObserver<bool> observer)
{
++this.SubscribedCount;
observer.OnNext(true);
return Disposable.Create(() => --this.SubscribedCount);
}
}
public class SubscribeCheck : IStyleable
{
public SubscribeCheck()
{
this.Classes = new PerspexList<string>();
this.SubscribeCheckObservable = new TestObservable();
}
public PerspexList<string> Classes
{
get;
private set;
}
public TestObservable SubscribeCheckObservable
{
get;
private set;
}
public virtual void SetValue(PerspexProperty property, object value, IObservable<bool> activator)
{
}
}
public static class TestSelectors
{
public static Match SubscribeCheck(this Match match)
{
match.Observables.Add(((SubscribeCheck)match.Control).SubscribeCheckObservable);
return match;
}
}
}

1
Perspex/Perspex.csproj

@ -79,6 +79,7 @@
<Compile Include="ControlTemplate.cs" />
<Compile Include="Input\MouseEventArgs.cs" />
<Compile Include="Interactive.cs" />
<Compile Include="Styling\Activator.cs" />
<Compile Include="Styling\IStyleable.cs" />
<Compile Include="Styling\IStyle.cs" />
<Compile Include="PriorityValue.cs" />

89
Perspex/Styling/Activator.cs

@ -0,0 +1,89 @@
// -----------------------------------------------------------------------
// <copyright file="Activator.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Styling
{
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Reactive.Disposables;
public class Activator : IObservable<bool>
{
List<bool> values = new List<bool>();
List<IDisposable> subscriptions = new List<IDisposable>();
List<IObserver<bool>> observers = new List<IObserver<bool>>();
bool last = false;
public Activator(IList<IObservable<bool>> observables)
{
int i = 0;
foreach (IObservable<bool> o in observables.Reverse())
{
int iCaptured = i;
this.values.Add(false);
IDisposable subscription = o.Subscribe(
x => this.Update(iCaptured, x),
x => this.Finish(iCaptured),
() => this.Finish(iCaptured));
this.subscriptions.Add(subscription);
++i;
}
}
public IDisposable Subscribe(IObserver<bool> observer)
{
Contract.Requires<ArgumentNullException>(observer != null);
this.observers.Add(observer);
observer.OnNext(last);
return Disposable.Create(() => this.observers.Remove(observer));
}
private void Update(int index, bool value)
{
this.values[index] = value;
bool current = this.values.All(x => x);
if (current != last)
{
this.Push(current);
last = current;
}
}
private void Finish(int i)
{
if (!this.values[i])
{
// If the observable has finished on 'false' then it will never go back to true
// so we can unsubscribe from all the other subscriptions now.
foreach (IDisposable subscription in this.subscriptions)
{
subscription.Dispose();
}
}
}
private void Push(bool value)
{
foreach (IObserver<bool> observer in this.observers)
{
observer.OnNext(value);
}
}
}
}

36
Perspex/Styling/Match.cs

@ -14,54 +14,38 @@ namespace Perspex.Styling
public class Match
{
public IStyleable Control
public Match(IStyleable control)
{
get;
set;
this.Control = control;
this.Observables = new List<IObservable<bool>>();
}
public IObservable<bool> Observable
public IStyleable Control
{
get;
set;
private set;
}
public Match Previous
public List<IObservable<bool>> Observables
{
get;
set;
}
public string Token
public string SelectorString
{
get;
set;
}
public IObservable<bool> GetActivator()
public Activator GetActivator()
{
List<IObservable<bool>> observables = new List<IObservable<bool>>();
Match match = this;
do
{
if (match.Observable != null)
{
observables.Add(match.Observable);
}
match = match.Previous;
}
while (match != null);
return System.Reactive.Linq.Observable.CombineLatest(observables).Select(x => x.All(b => b));
return new Activator(this.Observables);
}
public override string ToString()
{
string result = (this.Previous != null) ? this.Previous.ToString() : string.Empty;
result += this.Token;
return result;
return this.SelectorString;
}
}
}

50
Perspex/Styling/Selectors.cs

@ -18,47 +18,33 @@ namespace Perspex.Styling
public static class Selectors
{
public static Match Select<T>(this IStyleable control)
public static Match Select(this IStyleable control)
{
Contract.Requires<ArgumentNullException>(control != null);
if (control is T)
{
return new Match
{
Control = control,
Observable = Observable.Return(true),
Token = typeof(T).Name,
};
}
else
{
return null;
}
return new Match(control);
}
public static Match Class(this Match selector, string name)
public static Match Class(this Match match, string name)
{
Contract.Requires<ArgumentNullException>(match != null);
Contract.Requires<ArgumentNullException>(name != null);
if (selector != null)
{
IObservable<bool> match = Observable
.Return(selector.Control.Classes.Contains(name))
.Concat(selector.Control.Classes.Changed.Select(e => selector.Control.Classes.Contains(name)));
match.Observables.Add(Observable
.Return(match.Control.Classes.Contains(name))
.Concat(match.Control.Classes.Changed.Select(e => match.Control.Classes.Contains(name))));
match.SelectorString += (name[0] == ':') ? name : '.' + name;
return new Match
{
Control = selector.Control,
Observable = match,
Previous = selector,
Token = (name[0] == ':') ? name : '.' + name,
};
}
else
{
return null;
}
return match;
}
public static Match OfType<T>(this Match match)
{
Contract.Requires<ArgumentNullException>(match != null);
match.Observables.Add(Observable.Return(match.Control is T));
match.SelectorString += typeof(T).Name;
return match;
}
}
}

6
Perspex/Themes/Default/ButtonStyle.cs

@ -15,7 +15,7 @@ namespace Perspex.Themes.Default
{
this.AddRange(new[]
{
new Style(x => x.Select<Button>())
new Style(x => x.Select().OfType<Button>())
{
Setters = new[]
{
@ -26,7 +26,7 @@ namespace Perspex.Themes.Default
new Setter(Button.TemplateProperty, ControlTemplate.Create<Button>(this.Template)),
},
},
new Style(x => x.Select<Button>().Class(":mouseover"))
new Style(x => x.Select().OfType<Button>().Class(":mouseover"))
{
Setters = new[]
{
@ -34,7 +34,7 @@ namespace Perspex.Themes.Default
new Setter (Button.BorderBrushProperty, new SolidColorBrush(0xff3c7fb1)),
},
},
new Style(x => x.Select<Button>().Class(":pressed"))
new Style(x => x.Select().OfType<Button>().Class(":pressed"))
{
Setters = new[]
{

Loading…
Cancel
Save