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