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 }