#define _NIMLIB_
#include<khuidefs.h>
#include<commctrl.h>
#include<assert.h>
#define K5_SLIDER_WIDTH 208
#define K5_SLIDER_HEIGHT 40
#define K5_SLIDER_LBL_HPAD 5
#define K5_SLIDER_LBL_VPAD 22
#define KHUI_TRACKER_PROP L"KhmTrackerData"
int time_t_to_ticks(time_t tmin, time_t tmax)
{
int c = 0;
time_t lo, hi;
tmin -= tmin % 60;
if(tmax % 60)
tmax += 60 - (tmax % 60);
lo = tmin;
#define TFORWARD(limit,gran) \
if(lo < limit && lo < tmax) { \
hi = min(tmax, limit); \
c += (int)((hi - lo) / (gran)); \
lo = hi; \
}
TFORWARD(300,60);
TFORWARD(3600,300);
TFORWARD(3600*4, 60*15);
TFORWARD(3600*10,60*30);
TFORWARD(3600*24,3600);
TFORWARD(3600*24*4,3600*6);
TFORWARD(((time_t)(INFINITE & INT_MAX)),3600*24);
#undef TFORWARD
return c;
}
time_t ticks_to_time_t(int ticks, time_t tmin)
{
int c = 0;
tmin -= tmin % 60;
#define SFORWARD(limit,gran) \
if(tmin < limit && ticks > 0) { \
c = (int) min(ticks, (limit - tmin) / (gran)); \
tmin += c * gran; \
ticks -= c; \
}
SFORWARD(300,60);
SFORWARD(3600,300);
SFORWARD(3600*4,60*15);
SFORWARD(3600*10,60*30);
SFORWARD(3600*24,3600);
SFORWARD(3600*24*4,3600*6);
SFORWARD(((time_t)(INFINITE & INT_MAX)),3600*24);
#undef SFORWARD
return tmin;
}
void
initialize_tracker(HWND hwnd,
khui_tracker * tc)
{
RECT r;
FILETIME ft;
wchar_t wbuf[256];
khm_size cbbuf;
SendMessage(tc->hw_slider, TBM_SETRANGE, 0, MAKELONG(0, time_t_to_ticks(tc->min, tc->max)));
SendMessage(tc->hw_slider, TBM_SETPOS, TRUE, (LPARAM) time_t_to_ticks(tc->min, tc->current));
r.left = K5_SLIDER_LBL_HPAD;
r.top = K5_SLIDER_LBL_VPAD;
r.right = K5_SLIDER_WIDTH - K5_SLIDER_LBL_HPAD;
r.bottom = r.top;
MapDialogRect(hwnd, &r);
tc->lbl_y = r.top;
tc->lbl_lx = r.left;
tc->lbl_rx = r.right;
TimetToFileTimeInterval(tc->current, &ft);
cbbuf = sizeof(wbuf);
FtIntervalToString(&ft, wbuf, &cbbuf);
SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM)wbuf);
}
LRESULT CALLBACK
duration_tracker_proc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
khui_tracker * tc;
tc = (khui_tracker *) GetProp(hwnd, KHUI_TRACKER_PROP);
#ifdef DEBUG
assert(tc != NULL);
#endif
switch(uMsg) {
case WM_PAINT:
{
HDC hdc;
HFONT hf, hfold;
LRESULT lr;
FILETIME ft;
wchar_t buf[256];
khm_size cbbuf;
lr = CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam);
hdc = GetWindowDC(hwnd);
hf = (HFONT) SendMessage(tc->hw_edit, WM_GETFONT, 0, 0);
hfold = ((HFONT) SelectObject((hdc), (HGDIOBJ)(HFONT)(hf)));
TimetToFileTimeInterval(tc->min, &ft);
cbbuf = sizeof(buf);
FtIntervalToString(&ft, buf, &cbbuf);
SetTextColor(hdc, RGB(0,0,0));
SetBkMode(hdc, TRANSPARENT);
SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP);
TextOut(hdc, tc->lbl_lx, tc->lbl_y, buf, (int) wcslen(buf));
TimetToFileTimeInterval(tc->max, &ft);
cbbuf = sizeof(buf);
FtIntervalToString(&ft, buf, &cbbuf);
SetTextAlign(hdc, TA_RIGHT | TA_TOP | TA_NOUPDATECP);
TextOut(hdc, tc->lbl_rx, tc->lbl_y, buf, (int) wcslen(buf));
((HFONT) SelectObject((hdc), (HGDIOBJ)(HFONT)(hfold)));
ReleaseDC(hwnd, hdc);
return lr;
}
break;
case WM_KILLFOCUS:
{
if((HWND)wParam != tc->hw_edit)
ShowWindow(hwnd, SW_HIDE);
}
break;
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
{
LRESULT lr;
lr = CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam);
if(wParam & MK_LBUTTON) {
int c = (int) SendMessage(hwnd, TBM_GETPOS, 0, 0);
time_t t = ticks_to_time_t(c, tc->min);
if(t != tc->current) {
wchar_t buf[256];
FILETIME ft;
khm_size cbbuf;
tc->current = t;
cbbuf = sizeof(buf);
TimetToFileTimeInterval(t, &ft);
FtIntervalToString(&ft, buf, &cbbuf);
SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM) buf);
}
}
return lr;
}
}
return CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam);
}
void
create_edit_sliders(HWND hwnd,
HWND hwnd_dlg,
khui_tracker * tc)
{
RECT r;
RECT rs;
GetWindowRect(hwnd, &r);
rs.top = 0;
rs.left = 0;
rs.right = K5_SLIDER_WIDTH;
rs.bottom = K5_SLIDER_HEIGHT;
MapDialogRect(hwnd_dlg, &rs);
rs.right -= rs.left;
rs.bottom -= rs.top;
tc->hw_slider =
CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TRACKBAR_CLASS,
L"NetIDMgrTimeTickerTrackbar",
WS_POPUP | TBS_AUTOTICKS | TBS_BOTTOM |
#if (_WIN32_IE >= 0x0501)
TBS_DOWNISLEFT |
#endif
TBS_HORZ | WS_CLIPCHILDREN,
r.left,r.bottom,rs.right,rs.bottom,
hwnd,
NULL,
(HINSTANCE)(DWORD_PTR)
GetWindowLongPtr(hwnd, GWLP_HINSTANCE),
NULL);
SetProp(tc->hw_slider, KHUI_TRACKER_PROP,
(HANDLE) tc);
#pragma warning(push)
#pragma warning(disable: 4244)
tc->fn_tracker = (WNDPROC)(LONG_PTR) SetWindowLongPtr(tc->hw_slider, GWLP_WNDPROC, (LONG_PTR) duration_tracker_proc);
#pragma warning(pop)
}
LRESULT CALLBACK
duration_edit_proc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
khui_tracker * tc;
tc = (khui_tracker *) GetProp(hwnd, KHUI_TRACKER_PROP);
#ifdef DEBUG
assert(tc != NULL);
#endif
switch(uMsg) {
case WM_SETFOCUS:
{
HWND p;
p = GetParent(hwnd);
if(tc->hw_slider == NULL) {
create_edit_sliders(hwnd, p, tc);
initialize_tracker(p, tc);
}
khui_tracker_reposition(tc);
#ifdef SHOW_PANEL_ON_FIRST_ACTIVATE
ShowWindow(tc->hw_slider, SW_SHOWNOACTIVATE);
#endif
tc->act_time = GetTickCount();
}
break;
case WM_KILLFOCUS:
{
wchar_t wbuf[256];
FILETIME ft;
khm_size cbbuf;
if((HWND) wParam != tc->hw_slider)
ShowWindow(tc->hw_slider, SW_HIDE);
TimetToFileTimeInterval(tc->current, &ft);
cbbuf = sizeof(wbuf);
FtIntervalToString(&ft, wbuf, &cbbuf);
SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM)wbuf);
}
break;
case KHUI_WM_NC_NOTIFY:
if(HIWORD(wParam) == WMNC_DIALOG_SETUP) {
HWND p;
p = GetParent(hwnd);
if(tc->hw_slider == NULL) {
create_edit_sliders(hwnd,p,tc);
}
initialize_tracker(p, tc);
}
return TRUE;
case WM_LBUTTONUP:
if (IsWindowVisible(tc->hw_slider)) {
DWORD tm;
tm = GetTickCount();
if (tm - tc->act_time > 000)
ShowWindow(tc->hw_slider, SW_HIDE);
} else {
ShowWindow(tc->hw_slider, SW_SHOWNOACTIVATE);
}
break;
case EM_REPLACESEL:
case EM_UNDO:
case WM_UNDO:
case WM_CHAR:
#if (_WIN32_WINNT >= 0x0501)
case WM_UNICHAR:
#endif
{
wchar_t buf[256];
size_t nchars;
time_t ts;
FILETIME ft;
BOOL modified;
LRESULT lr = CallWindowProc(tc->fn_edit, hwnd, uMsg, wParam, lParam);
modified = (BOOL) SendMessage(hwnd, EM_GETMODIFY, 0, 0);
if(modified) {
if(nchars = (size_t) SendMessage(hwnd, WM_GETTEXT, ARRAYLENGTH(buf), (LPARAM) buf)) {
buf[nchars] = 0;
if(KHM_SUCCEEDED(IntervalStringToFt(&ft, buf))) {
ts = FtIntervalToSeconds(&ft);
if(ts >= tc->min && ts <= tc->max) {
tc->current = ts;
if(tc->hw_slider != NULL)
SendMessage(tc->hw_slider, TBM_SETPOS, TRUE, (LPARAM) time_t_to_ticks(tc->min, tc->current));
}
}
}
SendMessage(hwnd, EM_SETMODIFY, FALSE, 0);
}
return lr;
}
}
return CallWindowProc(tc->fn_edit, hwnd, uMsg, wParam, lParam);
}
KHMEXP void KHMAPI
khui_tracker_install(HWND hwnd_edit, khui_tracker * tc) {
#ifdef DEBUG
assert(hwnd_edit);
assert(tc);
#endif
tc->hw_edit = hwnd_edit;
SetProp(hwnd_edit, KHUI_TRACKER_PROP, (HANDLE) tc);
#pragma warning(push)
#pragma warning(disable: 4244)
tc->fn_edit = (WNDPROC)(LONG_PTR)
SetWindowLongPtr(hwnd_edit, GWLP_WNDPROC,
(LONG_PTR) duration_edit_proc);
#pragma warning(pop)
}
KHMEXP void KHMAPI
khui_tracker_reposition(khui_tracker * tc) {
RECT r;
if(tc->hw_slider && tc->hw_edit) {
GetWindowRect(tc->hw_edit, &r);
SetWindowPos(tc->hw_slider,
NULL,
r.left, r.bottom,
0, 0,
SWP_NOOWNERZORDER | SWP_NOSIZE |
SWP_NOZORDER | SWP_NOACTIVATE);
}
}
KHMEXP void KHMAPI
khui_tracker_initialize(khui_tracker * tc) {
ZeroMemory(tc, sizeof(*tc));
}
KHMEXP void KHMAPI
khui_tracker_refresh(khui_tracker * tc) {
if (!tc->hw_edit)
return;
SendMessage(tc->hw_edit,
KHUI_WM_NC_NOTIFY,
MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0);
}
KHMEXP void KHMAPI
khui_tracker_kill_controls(khui_tracker * tc) {
if (tc->hw_slider)
DestroyWindow(tc->hw_slider);
if (tc->hw_edit)
DestroyWindow(tc->hw_edit);
tc->hw_slider = NULL;
tc->hw_edit = NULL;
tc->fn_edit = NULL;
tc->fn_tracker = NULL;
}