mirror of https://github.com/buggins/dlangui.git
timers support part 1 - for win32 platform
This commit is contained in:
parent
016a958a17
commit
1377556d92
|
@ -66,7 +66,7 @@
|
|||
<debuglevel>0</debuglevel>
|
||||
<debugids>DebugFocus</debugids>
|
||||
<versionlevel>0</versionlevel>
|
||||
<versionids>EmbedStandardResources Unicode USE_SDL USE_FREETYPE</versionids>
|
||||
<versionids>EmbedStandardResources Unicode</versionids>
|
||||
<dump_source>0</dump_source>
|
||||
<mapverbosity>0</mapverbosity>
|
||||
<createImplib>1</createImplib>
|
||||
|
|
|
@ -117,20 +117,39 @@ class TimerInfo {
|
|||
@property long nextTimestamp() { return _nextTimestamp; }
|
||||
/// widget to route timer event to
|
||||
@property Widget targetWidget() { return _targetWidget; }
|
||||
/// return true if timer is not yet cancelled
|
||||
@property bool valid() { return _targetWidget !is null; }
|
||||
|
||||
protected ulong _id;
|
||||
protected long _interval;
|
||||
protected long _nextTimestamp;
|
||||
protected Widget _targetWidget;
|
||||
}
|
||||
|
||||
class TimerQueue {
|
||||
protected TimerInfo[] _queue;
|
||||
void add(TimerInfo event) {
|
||||
int len = cast(int)_queue.length;
|
||||
override bool opEquals(Object obj) {
|
||||
TimerInfo b = cast(TimerInfo)obj;
|
||||
if (!b)
|
||||
return false;
|
||||
return b._nextTimestamp == _nextTimestamp;
|
||||
}
|
||||
override int opCmp(Object obj) {
|
||||
TimerInfo b = cast(TimerInfo)obj;
|
||||
if (!b)
|
||||
return false;
|
||||
if (valid && !b.valid)
|
||||
return -1;
|
||||
if (!valid && b.valid)
|
||||
return 1;
|
||||
if (!valid && !b.valid)
|
||||
return 0;
|
||||
if (_nextTimestamp < b._nextTimestamp)
|
||||
return -1;
|
||||
if (_nextTimestamp > b._nextTimestamp)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Window abstraction layer. Widgets can be shown only inside window.
|
||||
*
|
||||
|
@ -261,6 +280,7 @@ class Window {
|
|||
|
||||
this() {
|
||||
_eventList = new EventList();
|
||||
_timerQueue = new TimerQueue();
|
||||
_backgroundColor = 0xFFFFFF;
|
||||
}
|
||||
~this() {
|
||||
|
@ -272,6 +292,7 @@ class Window {
|
|||
_mainWidget = null;
|
||||
}
|
||||
destroy(_eventList);
|
||||
destroy(_timerQueue);
|
||||
_eventList = null;
|
||||
}
|
||||
|
||||
|
@ -818,6 +839,124 @@ class Window {
|
|||
dlg.show();
|
||||
}
|
||||
|
||||
protected TimerQueue _timerQueue;
|
||||
|
||||
|
||||
/// schedule timer for interval in milliseconds - call window.onTimer when finished
|
||||
protected void scheduleSystemTimer(long intervalMillis) {
|
||||
Log.d("override scheduleSystemTimer to support timers");
|
||||
}
|
||||
|
||||
/// system timer interval expired - notify queue
|
||||
protected void onTimer() {
|
||||
bool res = _timerQueue.notify();
|
||||
if (res) {
|
||||
// check if update needed and redraw if so
|
||||
update(false);
|
||||
}
|
||||
long nextInterval = _timerQueue.nextIntervalMillis();
|
||||
if (nextInterval > 0) {
|
||||
scheduleSystemTimer(nextInterval);
|
||||
}
|
||||
}
|
||||
|
||||
/// set timer for destination widget - destination.onTimer() will be called after interval expiration; returns timer id
|
||||
ulong setTimer(Widget destination, long intervalMillis) {
|
||||
if (!isChild(destination)) {
|
||||
Log.e("setTimer() is called not for child widget of window");
|
||||
return 0;
|
||||
}
|
||||
ulong res = _timerQueue.add(destination, intervalMillis);
|
||||
long nextInterval = _timerQueue.nextIntervalMillis();
|
||||
if (nextInterval > 0) {
|
||||
scheduleSystemTimer(intervalMillis);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// cancel previously scheduled widget timer (for timerId pass value returned from setTimer)
|
||||
void cancelTimer(ulong timerId) {
|
||||
_timerQueue.cancelTimer(timerId);
|
||||
}
|
||||
|
||||
/// timers queue
|
||||
private class TimerQueue {
|
||||
protected TimerInfo[] _queue;
|
||||
/// add new timer
|
||||
ulong add(Widget destination, long intervalMillis) {
|
||||
TimerInfo item = new TimerInfo(destination, intervalMillis);
|
||||
_queue ~= item;
|
||||
sort(_queue);
|
||||
return item.id;
|
||||
}
|
||||
/// cancel timer
|
||||
void cancelTimer(ulong timerId) {
|
||||
for (size_t i = _queue.length - 1; i >= 0; i--) {
|
||||
if (_queue[i].id == timerId) {
|
||||
_queue[i].cancel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// returns interval if millis of next scheduled event or -1 if no events queued
|
||||
long nextIntervalMillis() {
|
||||
if (!_queue.length || !_queue[0].valid)
|
||||
return -1;
|
||||
long delta = _queue[0].nextTimestamp - currentTimeMillis;
|
||||
if (delta < 1)
|
||||
delta = 1;
|
||||
return delta;
|
||||
}
|
||||
private void cleanup() {
|
||||
sort(_queue);
|
||||
size_t newsize = 0;
|
||||
for (size_t i = _queue.length - 1; i >= 0; i--) {
|
||||
if (!_queue[i].valid) {
|
||||
newsize = i;
|
||||
}
|
||||
}
|
||||
if (_queue.length > newsize)
|
||||
_queue.length = newsize;
|
||||
}
|
||||
private TimerInfo[] expired() {
|
||||
long ts = currentTimeMillis;
|
||||
TimerInfo[] res;
|
||||
for (int i = 0; i < _queue.length; i++) {
|
||||
if (_queue[i].nextTimestamp <= ts)
|
||||
res ~= _queue[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/// returns true if at least one widget was notified
|
||||
bool notify() {
|
||||
bool res = false;
|
||||
checkValidWidgets();
|
||||
TimerInfo[] list = expired();
|
||||
if (list) {
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
Widget w = _queue[i].targetWidget;
|
||||
if (w && !isChild(w))
|
||||
_queue[i].cancel();
|
||||
else {
|
||||
_queue[i].notify();
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanup();
|
||||
return res;
|
||||
}
|
||||
private void checkValidWidgets() {
|
||||
for (int i = 0; i < _queue.length; i++) {
|
||||
Widget w = _queue[i].targetWidget;
|
||||
if (w && !isChild(w))
|
||||
_queue[i].cancel();
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -318,6 +318,27 @@ class Win32Window : Window {
|
|||
PostMessageW(_hwnd, CUSTOM_MESSAGE_ID, 0, event.uniqueId);
|
||||
}
|
||||
|
||||
private long _nextExpectedTimerTs;
|
||||
private UINT_PTR _timerId;
|
||||
|
||||
/// schedule timer for interval in milliseconds - call window.onTimer when finished
|
||||
override protected void scheduleSystemTimer(long intervalMillis) {
|
||||
if (intervalMillis < 10)
|
||||
intervalMillis = 10;
|
||||
long nextts = currentTimeMillis + intervalMillis;
|
||||
if (_timerId && _nextExpectedTimerTs && _nextExpectedTimerTs < nextts + 10)
|
||||
return; // don't reschedule timer, timer event will be received soon
|
||||
if (_hwnd) {
|
||||
_timerId = SetTimer(_hwnd, _timerId, cast(uint)intervalMillis, null);
|
||||
_nextExpectedTimerTs = nextts;
|
||||
}
|
||||
}
|
||||
|
||||
void handleTimer(UINT_PTR timerId) {
|
||||
onTimer();
|
||||
}
|
||||
|
||||
|
||||
Win32ColorDrawBuf getDrawBuf() {
|
||||
//RECT rect;
|
||||
//GetClientRect(_hwnd, &rect);
|
||||
|
@ -1062,6 +1083,12 @@ LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
return 1;
|
||||
}
|
||||
break;
|
||||
case WM_TIMER:
|
||||
if (window !is null) {
|
||||
window.handleTimer(wParam);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_GETMINMAXINFO:
|
||||
case WM_NCCREATE:
|
||||
case WM_NCCALCSIZE:
|
||||
|
|
|
@ -923,9 +923,21 @@ class Widget {
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
/// set new timer to call onTimer() after specified interval (for recurred notifications, return true from onTimer)
|
||||
ulong setTimer(long intervalMillis) {
|
||||
return window.setTimer(this, intervalMillis);
|
||||
}
|
||||
|
||||
/// cancel timer - pass value returned from setTimer() as timerId parameter
|
||||
void cancelTimer(ulong timerId) {
|
||||
window.cancelTimer(timerId);
|
||||
}
|
||||
|
||||
/// handle timer; return true to repeat timer event after next interval, false cancel timer
|
||||
bool onTimer(ulong id) {
|
||||
// override to do something useful
|
||||
// return true to repeat after the same interval, false to stop timer
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue