Skip to content

Instantly share code, notes, and snippets.

@eonist
Last active April 8, 2016 18:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eonist/9c5345a53f75ff8aec07 to your computer and use it in GitHub Desktop.
Save eonist/9c5345a53f75ff8aec07 to your computer and use it in GitHub Desktop.
A simple event system that propagates events through hierarchical classes
import Foundation
/*
* TODO: Implement the immediate variable if its needed (it would be a way to get assert the 1-level down immediate child an event came from, rather than the origin child which can be many levels deeper in the hirarchy)
*/
class Event{
static var update:String = "eventUpdate"/*Idealy I would name this change but apparently then subclasses can name their const the same*/
var type:String
var origin:AnyObject/*origin sender of event, this could also be weak if you discover a memory leak*/
/*var immediate:Any?*///prev sender of event, may be implemented in the future if needed
init(_ type:String = "", _ origin:AnyObject/*, immediate:Any? = nil*/){
self.type = type
self.origin = origin
}
}
class ButtonEvent:Event{
static var down:String = "buttonEventDown"
static var up:String = "buttonEventUp"
}
class MouseEvent:Event{/*<--Sudo MouseEvent, the Real mouseEvent actually wraps an NSEvent*/
static var down:String = "mouseEventDown"
static var up:String = "mouseEventUp"
var pos:CGPoint
init(_ type:String,_ pos:CGPoint, _ origin:AnyObject){
self.pos = pos
super.init(type, origin)
}
}
/**
* All elements in the hierarchy that wants to propagate the event must implement this protocol
*/
protocol IEventSender:class {
var event: ((Event) -> ())?{get set}//maybe rename to eventRelay?
func onEvent(event:Event)
}
/**
* Sudo version of the NSView
*/
class View{
var superview:View?
init(_ parent:View? = nil){
superview = parent
}
}
/**
* InteractiveView facilitates sending of events when interactionEvents happens on the view
* NOTE: its primary use-case is to wrap NSEvents into Event so that the view hierarchy can retrieve the view where the event came from which is not possible when using NSEvent. NSEvent cant be subclasses so this is the best solution ive found for this particular usecase.
*/
class InteractiveView:View,IEventSender{
var eventCall:((Event) -> ())? {
return {
(event:Event) -> Void in if(self.superview is IEventSender){(self.superview as! IEventSender).onEvent(event)
}
}
}//returns closure that will take care of propagating the event to the parent
var event: ((Event) -> ())? /*this holds any method assigned to it that has its type*/
override init(_ parent: View? = nil) {
super.init(parent)
//event = onEvent/*assign method to selector*/
event = eventCall
}
/**
* EXAMPLE: override onEvent in a subClass then assert origin === thumb && event.type == ButtonEvent.down
*/
func onEvent(event:Event){
//Swift.print("InteractiveView.onEvent: type: " + "\(event.type)")
self.event!(event)
}
}
class A:InteractiveView{
var b:InteractiveView?
override init(_ parent:View? = nil){
super.init(parent)
b = B(self)
}
}
class B:B2{
var c:InteractiveView?
override init(_ parent:View? = nil){
super.init(parent)
c = C(self)
}
override func onEvent(event: Event) {//override onEvent in this subClass
//Swift.print("B.onEvent() ")
if(event.origin === c && event.type == MouseEvent.down){Swift.print("B.onEvent() event.type: " + event.type + " pos: " + "\((event as! MouseEvent).pos)")}//we listen for events that is of c origin only and is of EVent type MouseEvent.down
super.onEvent(event)
}
}
class B2:InteractiveView{
override func onEvent(event: Event) {//override onEvent in this subClass, we can listen to events etc
//Swift.print("B2.onEvent() ")
super.onEvent(event)
}
}
class C:InteractiveView{
override init(_ parent:View? = nil){
super.init(parent)
}
}
let a = A(nil)
func onEvent(event:Event){
Swift.print("Root onEvent() origin: " + "\(event.origin)" + " type: " + "\(event.type)")
}
a.event = onEvent//lets hi-jack the event exit point of instance a. All events that are sent from a are now rerouted to onEvent method in root
let c = (a.b as! B).c!//Reference to the c instance
//imitate that an event was sent from instance c:
c.onEvent(Event(Event.update,c))//in root: type: eventUpdate
c.onEvent(MouseEvent(MouseEvent.down,CGPoint(x: 25,y: 25),c))//OutPut: in B type: mouseEventDown pos: (25.0, 25.0)
@eonist
Copy link
Author

eonist commented Feb 11, 2016

you can also read more about this event system here: http://stylekit.org/blog/2016/02/10/The-event-system/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment