1 /** 2 Copyright: Copyright (c) 2013-2014 Andrey Penechko. 3 License: a$(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module anchovy.gui.utils.timermanager; 8 9 public import anchovy.gui.utils.timer; 10 11 import core.time; 12 import std.array; 13 import std.algorithm; 14 import std.math: isNaN; 15 import std.stdio; 16 17 import anchovy.core.types; 18 19 class TimerManager 20 { 21 this(double delegate() currentTimeCallback) 22 in 23 { 24 assert(currentTimeCallback); 25 } 26 body 27 { 28 freeTimers.reserve(128); 29 queue.reserve(128); 30 currentTime = currentTimeCallback; 31 } 32 33 void updateTimers(double currentTime) 34 { 35 while(!queue.empty) 36 { 37 foreach(i, t; queue) 38 { 39 if (currentTime < t.nextUpdateTime) 40 return; 41 t.tick(currentTime); 42 if (t.nextUpdateTime <= 0 || isNaN(t.nextUpdateTime)) 43 { 44 freeTimers ~= t; 45 queue = queue[0..i] ~ queue[i + 1..$]; 46 break; 47 } 48 if (t.tickType == TimerTickType.PROCESS_ALL_ORDERED) 49 { 50 break; 51 } 52 } 53 sortTimers(); 54 } 55 } 56 57 /// initialDelay can be used to specify first delay to be different from following, that are set with delay parameter. 58 /// Must be not NaN and > 0 to be used as first delay. 59 Timer addTimer(double _delay, TimerHandler _handler, double _initialDelay = double.nan, TimerTickType _tickType = TimerTickType.init) 60 { 61 Timer timer = popFreeTimer(); 62 63 double startTime = currentTime(); 64 65 if (!isNaN(_initialDelay) || _initialDelay < 0) 66 { 67 startTime += _initialDelay; 68 } 69 else 70 startTime += _delay; 71 72 timer.initialize(startTime, currentTime(), _delay, _handler, _tickType); 73 addToQueue(timer); 74 75 return timer; 76 } 77 78 /// Resets timer's delay to newDelay if > 0 or to timer.delay otherwise. 79 /// 80 /// Timer.delay will not be changed. Timer.nextUpdate only chabges. 81 /// If you wish change Timer.delay you can do this by returning new delay in timer callback or 82 /// by setting it directly trough the reference returned by addTimer. 83 void resetTimer(Timer timer, double newDelay = double.nan) 84 { 85 double _delay = newDelay; 86 if (!(_delay > 0)) _delay = timer.delay; 87 timer.nextUpdateTime = currentTime() + _delay; 88 89 sortTimers(); 90 } 91 92 void stopTimer(Timer timer) 93 { 94 foreach(i, ref t; queue) 95 { 96 if (t == timer) 97 { 98 freeTimers ~= t; 99 queue = queue[0..i] ~ queue[i + 1..$]; 100 return; 101 } 102 } 103 104 assert("Tried to stop not running timer"); 105 } 106 107 protected: 108 109 Timer popFreeTimer() 110 { 111 if (freeTimers.length > 0) 112 { 113 scope(exit) freeTimers.popBack; 114 return freeTimers.back; 115 } 116 else 117 { 118 return new Timer(); 119 } 120 } 121 122 /// timer must be previously removed from freeTimers. 123 void addToQueue(Timer timer) 124 { 125 queue ~= timer; 126 sortTimers(); 127 } 128 129 void sortTimers() 130 { 131 sort!(q{a.nextUpdateTime < b.nextUpdateTime})(queue); 132 } 133 134 Timer[] freeTimers; 135 Timer[] queue; 136 137 double delegate() currentTime; 138 }