1 module sbylib.event.frameevent;
2 
3 import std;
4 import sbylib.event;
5 
6 private alias FrameCallback = void delegate();
7 
8 struct FrameNotification {
9     private bool delegate() condition;
10     private immutable uint priority;
11 }
12 
13 FrameNotification Frame(uint p = FrameEventWatcher.DefaultPriority) {
14     return FrameNotification(null, p);
15 }
16 
17 VoidEvent when(lazy bool condition, uint p = FrameEventWatcher.DefaultPriority) {
18     return when(FrameNotification(() => condition, p));
19 }
20 
21 VoidEvent when(FrameNotification frame) {
22     import sbylib.event : when;
23 
24     auto event = new VoidEvent;
25     auto cb = FrameEventWatcher.add(frame.priority, {
26         if (frame.condition && frame.condition() == false) return;
27         event.fire();
28     });
29     when(event.finish).then({
30         FrameEventWatcher.remove(frame.priority, cb);
31     });
32     return event;
33 }
34 
35 class FrameEventWatcher {
36 static:
37 
38     enum DefaultPriority = 50;
39     enum MaxPriority = 100;
40 
41     private Array!FrameCallback[MaxPriority] callbackList;
42 
43     private FrameCallback add(uint priority, FrameCallback callback) {
44         this.callbackList[priority] ~= callback;
45         return callback;
46     }
47 
48     private void remove(uint priority, FrameCallback callback) {
49         auto target = callbackList[priority];
50         target.linearRemove(target[].find(callback).take(1));
51     }
52 
53     void update() {
54         foreach (cb; callbackList) {
55             for (int i = 0; i < cb.length; i++) {
56                 cb[i]();
57             }
58         }
59     }
60 }
61 
62 unittest {
63     int count1;
64     when(Frame).then({
65         count1++;
66     });
67 
68     int count2;
69     when(count1 % 2 == 0).then({
70         count2++;
71     });
72 
73     int count3;
74     when(count1 > 2).then({
75         count3++;
76     });
77 
78     int count4;
79     when(count1 > 2).once({
80         count4++;
81     });
82 
83     foreach (i; 0..5) {
84         FrameEventWatcher.update();
85     }
86 
87     assert(count1 == 5);
88     assert(count2 == 2);
89     assert(count3 == 3);
90     assert(count4 == 1);
91 }