1 // TimeBar.cpp --- Time bar
2 //
3 // Copyright (C) 2004, 2005, 2006, 2007 Raymond Penners <raymond@dotsphinx.com>
4 // All rights reserved.
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19 // $Id$
20
21 #include <stdio.h>
22
23 #include "TimeBar.h"
24 #include "DeskBand.h"
25 #include "Debug.h"
26 #include "PaintHelper.h"
27
28 const int BORDER_SIZE = 2;
29 const int MARGINX = 4;
30 const int MARGINY = 0;
31 const int MINIMAL_HEIGHT = 16;
32
33 #define TIME_BAR_CLASS_NAME "WorkraveTimeBar"
34 #define GDK_TO_COLORREF(r, g, b) (((r)>>8) | (((g)>>8) <<8) | (((b)>>8) << 16))
35
36 HBRUSH TimeBar::bar_colors[ITimeBar::COLOR_ID_SIZEOF];
37 HFONT TimeBar::bar_font = NULL;
38
TimeBar(HWND parent,HINSTANCE hinst,CDeskBand * deskband)39 TimeBar::TimeBar(HWND parent, HINSTANCE hinst, CDeskBand *deskband)
40 : deskband(deskband)
41 {
42 init(hinst);
43
44 bar_text[0] = 0;
45 bar_max_value = 100;
46 bar_value = 0;
47 secondary_bar_max_value = 0;
48 secondary_bar_value = 100;
49 secondary_bar_color = ITimeBar::COLOR_ID_INACTIVE;
50 bar_color = ITimeBar::COLOR_ID_ACTIVE;
51
52 hwnd = CreateWindowEx(0, TIME_BAR_CLASS_NAME, "",
53 WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 56, 16, parent, NULL, hinst, (LPVOID)this );
54
55 paint_helper = new PaintHelper(hwnd);
56 compute_size(width, height);
57 SetWindowPos(hwnd, NULL, 0, 0, width, height, SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE);
58 }
59
~TimeBar()60 TimeBar::~TimeBar()
61 {
62 DestroyWindow(hwnd);
63 }
64
65 LRESULT CALLBACK
wnd_proc(HWND hWnd,UINT uMessage,WPARAM wParam,LPARAM lParam)66 TimeBar::wnd_proc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
67 {
68 TimeBar *pThis = (TimeBar*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
69
70 switch (uMessage)
71 {
72 case WM_NCCREATE:
73 {
74 LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
75 pThis = (TimeBar *)( lpcs->lpCreateParams );
76 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
77 SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
78 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );
79 }
80 break;
81
82 case WM_PAINT:
83 return pThis->on_paint();
84
85 case WM_LBUTTONUP:
86 SendMessage(pThis->deskband->get_command_window(), WM_USER + 1, 0, NULL);
87 break;
88 }
89 return DefWindowProc(hWnd, uMessage, wParam, lParam);
90 }
91
92 void
get_size(int & w,int & h)93 TimeBar::get_size(int &w, int &h)
94 {
95 w = width;
96 h = height;
97 }
98
99 void
compute_size(int & w,int & h)100 TimeBar::compute_size(int &w, int &h)
101 {
102 TRACE_ENTER("TimeBar::compute_size");
103 HDC dc = GetDC(hwnd);
104 SelectObject(dc, (HGDIOBJ) bar_font);
105 char buf[80];
106
107 time_to_string(-(59+59*60+9*60*60), buf, sizeof(buf));
108
109 RECT rect;
110 rect.left = 0;
111 rect.top = 0;
112 rect.bottom = 0;
113 rect.right = 0;
114 h= DrawText(dc, buf, (int)strlen( buf ), &rect, DT_CALCRECT);
115 if (! h)
116 {
117 w = 32;
118 h = 16;
119 }
120 else
121 {
122 w= rect.right;
123 }
124
125 w += 2*MARGINX + 2*BORDER_SIZE;
126 h += 2*MARGINY + 2*BORDER_SIZE;
127 if (h < MINIMAL_HEIGHT)
128 h = MINIMAL_HEIGHT;
129 ReleaseDC(hwnd, dc);
130
131 TRACE_MSG(w << " " << h);
132 TRACE_EXIT();
133 }
134
135 LRESULT
on_paint()136 TimeBar::on_paint()
137 {
138 TRACE_ENTER("TimeBar::on_paint");
139 RECT rc;
140
141 HDC dc = paint_helper->BeginPaint();
142
143 GetClientRect(hwnd, &rc);
144
145 RECT r;
146
147 int winx = rc.left, winy = rc.top, winw = rc.right-rc.left, winh = rc.bottom-rc.top;
148
149 SelectObject(dc, (HGDIOBJ) bar_font);
150 r.left = r.top = r.bottom = r.right = 0;
151
152 TRACE_MSG("1" << winx << " " << winy << " " << winw << " " << winh);
153 // Bar
154 int bar_width = 0;
155 int border_size = BORDER_SIZE;
156 if (bar_max_value > 0)
157 {
158 bar_width = (bar_value * (winw - 2 * border_size)) / bar_max_value;
159 }
160
161 // Secondary bar
162 int sbar_width = 0;
163 if (secondary_bar_max_value > 0)
164 {
165 sbar_width = (secondary_bar_value * (winw - 2 * border_size)) / secondary_bar_max_value;
166 }
167
168 int bar_h = winh - 2 * border_size;
169
170 TRACE_MSG("2");
171 if (sbar_width > 0)
172 {
173 // Overlap
174 //assert(secondary_bar_color == COLOR_ID_INACTIVE);
175 ITimeBar::ColorId overlap_color;
176 switch (bar_color)
177 {
178 case ITimeBar::COLOR_ID_ACTIVE:
179 overlap_color = ITimeBar::COLOR_ID_INACTIVE_OVER_ACTIVE;
180 break;
181 case ITimeBar::COLOR_ID_OVERDUE:
182 overlap_color = ITimeBar::COLOR_ID_INACTIVE_OVER_OVERDUE;
183 break;
184 default:
185 overlap_color = ITimeBar::COLOR_ID_BG;
186 }
187
188 if (sbar_width >= bar_width)
189 {
190 if (bar_width)
191 {
192 r.left = winx+ border_size ;
193 r.top = winy+ border_size ;
194 r.right = r.left + bar_width;
195 r.bottom = r.top + bar_h;
196 FillRect(dc, &r, bar_colors[overlap_color]);
197 }
198 if (sbar_width > bar_width)
199 {
200 r.left = winx + bar_width+ border_size ;
201 r.top = winy+ border_size ;
202 r.right = r.left + sbar_width - bar_width;
203 r.bottom = r.top + bar_h;
204 FillRect(dc, &r, bar_colors[secondary_bar_color]);
205 }
206 }
207 else
208 {
209 if (sbar_width)
210 {
211 r.left = winx+ border_size ;
212 r.top = winy+ border_size ;
213 r.right = r.left + sbar_width;
214 r.bottom = r.top + bar_h;
215 FillRect(dc, &r, bar_colors[overlap_color]);
216 }
217 r.left = winx + border_size + sbar_width;
218 r.top = winy + border_size ;
219 r.right = r.left + bar_width - sbar_width;
220 r.bottom = r.top + bar_h;
221 FillRect(dc, &r, bar_colors[bar_color]);
222 }
223 }
224 else
225 {
226 // No overlap
227 r.left = winx + border_size;
228 r.top = winy + border_size;
229 r.right = r.left + bar_width;
230 r.bottom = r.top + bar_h;
231 FillRect(dc, &r, bar_colors[bar_color]);
232 }
233
234 TRACE_MSG("3");
235 r.left = winx + border_size + __max(bar_width, sbar_width);
236 r.top = winy + border_size;
237 r.right = winx + winw - border_size;
238 r.bottom = r.top + bar_h;
239 FillRect(dc, &r, bar_colors[ITimeBar::COLOR_ID_BG]);
240
241 r.left = winx;
242 r.top = winy;
243 r.bottom = r.top + winh;
244 r.right = r.left + winw;
245 DrawEdge(dc, &r, BF_ADJUST|EDGE_SUNKEN,BF_RECT);
246
247 SetBkMode(dc, TRANSPARENT);
248 r.right -= border_size + MARGINX;
249 r.left += border_size + MARGINX;
250 DrawText(dc, bar_text, (int)strlen( bar_text ), &r, DT_SINGLELINE|DT_VCENTER|DT_RIGHT);
251
252 TRACE_MSG("4");
253
254 paint_helper->EndPaint();
255
256 TRACE_EXIT();
257 return 0;
258 }
259
260 void
init(HINSTANCE hinst)261 TimeBar::init(HINSTANCE hinst)
262 {
263 TRACE_ENTER("TimeBar::init");
264
265 //If the window class has not been registered, then do so.
266 WNDCLASS wc;
267 if (!GetClassInfo(hinst, TIME_BAR_CLASS_NAME, &wc))
268 {
269 ZeroMemory(&wc, sizeof(wc));
270 wc.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
271 wc.lpfnWndProc = (WNDPROC)wnd_proc;
272 wc.cbClsExtra = 0;
273 wc.cbWndExtra = 0;
274 wc.hInstance = hinst;
275 wc.hIcon = NULL;
276 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
277 wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(192, 0, 0));
278 wc.lpszMenuName = NULL;
279 wc.lpszClassName = TIME_BAR_CLASS_NAME;
280
281 RegisterClass(&wc);
282
283 HBRUSH green_mix_blue = CreateSolidBrush(0x00b2d400);
284 HBRUSH light_green = CreateSolidBrush(GDK_TO_COLORREF(37008,61166,37008));
285 HBRUSH orange = CreateSolidBrush(GDK_TO_COLORREF(65535, 42405, 0));
286 HBRUSH light_blue = CreateSolidBrush(GDK_TO_COLORREF(44461, 55512, 59110));
287 HBRUSH bg = CreateSolidBrush(GetSysColor(COLOR_3DLIGHT));
288
289 bar_colors[ITimeBar::COLOR_ID_ACTIVE] = light_blue;
290 bar_colors[ITimeBar::COLOR_ID_INACTIVE] = light_green;
291 bar_colors[ITimeBar::COLOR_ID_OVERDUE] = orange;
292 bar_colors[ITimeBar::COLOR_ID_INACTIVE_OVER_ACTIVE] = green_mix_blue;
293 bar_colors[ITimeBar::COLOR_ID_INACTIVE_OVER_OVERDUE] = light_green;
294 bar_colors[ITimeBar::COLOR_ID_BG] = bg;
295
296 NONCLIENTMETRICS_PRE_VISTA_STRUCT ncm;
297 LOGFONT lfDefault =
298 // the default status font info on my system:
299 {
300 -12, 0, 0, 0, 400, 0, 0, 0, '\1', 0, 0, 0, 0, TEXT( "Tahoma" )
301 //0, 0x00146218, 0, 0x001461F0, 0, '@', 0, 0, 0, 0, 0, 0, 0, TEXT( "�~" )
302 };
303
304 ZeroMemory( &ncm, sizeof( ncm ) );
305 ncm.cbSize = sizeof( ncm );
306 ncm.lfStatusFont = lfDefault;
307
308 if (!SystemParametersInfo( SPI_GETNONCLIENTMETRICS, sizeof( ncm ), &ncm, 0 ))
309 // If SystemParametersInfo fails, use my default.
310 // Now that we're filling a pre-vista NCM struct, there
311 // shouldn't be any problem though, regardless of target.
312 {
313 ncm.lfStatusFont = lfDefault;
314 }
315
316 bar_font = CreateFontIndirect(&ncm.lfStatusFont);
317 }
318 TRACE_EXIT();
319 }
320
321
322 //! Converts the specified time to a string
323 void
time_to_string(time_t time,char * buf,int len)324 TimeBar::time_to_string(time_t time, char *buf, int len)
325 {
326 char t[2];
327
328 if (time < 0)
329 {
330 t[0] = '-';
331 t[1] = 0;
332 time = -time;
333 }
334 else
335 {
336 t[0] = 0;
337 }
338 int hrs = (int)( time / 3600 );
339 int min = (int)( (time / 60) % 60 );
340 int sec = (int)( time % 60 );
341
342 if (hrs > 0)
343 {
344 _snprintf_s( buf, len, _TRUNCATE, "%s%d:%02d:%02d", t, hrs, min, sec );
345 }
346 else
347 {
348 _snprintf_s( buf, len, _TRUNCATE, "%s%d:%02d", t, min, sec );
349 }
350 }
351
352
353 void
set_progress(int value,int max_value)354 TimeBar::set_progress(int value, int max_value)
355 {
356 bar_value = value;
357 bar_max_value = max_value;
358 }
359
360 void
set_secondary_progress(int value,int max_value)361 TimeBar::set_secondary_progress(int value, int max_value)
362 {
363 secondary_bar_value = value;
364 secondary_bar_max_value = max_value;
365 }
366
367 void
set_text(const char * text)368 TimeBar::set_text(const char *text)
369 {
370 TRACE_ENTER("TimeBar::set_text");
371 strncpy_s(bar_text, APPLET_BAR_TEXT_MAX_LENGTH, text, _TRUNCATE);
372 TRACE_EXIT();
373 }
374
375 void
update()376 TimeBar::update()
377 {
378 TRACE_ENTER("TimeBar::update");
379 InvalidateRect(hwnd, NULL, FALSE);
380 TRACE_EXIT();
381 }
382
383 void
set_bar_color(ITimeBar::ColorId color)384 TimeBar::set_bar_color(ITimeBar::ColorId color)
385 {
386 bar_color = color;
387 }
388
389 void
set_secondary_bar_color(ITimeBar::ColorId color)390 TimeBar::set_secondary_bar_color(ITimeBar::ColorId color)
391 {
392 secondary_bar_color = color;
393 }
394