10 changed files with 420 additions and 8 deletions
@ -0,0 +1,14 @@ |
|||||
|
// -----------------------------------------------------------------------
|
||||
|
// <copyright file="MouseEventArgs.cs" company="Steven Kirk">
|
||||
|
// Copyright 2013 MIT Licence. See licence.md for more information.
|
||||
|
// </copyright>
|
||||
|
// -----------------------------------------------------------------------
|
||||
|
|
||||
|
namespace Perspex.Input |
||||
|
{ |
||||
|
using System; |
||||
|
|
||||
|
public class MouseEventArgs : RoutedEventArgs |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,106 @@ |
|||||
|
// -----------------------------------------------------------------------
|
||||
|
// <copyright file="Interactive.cs" company="Steven Kirk">
|
||||
|
// Copyright 2014 MIT Licence. See licence.md for more information.
|
||||
|
// </copyright>
|
||||
|
// -----------------------------------------------------------------------
|
||||
|
|
||||
|
namespace Perspex |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Diagnostics.Contracts; |
||||
|
using System.Reactive; |
||||
|
using System.Reactive.Linq; |
||||
|
|
||||
|
public class Interactive : Visual |
||||
|
{ |
||||
|
private Dictionary<RoutedEvent, List<Delegate>> eventHandlers = new Dictionary<RoutedEvent, List<Delegate>>(); |
||||
|
|
||||
|
public void AddHandler(RoutedEvent routedEvent, Delegate handler) |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(routedEvent != null); |
||||
|
Contract.Requires<NullReferenceException>(handler != null); |
||||
|
|
||||
|
List<Delegate> delegates; |
||||
|
|
||||
|
if (!this.eventHandlers.TryGetValue(routedEvent, out delegates)) |
||||
|
{ |
||||
|
delegates = new List<Delegate>(); |
||||
|
this.eventHandlers.Add(routedEvent, delegates); |
||||
|
} |
||||
|
|
||||
|
delegates.Add(handler); |
||||
|
} |
||||
|
|
||||
|
public IObservable<EventPattern<T>> GetObservable<T>(RoutedEvent<T> routedEvent) where T : RoutedEventArgs |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(routedEvent != null); |
||||
|
|
||||
|
return Observable.FromEventPattern<T>( |
||||
|
handler => this.AddHandler(routedEvent, handler), |
||||
|
handler => this.RemoveHandler(routedEvent, handler)); |
||||
|
} |
||||
|
|
||||
|
public void RemoveHandler(RoutedEvent routedEvent, Delegate handler) |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(routedEvent != null); |
||||
|
Contract.Requires<NullReferenceException>(handler != null); |
||||
|
|
||||
|
List<Delegate> delegates; |
||||
|
|
||||
|
if (this.eventHandlers.TryGetValue(routedEvent, out delegates)) |
||||
|
{ |
||||
|
delegates.Remove(handler); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void RaiseEvent(RoutedEventArgs e) |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(e != null); |
||||
|
|
||||
|
if (e.RoutedEvent != null) |
||||
|
{ |
||||
|
switch (e.RoutedEvent.RoutingStrategy) |
||||
|
{ |
||||
|
case RoutingStrategy.Bubble: |
||||
|
this.BubbleEvent(e); |
||||
|
break; |
||||
|
case RoutingStrategy.Direct: |
||||
|
this.RaiseEventImpl(e); |
||||
|
break; |
||||
|
default: |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void BubbleEvent(RoutedEventArgs e) |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(e != null); |
||||
|
|
||||
|
Interactive target = this; |
||||
|
|
||||
|
while (target != null) |
||||
|
{ |
||||
|
target.RaiseEventImpl(e); |
||||
|
target = target.GetVisualAncestor<Interactive>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void RaiseEventImpl(RoutedEventArgs e) |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(e != null); |
||||
|
|
||||
|
List<Delegate> delegates; |
||||
|
|
||||
|
if (this.eventHandlers.TryGetValue(e.RoutedEvent, out delegates)) |
||||
|
{ |
||||
|
foreach (Delegate handler in delegates) |
||||
|
{ |
||||
|
// TODO: Implement the Handled stuff.
|
||||
|
handler.DynamicInvoke(this, e); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,87 @@ |
|||||
|
// -----------------------------------------------------------------------
|
||||
|
// <copyright file="RoutedEvent.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.Reflection; |
||||
|
|
||||
|
public enum RoutingStrategy |
||||
|
{ |
||||
|
Tunnel, |
||||
|
Bubble, |
||||
|
Direct, |
||||
|
} |
||||
|
|
||||
|
public class RoutedEvent |
||||
|
{ |
||||
|
public RoutedEvent( |
||||
|
string name, |
||||
|
RoutingStrategy routingStrategy, |
||||
|
Type eventArgsType, |
||||
|
Type ownerType) |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(name != null); |
||||
|
Contract.Requires<NullReferenceException>(eventArgsType != null); |
||||
|
Contract.Requires<NullReferenceException>(ownerType != null); |
||||
|
Contract.Requires<InvalidCastException>(typeof(RoutedEventArgs).GetTypeInfo().IsAssignableFrom(eventArgsType.GetTypeInfo())); |
||||
|
Contract.Requires<InvalidCastException>(typeof(Interactive).GetTypeInfo().IsAssignableFrom(ownerType.GetTypeInfo())); |
||||
|
|
||||
|
this.EventArgsType = eventArgsType; |
||||
|
this.Name = name; |
||||
|
this.OwnerType = ownerType; |
||||
|
this.RoutingStrategy = routingStrategy; |
||||
|
} |
||||
|
|
||||
|
public Type EventArgsType |
||||
|
{ |
||||
|
get; |
||||
|
private set; |
||||
|
} |
||||
|
|
||||
|
public string Name |
||||
|
{ |
||||
|
get; |
||||
|
private set; |
||||
|
} |
||||
|
|
||||
|
public Type OwnerType |
||||
|
{ |
||||
|
get; |
||||
|
private set; |
||||
|
} |
||||
|
|
||||
|
public RoutingStrategy RoutingStrategy |
||||
|
{ |
||||
|
get; |
||||
|
private set; |
||||
|
} |
||||
|
|
||||
|
public static RoutedEvent<TEventArgs> Register<TOwner, TEventArgs>( |
||||
|
string name, |
||||
|
RoutingStrategy routingStrategy) |
||||
|
where TOwner : Interactive |
||||
|
where TEventArgs : RoutedEventArgs |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(name != null); |
||||
|
|
||||
|
return new RoutedEvent<TEventArgs>(name, routingStrategy, typeof(TOwner)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class RoutedEvent<TEventArgs> : RoutedEvent |
||||
|
where TEventArgs : RoutedEventArgs |
||||
|
{ |
||||
|
public RoutedEvent(string name, RoutingStrategy routingStrategy, Type ownerType) |
||||
|
: base(name, routingStrategy, typeof(TEventArgs), ownerType) |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(name != null); |
||||
|
Contract.Requires<NullReferenceException>(ownerType != null); |
||||
|
Contract.Requires<InvalidCastException>(typeof(Interactive).GetTypeInfo().IsAssignableFrom(ownerType.GetTypeInfo())); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
// -----------------------------------------------------------------------
|
||||
|
// <copyright file="RoutedEventArgs.cs" company="Steven Kirk">
|
||||
|
// Copyright 2014 MIT Licence. See licence.md for more information.
|
||||
|
// </copyright>
|
||||
|
// -----------------------------------------------------------------------
|
||||
|
|
||||
|
namespace Perspex |
||||
|
{ |
||||
|
using System; |
||||
|
|
||||
|
public class RoutedEventArgs : EventArgs |
||||
|
{ |
||||
|
public RoutedEventArgs() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public RoutedEventArgs(RoutedEvent routedEvent) |
||||
|
{ |
||||
|
this.RoutedEvent = routedEvent; |
||||
|
} |
||||
|
|
||||
|
public RoutedEventArgs(RoutedEvent routedEvent, object source) |
||||
|
{ |
||||
|
this.RoutedEvent = routedEvent; |
||||
|
this.Source = source; |
||||
|
} |
||||
|
|
||||
|
public bool Handled { get; set; } |
||||
|
|
||||
|
public object OriginalSource { get; set; } |
||||
|
|
||||
|
public RoutedEvent RoutedEvent { get; set; } |
||||
|
|
||||
|
public object Source { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
// -----------------------------------------------------------------------
|
||||
|
// <copyright file="VisualExtensions.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; |
||||
|
|
||||
|
public static class VisualExtensions |
||||
|
{ |
||||
|
public static T GetVisualAncestor<T>(this Visual visual) where T : Visual |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(visual != null); |
||||
|
|
||||
|
visual = visual.VisualParent; |
||||
|
|
||||
|
while (visual != null) |
||||
|
{ |
||||
|
if (visual is T) |
||||
|
{ |
||||
|
return (T)visual; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
visual = visual.VisualParent; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public static Visual GetVisualAt(this Visual visual, Point p) |
||||
|
{ |
||||
|
Contract.Requires<NullReferenceException>(visual != null); |
||||
|
|
||||
|
if (visual.Bounds.Contains(p)) |
||||
|
{ |
||||
|
p -= visual.Bounds.Position; |
||||
|
|
||||
|
if (visual.VisualChildren.Any()) |
||||
|
{ |
||||
|
foreach (Visual child in visual.VisualChildren) |
||||
|
{ |
||||
|
Visual hit = child.GetVisualAt(p); |
||||
|
|
||||
|
if (hit != null) |
||||
|
{ |
||||
|
return hit; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return visual; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue