Browse Source

Change button color on mouseover! Woo!

pull/4/head
grokys 13 years ago
parent
commit
a777d24824
  1. 2
      Perspex.Windows/Threading/Dispatcher.cs
  2. 25
      Perspex.Windows/Window.cs
  3. 7
      Perspex/Controls/Border.cs
  4. 2
      Perspex/Controls/Button.cs
  5. 3
      Perspex/Controls/ContentControl.cs
  6. 1
      Perspex/Controls/ContentPresenter.cs
  7. 28
      Perspex/Controls/Control.cs
  8. 30
      Perspex/Match.cs
  9. 5
      Perspex/Media/SolidColorBrush.cs
  10. 1
      Perspex/Perspex.csproj
  11. 51
      Perspex/PerspexObject.cs
  12. 5
      Perspex/Point.cs
  13. 11
      Perspex/Rect.cs
  14. 37
      Perspex/Selectors.cs
  15. 16
      Perspex/Setter.cs
  16. 44
      Perspex/Style.cs
  17. 19
      Perspex/Visual.cs
  18. 2
      TestApplication/Program.cs

2
Perspex.Windows/Threading/Dispatcher.cs

@ -220,7 +220,7 @@ namespace Perspex.Windows.Threading
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method)
public DispatcherOperation BeginInvoke(DispatcherPriority priority, Action method)
{
if (priority < 0 || priority > DispatcherPriority.Send)
{

25
Perspex.Windows/Window.cs

@ -7,6 +7,7 @@
using Perspex.Controls;
using Perspex.Layout;
using Perspex.Windows.Interop;
using Perspex.Windows.Threading;
public class Window : ContentControl, ILayoutRoot
{
@ -31,11 +32,13 @@
this.LayoutManager = new LayoutManager();
this.renderer = new Renderer(this.Handle, (int)clientSize.Width, (int)clientSize.Height);
// TODO: Do this by pushing to Dispatcher rather than right away!
this.LayoutManager.LayoutNeeded.Subscribe(x =>
{
this.LayoutManager.ExecuteLayoutPass();
this.renderer.Render(this);
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Render, () =>
{
this.LayoutManager.ExecuteLayoutPass();
this.renderer.Render(this);
});
});
}
@ -121,6 +124,16 @@
}
}
private void MouseMove(Visual visual, Point p)
{
visual.IsMouseOver = visual.Bounds.Contains(p);
foreach (Visual child in visual.VisualChildren)
{
this.MouseMove(child, p - visual.Bounds.Position);
}
}
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")]
private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
@ -146,9 +159,9 @@
//// InputManager.Current.ProcessInput(new RawMouseEventArgs(mouse, RawMouseEventType.LeftButtonUp));
//// break;
////case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE:
//// InputManager.Current.ProcessInput(new RawMouseEventArgs(mouse, RawMouseEventType.Move));
//// break;
case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE:
this.MouseMove(this, new Point((uint)lParam & 0xffff, (uint)lParam >> 16));
break;
case UnmanagedMethods.WindowsMessage.WM_SIZE:
this.renderer.Resize((int)lParam & 0xffff, (int)lParam >> 16);

7
Perspex/Controls/Border.cs

@ -1,6 +1,7 @@
namespace Perspex.Controls
{
using System.Diagnostics.Contracts;
using System;
using System.Reactive.Linq;
using Perspex.Media;
public class Border : Decorator
@ -13,6 +14,10 @@
if (background != null)
{
System.Diagnostics.Debug.WriteLine(
string.Format("{0} Draw Background={1}",
this.GetHashCode(),
background));
context.FillRectange(background, new Rect(this.Bounds.Size));
}

2
Perspex/Controls/Button.cs

@ -6,6 +6,8 @@
namespace Perspex.Controls
{
using System;
public class Button : ContentControl
{
protected override Visual DefaultTemplate()

3
Perspex/Controls/ContentControl.cs

@ -1,6 +1,7 @@
namespace Perspex.Controls
{
using System;
using System.Collections.Generic;
using System.Linq;
public abstract class ContentControl : TemplatedControl
@ -12,10 +13,12 @@
{
this.GetObservable(ContentProperty).Subscribe(x =>
{
Visual visual = x as Visual;
Control control = x as Control;
if (control != null)
{
control.VisualParent = this;
control.SetValue(ParentPropertyRW, this);
}
});

1
Perspex/Controls/ContentPresenter.cs

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Perspex.Media;
public class ContentPresenter : Control
{

28
Perspex/Controls/Control.cs

@ -1,11 +1,12 @@
namespace Perspex.Controls
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using Perspex.Layout;
using Perspex.Media;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Reactive.Linq;
using Perspex.Layout;
using Perspex.Media;
public enum HorizontalAlignment
{
@ -54,6 +55,9 @@ using Perspex.Media;
this.Classes = new ObservableCollection<string>();
this.Styles = new ObservableCollection<Style>();
this.GetObservableWithHistory(ParentPropertyRW).Subscribe(this.ParentChanged);
// Hacky hack hack!
this.GetObservable(BackgroundProperty).Skip(1).Subscribe(_ => this.InvalidateMeasure());
}
public Brush Background
@ -143,12 +147,22 @@ using Perspex.Media;
public void InvalidateArrange()
{
this.GetLayoutRoot().LayoutManager.InvalidateArrange(this);
ILayoutRoot root = this.GetLayoutRoot();
if (root != null)
{
root.LayoutManager.InvalidateArrange(this);
}
}
public void InvalidateMeasure()
{
this.GetLayoutRoot().LayoutManager.InvalidateMeasure(this);
ILayoutRoot root = this.GetLayoutRoot();
if (root != null)
{
root.LayoutManager.InvalidateMeasure(this);
}
}
protected virtual Size ArrangeContent(Size finalSize)

30
Perspex/Match.cs

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Perspex.Controls;
namespace Perspex
{
public class Match
{
public Control Control
{
get;
set;
}
public IObservable<bool> Observable
{
get;
set;
}
public Match Previous
{
get;
set;
}
}
}

5
Perspex/Media/SolidColorBrush.cs

@ -37,5 +37,10 @@ namespace Perspex.Media
get;
private set;
}
public override string ToString()
{
return this.Color.ToString();
}
}
}

1
Perspex/Perspex.csproj

@ -92,6 +92,7 @@
<Compile Include="PerspexPropertyChangedEventArgs.cs" />
<Compile Include="Point.cs" />
<Compile Include="ReadOnlyPerspexProperty.cs" />
<Compile Include="Match.cs" />
<Compile Include="Selectors.cs" />
<Compile Include="ServiceLocator.cs" />
<Compile Include="Setter.cs" />

51
Perspex/PerspexObject.cs

@ -167,10 +167,10 @@ namespace Perspex
this.ClearBinding(target);
IDisposable binding = source.Subscribe(Observer.Create<T>(value =>
IDisposable binding = source.Subscribe(value =>
{
this.SetValue(target, value);
}));
this.SetValueImpl(target, value);
});
this.bindings.Add(target, binding);
}
@ -210,6 +210,8 @@ namespace Perspex
/// <returns></returns>
public IObservable<object> GetObservable(PerspexProperty property)
{
Contract.Requires<NullReferenceException>(property != null);
return Observable.Create<object>(observer =>
{
EventHandler<PerspexPropertyChangedEventArgs> handler = (s, e) =>
@ -238,24 +240,9 @@ namespace Perspex
/// <returns></returns>
public IObservable<T> GetObservable<T>(PerspexProperty<T> property)
{
return Observable.Create<T>(observer =>
{
EventHandler<PerspexPropertyChangedEventArgs> handler = (s, e) =>
{
if (e.Property == property)
{
observer.OnNext((T)e.NewValue);
}
};
this.PropertyChanged += handler;
observer.OnNext(this.GetValue(property));
Contract.Requires<NullReferenceException>(property != null);
return () =>
{
this.PropertyChanged -= handler;
};
});
return this.GetObservable((PerspexProperty)property).Cast<T>();
}
/// <summary>
@ -266,6 +253,8 @@ namespace Perspex
/// <returns></returns>
public IObservable<T> GetObservable<T>(ReadOnlyPerspexProperty<T> property)
{
Contract.Requires<NullReferenceException>(property != null);
return this.GetObservable((PerspexProperty<T>)property.Property);
}
@ -369,14 +358,7 @@ namespace Perspex
Contract.Requires<NullReferenceException>(property != null);
this.ClearBinding(property);
object oldValue = this.GetValue(property);
if (!object.Equals(oldValue, value))
{
this.values[property] = value;
this.RaisePropertyChanged(property, oldValue, value);
}
this.SetValueImpl(property, value);
}
/// <summary>
@ -425,5 +407,18 @@ namespace Perspex
new PerspexPropertyChangedEventArgs(property, oldValue, newValue));
}
}
public void SetValueImpl(PerspexProperty property, object value)
{
Contract.Requires<NullReferenceException>(property != null);
object oldValue = this.GetValue(property);
if (!object.Equals(oldValue, value))
{
this.values[property] = value;
this.RaisePropertyChanged(property, oldValue, value);
}
}
}
}

5
Perspex/Point.cs

@ -52,5 +52,10 @@
{
return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", this.x, this.y);
}
public static Point operator-(Point a, Point b)
{
return new Point(a.x - b.x, a.y - b.y);
}
}
}

11
Perspex/Rect.cs

@ -116,6 +116,17 @@
get { return new Size(this.width, this.height); }
}
/// <summary>
/// Determines whether a points in in the bounds of the rectangle.
/// </summary>
/// <param name="p">The point.</param>
/// <returns>true if the point is in the bounds of the rectangle; otherwise false.</returns>
public bool Contains(Point p)
{
return p.X >= this.x && p.Y < this.x + this.width &&
p.Y >= this.y && p.Y < this.y + this.height;
}
/// <summary>
/// Deflates the rectangle by a <see cref="Thickness"/>.
/// </summary>

37
Perspex/Selectors.cs

@ -11,11 +11,42 @@
public static class Selectors
{
public static IObservable<bool> OfType<T>(this Control control)
public static Match Select<T>(this Control control)
{
Contract.Requires<ArgumentNullException>(control != null);
return Observable.Return(control is T);
if (control is T)
{
return new Match
{
Control = control,
};
}
else
{
return null;
}
}
public static Match PropertyEquals<T>(this Match selector, PerspexProperty<T> property, T value)
{
Contract.Requires<ArgumentNullException>(property != null);
if (selector != null)
{
IObservable<bool> match = selector.Control.GetObservable(property).Select(x => object.Equals(x, value));
return new Match
{
Control = selector.Control,
Observable = match,
Previous = selector,
};
}
else
{
return null;
}
}
}
}

16
Perspex/Setter.cs

@ -26,13 +26,27 @@
this.oldValue = control.GetValue(this.Property);
control.SetValue(this.Property, this.Value);
System.Diagnostics.Debug.WriteLine(
string.Format("{0} Style Set {1}.{2}={3}",
control.GetHashCode(),
control.GetType().Name,
this.Property.Name,
this.Value));
}
public void Detach(Control control)
public void Unapply(Control control)
{
Contract.Requires<NullReferenceException>(control != null);
control.SetValue(this.Property, this.oldValue);
System.Diagnostics.Debug.WriteLine(
string.Format("{0} Style Unset {1}.{2}={3}",
control.GetHashCode(),
control.GetType().Name,
this.Property.Name,
oldValue));
}
}
}

44
Perspex/Style.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using Perspex.Controls;
@ -10,12 +11,14 @@ namespace Perspex
{
public class Style
{
private bool applied;
public Style()
{
this.Setters = new List<Setter>();
}
public Func<Control, IObservable<bool>> Selector
public Func<Control, Match> Selector
{
get;
set;
@ -29,19 +32,36 @@ namespace Perspex
public void Attach(Control control)
{
this.Selector(control).Subscribe(x =>
Match match = this.Selector(control);
if (match != null)
{
if (x)
List<IObservable<bool>> o = new List<IObservable<bool>>();
while (match != null)
{
this.Apply(control);
if (match.Observable != null)
{
o.Add(match.Observable);
}
match = match.Previous;
}
else
Observable.CombineLatest(o).Subscribe(x =>
{
this.Unapply(control);
}
});
if (x.All(y => y))
{
this.Apply(control);
}
else if (this.applied)
{
this.Unapply(control);
}
});
}
}
private void Apply(Control control)
{
if (this.Setters != null)
@ -51,6 +71,8 @@ namespace Perspex
setter.Apply(control);
}
}
this.applied = true;
}
private void Unapply(Control control)
@ -59,8 +81,10 @@ namespace Perspex
{
foreach (Setter setter in this.Setters)
{
setter.Detach(control);
setter.Unapply(control);
}
this.applied = false;
}
}
}

19
Perspex/Visual.cs

@ -9,17 +9,26 @@
public abstract class Visual : PerspexObject
{
public static readonly ReadOnlyPerspexProperty<Rect> BoundsProperty =
new ReadOnlyPerspexProperty<Rect>(BoundsPropertyW);
new ReadOnlyPerspexProperty<Rect>(BoundsPropertyRW);
private static readonly PerspexProperty<Rect> BoundsPropertyW =
PerspexProperty.Register<Visual, Rect>("Bounds", new Rect());
private static readonly PerspexProperty<Rect> BoundsPropertyRW =
PerspexProperty.Register<Visual, Rect>("Bounds");
public static readonly PerspexProperty<bool> IsMouseOverProperty =
PerspexProperty.Register<Visual, bool>("IsMouseOver");
private Visual visualParent;
public Rect Bounds
{
get { return this.GetValue(BoundsPropertyW); }
protected set { this.SetValue(BoundsPropertyW, value); }
get { return this.GetValue(BoundsPropertyRW); }
protected set { this.SetValue(BoundsPropertyRW, value); }
}
public bool IsMouseOver
{
get { return this.GetValue(IsMouseOverProperty); }
set { this.SetValue(IsMouseOverProperty, value); }
}
public virtual IEnumerable<Visual> VisualChildren

2
TestApplication/Program.cs

@ -26,7 +26,7 @@ namespace TestApplication
{
new Style
{
Selector = x => x.OfType<Button>(),
Selector = x => x.Select<Button>().PropertyEquals(Visual.IsMouseOverProperty, true),
Setters = new[]
{
new Setter

Loading…
Cancel
Save