1 module rpui.events_observer; 2 3 import rpui.events; 4 import std.algorithm.mutation; 5 import std.algorithm.searching; 6 import std.variant; 7 8 interface Subscriber { 9 void onEventReceived(in Variant event); 10 } 11 12 final class ListenerSubscriber(T) : Subscriber { 13 private void delegate(in T event) listener = null; 14 private void delegate() listenerWithoutEvent = null; 15 16 this(void delegate(in T event) listener) { 17 this.listener = listener; 18 } 19 20 this(void delegate() listener) { 21 this.listenerWithoutEvent = listener; 22 } 23 24 override void onEventReceived(in Variant event) { 25 if (event.type != typeid(const(T))) 26 return; 27 28 if (listener !is null) { 29 listener(event.get!(const(T))); 30 } else { 31 listenerWithoutEvent(); 32 } 33 } 34 } 35 36 class EventsSubscriber(T) : Subscriber { 37 private T listener; 38 39 this(T listener) { 40 this.listener = listener; 41 } 42 43 override void onEventReceived(in Variant event) { 44 static immutable events = [ 45 "KeyPressed", 46 "KeyReleased", 47 "TextEntered", 48 "MouseDown", 49 "MouseUp", 50 "DblClick", 51 "TripleClick", 52 "MouseMove", 53 "MouseWheel", 54 "WindowResize", 55 "WindowExposed", 56 ]; 57 onEventReceivedFor!(events)(event); 58 } 59 60 protected void onEventReceivedFor(string[] events)(in Variant event) { 61 static foreach (eventName; events) { 62 { 63 mixin("alias eventType = " ~ eventName ~ "Event;"); 64 65 if (event.type == typeid(const(eventType))) { 66 const e = event.get!(const(eventType)); 67 mixin("listener.on" ~ eventName ~ "(e);"); 68 } 69 } 70 } 71 } 72 } 73 74 class EventsObserver { 75 private bool[EventsObserver] observerIsActive; 76 private const(TypeInfo)[][EventsObserver] observerJoinedEvents; 77 private EventsObserver[] joinedObservers; 78 private Subscriber[] subscribers; 79 80 bool subscriberIsNotifiable(Subscriber subscriber) { 81 return true; 82 } 83 84 final: 85 Subscriber subscribe(Subscriber subscriber) { 86 subscribers ~= subscriber; 87 return subscriber; 88 } 89 90 Subscriber subscribe(T)(void delegate(in T event) listener) { 91 return subscribe(new ListenerSubscriber!(T)(listener)); 92 } 93 94 Subscriber subscribe(T)(void delegate() listener) { 95 return subscribe(new ListenerSubscriber!(T)(listener)); 96 } 97 98 Subscriber subscribe(EventsListener subscriber) { 99 return subscribe(new EventsSubscriber!(EventsListener)(subscriber)); 100 } 101 102 void unsubscribe(Subscriber subscriber) { 103 subscribers = subscribers.remove!(a => a == subscriber); 104 } 105 106 void notify(T)(in T event) { 107 foreach (subscriber; subscribers) { 108 if (subscriberIsNotifiable(subscriber)) 109 subscriber.onEventReceived(Variant(event)); 110 } 111 112 foreach (observer; joinedObservers) { 113 const shouldNotify = observerJoinedEvents[observer].length == 0 || 114 observerJoinedEvents[observer].canFind(typeid(T)); 115 116 if (observerIsActive[observer] && shouldNotify) 117 observer.notify(event); 118 } 119 } 120 121 void join(EventsObserver observer, in TypeInfo[] events) { 122 joinedObservers ~= observer; 123 observerIsActive[observer] = true; 124 observerJoinedEvents[observer] = events; 125 } 126 127 void join(EventsObserver observer) { 128 joinedObservers ~= observer; 129 observerIsActive[observer] = true; 130 131 // when list is empty, then join to all events 132 observerJoinedEvents[observer] = []; 133 } 134 135 void unjoin(EventsObserver observer) { 136 observerIsActive.remove(observer); 137 joinedObservers = joinedObservers.remove!(a => a == observer); 138 } 139 140 void silent(EventsObserver observer) { 141 observerIsActive[observer] = false; 142 } 143 144 void unsilent(EventsObserver observer) { 145 observerIsActive[observer] = true; 146 } 147 }