update for HEAD-2003091401
[reactos.git] / subsys / system / explorer / utility / window.cpp
1 /*
2  * Copyright 2003 Martin Fuchs
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20  //
21  // Explorer clone
22  //
23  // window.cpp
24  //
25  // Martin Fuchs, 23.07.2003
26  //
27
28
29 #include "utility.h"
30 #include "shellclasses.h"
31 #include "window.h"
32
33 #include "../globals.h"
34
35
36 WindowClass::WindowClass(LPCTSTR classname, UINT style_, WNDPROC wndproc)
37 {
38         memset(this, 0, sizeof(WNDCLASSEX));
39
40         cbSize = sizeof(WNDCLASSEX);
41         style = style_;
42         hInstance = g_Globals._hInstance;
43         hCursor = LoadCursor(0, IDC_ARROW);
44
45         lpszClassName = classname;
46         lpfnWndProc = wndproc;
47
48         _atomClass = 0;
49 }
50
51
52 IconWindowClass::IconWindowClass(LPCTSTR classname, UINT nid, UINT style, WNDPROC wndproc)
53  :      WindowClass(classname, style, wndproc)
54 {
55         hIcon = ResIcon(nid);
56         hIconSm = SmallIcon(nid);
57 }
58
59
60 Window::WindowMap       Window::s_wnd_map;
61
62 Window::CREATORFUNC     Window::s_window_creator = NULL;
63 const void*                     Window::s_new_info = NULL;
64
65 HHOOK                           Window::s_hcbtHook = 0;
66
67
68 Window::StaticWindowData& Window::GetStaticWindowData()
69 {
70         static StaticWindowData s_initialized_data;
71
72         return s_initialized_data;
73 }
74
75
76 Window::Window(HWND hwnd)
77  :      WindowHandle(hwnd)
78 {
79         Lock lock(GetStaticWindowData()._map_crit_sect);        // protect access to s_wnd_map
80
81         s_wnd_map[_hwnd] = this;
82 }
83
84 Window::~Window()
85 {
86         Lock lock(GetStaticWindowData()._map_crit_sect);        // protect access to s_wnd_map
87
88         s_wnd_map.erase(_hwnd);
89 }
90
91
92 HWND Window::Create(CREATORFUNC creator, DWORD dwExStyle,
93                                         LPCTSTR lpClassName, LPCTSTR lpWindowName,
94                                         DWORD dwStyle, int x, int y, int w, int h,
95                                         HWND hwndParent, HMENU hMenu, LPVOID lpParam)
96 {
97         Lock lock(GetStaticWindowData()._create_crit_sect);     // protect access to s_window_creator and s_new_info
98
99         s_window_creator = creator;
100         s_new_info = NULL;
101
102         return CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle,
103                                                         x, y, w, h,
104                                                         hwndParent, hMenu, g_Globals._hInstance, 0/*lpParam*/);
105 }
106
107 HWND Window::Create(CREATORFUNC creator, const void* info, DWORD dwExStyle,
108                                         LPCTSTR lpClassName, LPCTSTR lpWindowName,
109                                         DWORD dwStyle, int x, int y, int w, int h,
110                                         HWND hwndParent, HMENU hMenu, LPVOID lpParam)
111 {
112         Lock lock(GetStaticWindowData()._create_crit_sect);     // protect access to s_window_creator and s_new_info
113
114         s_window_creator = creator;
115         s_new_info = info;
116
117         return CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle,
118                                                         x, y, w, h,
119                                                         hwndParent, hMenu, g_Globals._hInstance, 0/*lpParam*/);
120 }
121
122
123 static Window* s_new_child_wnd = NULL;
124
125 Window* Window::create_mdi_child(HWND hmdiclient, const MDICREATESTRUCT& mcs, CREATORFUNC creator, const void* info)
126 {
127         Lock lock(GetStaticWindowData()._create_crit_sect);     // protect access to s_window_creator and s_new_info
128
129         s_window_creator = creator;
130         s_new_info = info;
131         s_new_child_wnd = NULL;
132
133         s_hcbtHook = SetWindowsHookEx(WH_CBT, CBTHookProc, 0, GetCurrentThreadId());
134
135         HWND hwnd = (HWND) SendMessage(hmdiclient, WM_MDICREATE, 0, (LPARAM)&mcs);
136
137         UnhookWindowsHookEx(s_hcbtHook);
138
139         Window* child = s_new_child_wnd;
140         s_new_info = NULL;
141         s_new_child_wnd = NULL;
142
143         if (!hwnd || !child || !child->_hwnd)
144                 child = NULL;
145
146         return child;
147 }
148
149 LRESULT CALLBACK Window::CBTHookProc(int code, WPARAM wparam, LPARAM lparam)
150 {
151         if (code == HCBT_CREATEWND) {
152                  // create Window controller and associate it with the window handle
153                 Window* child = get_window((HWND)wparam);
154
155                 if (child)
156                         s_new_child_wnd = child;
157         }
158
159         return CallNextHookEx(s_hcbtHook, code, wparam, lparam);
160 }
161
162
163  // get window controller from window handle
164  // if not already present, create a new controller
165
166 Window* Window::get_window(HWND hwnd)
167 {
168         {
169                 Lock lock(GetStaticWindowData()._map_crit_sect);        // protect access to s_wnd_map
170
171                 WindowMap::const_iterator found = s_wnd_map.find(hwnd);
172
173                 if (found!=s_wnd_map.end())
174                         return found->second;
175         }
176
177         if (s_window_creator) { // protect for recursion
178                 Lock lock(GetStaticWindowData()._create_crit_sect);     // protect access to s_window_creator and s_new_info
179
180                 const void* info = s_new_info;
181                 s_new_info = NULL;
182
183                 CREATORFUNC window_creator = s_window_creator;
184                 s_window_creator = NULL;
185
186                 if (info)
187                         return window_creator(hwnd, info);
188                 else
189                         return CREATORFUNC_NO_INFO(window_creator)(hwnd);
190         }
191
192         return NULL;
193 }
194
195
196 LRESULT Window::Init(LPCREATESTRUCT pcs)
197 {
198         return 0;
199 }
200
201
202 LRESULT CALLBACK Window::WindowWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
203 {
204         Window* pThis = get_window(hwnd);
205
206         if (pThis) {
207                 switch(nmsg) {
208                   case WM_COMMAND:
209                         return pThis->Command(LOWORD(wparam), HIWORD(wparam));
210
211                   case WM_NOTIFY:
212                         return pThis->Notify(wparam, (NMHDR*)lparam);
213
214                   case WM_CREATE:
215                         return pThis->Init((LPCREATESTRUCT)lparam);
216
217                   case WM_NCDESTROY:
218                         delete pThis;
219                         return 0;
220
221                   default:
222                         return pThis->WndProc(nmsg, wparam, lparam);
223                 }
224         }
225         else
226                 return DefWindowProc(hwnd, nmsg, wparam, lparam);
227 }
228
229 LRESULT Window::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
230 {
231 /*@@TODO: replaced by StartMenu::TrackStartmenu()
232         HWND hwnd = _hwnd;
233
234          // close startup menu and other popup menus
235          // This functionality is for tray notification icons missing in MS Windows.
236         if (nmsg == WM_SETFOCUS)
237                 CancelModes((HWND)wparam);      // erronesly cancels desktop bar resize when switching from another process
238 */
239
240         return DefWindowProc(_hwnd, nmsg, wparam, lparam);
241 }
242
243 int Window::Command(int id, int code)
244 {
245         return 0;
246 }
247
248 int Window::Notify(int id, NMHDR* pnmh)
249 {
250         return 0;
251 }
252
253 void Window::CancelModes(HWND hwnd)
254 {
255         if (hwnd)
256                 PostMessage(hwnd, WM_CANCELMODE, 0, 0);
257         else
258                 PostMessage(HWND_BROADCAST, WM_CANCELMODE, 0, 0);
259 }
260
261
262 SubclassedWindow::SubclassedWindow(HWND hwnd)
263  :      super(hwnd)
264 {
265         _orgWndProc = SubclassWindow(_hwnd, WindowWndProc);
266
267         if (!_orgWndProc)
268                 delete this;
269 }
270
271 LRESULT SubclassedWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
272 {
273 /*@@TODO: replaced by StartMenu::TrackStartmenu()
274          // close startup menu and other popup menus
275          // This functionality is for tray notification icons missing in MS Windows.
276         if (nmsg == WM_SETFOCUS)
277                 CancelModes((HWND)wparam);
278 */
279         return CallWindowProc(_orgWndProc, _hwnd, nmsg, wparam, lparam);
280 }
281
282
283 ChildWindow::ChildWindow(HWND hwnd)
284  :      super(hwnd)
285 {
286         _focus_pane = 0;
287         _split_pos = DEFAULT_SPLIT_POS;
288         _last_split = DEFAULT_SPLIT_POS;
289 }
290
291
292 ChildWindow* ChildWindow::create(HWND hmdiclient, const RECT& rect, CREATORFUNC creator, LPCTSTR classname, LPCTSTR title, const void* info)
293 {
294         MDICREATESTRUCT mcs;
295
296         mcs.szClass = classname;
297         mcs.szTitle = title;
298         mcs.hOwner      = g_Globals._hInstance;
299         mcs.x           = rect.left,
300         mcs.y           = rect.top;
301         mcs.cx          = rect.right - rect.left;
302         mcs.cy          = rect.bottom - rect.top;
303         mcs.style       = 0;
304         mcs.lParam      = 0;
305
306         return static_cast<ChildWindow*>(create_mdi_child(hmdiclient, mcs, creator, info));
307 }
308
309
310 LRESULT ChildWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
311 {
312         switch(nmsg) {
313           case WM_PAINT: {
314                 PaintCanvas canvas(_hwnd);
315                 ClientRect rt(_hwnd);
316                 rt.left = _split_pos-SPLIT_WIDTH/2;
317                 rt.right = _split_pos+SPLIT_WIDTH/2+1;
318                 HBRUSH lastBrush = SelectBrush(canvas, GetStockBrush(COLOR_SPLITBAR));
319                 Rectangle(canvas, rt.left, rt.top-1, rt.right, rt.bottom+1);
320                 SelectObject(canvas, lastBrush);
321                 break;}
322
323           case WM_SETCURSOR:
324                 if (LOWORD(lparam) == HTCLIENT) {
325                         POINT pt;
326                         GetCursorPos(&pt);
327                         ScreenToClient(_hwnd, &pt);
328
329                         if (pt.x>=_split_pos-SPLIT_WIDTH/2 && pt.x<_split_pos+SPLIT_WIDTH/2+1) {
330                                 SetCursor(LoadCursor(0, IDC_SIZEWE));
331                                 return TRUE;
332                         }
333                 }
334                 goto def;
335
336           case WM_SIZE:
337                 if (wparam != SIZE_MINIMIZED)
338                         resize_children(LOWORD(lparam), HIWORD(lparam));
339                 goto def;
340
341           case WM_GETMINMAXINFO:
342                 DefMDIChildProc(_hwnd, nmsg, wparam, lparam);
343
344                 {LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
345
346                 lpmmi->ptMaxTrackSize.x <<= 1;  // 2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN
347                 lpmmi->ptMaxTrackSize.y <<= 1;  // 2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN
348                 break;}
349
350           case WM_LBUTTONDOWN: {
351                 int x = GET_X_LPARAM(lparam);
352
353                 ClientRect rt(_hwnd);
354
355                 if (x>=_split_pos-SPLIT_WIDTH/2 && x<_split_pos+SPLIT_WIDTH/2+1) {
356                         _last_split = _split_pos;
357                         SetCapture(_hwnd);
358                 }
359
360                 break;}
361
362           case WM_LBUTTONUP:
363                 if (GetCapture() == _hwnd)
364                         ReleaseCapture();
365                 break;
366
367           case WM_KEYDOWN:
368                 if (wparam == VK_ESCAPE)
369                         if (GetCapture() == _hwnd) {
370                                 _split_pos = _last_split;
371                                 ClientRect rt(_hwnd);
372                                 resize_children(rt.right, rt.bottom);
373                                 _last_split = -1;
374                                 ReleaseCapture();
375                                 SetCursor(LoadCursor(0, IDC_ARROW));
376                         }
377                 break;
378
379           case WM_MOUSEMOVE:
380                 if (GetCapture() == _hwnd) {
381                         int x = LOWORD(lparam);
382
383                         ClientRect rt(_hwnd);
384
385                         if (x>=0 && x<rt.right) {
386                                 _split_pos = x;
387                                 resize_children(rt.right, rt.bottom);
388                                 rt.left = x-SPLIT_WIDTH/2;
389                                 rt.right = x+SPLIT_WIDTH/2+1;
390                                 InvalidateRect(_hwnd, &rt, FALSE);
391                                 UpdateWindow(_left_hwnd);
392                                 UpdateWindow(_hwnd);
393                                 UpdateWindow(_right_hwnd);
394                         }
395                 }
396                 break;
397
398           case PM_DISPATCH_COMMAND:
399                 return FALSE;
400
401           default: def:
402                 return DefMDIChildProc(_hwnd, nmsg, wparam, lparam);
403         }
404
405         return 0;
406 }
407
408
409 void ChildWindow::resize_children(int cx, int cy)
410 {
411         HDWP hdwp = BeginDeferWindowPos(4);
412         RECT rt;
413
414         rt.left   = 0;
415         rt.top    = 0;
416         rt.right  = cx;
417         rt.bottom = cy;
418
419         if (_left_hwnd) {
420                 cx = _split_pos + SPLIT_WIDTH/2;
421
422                 hdwp = DeferWindowPos(hdwp, _left_hwnd, 0, rt.left, rt.top, _split_pos-SPLIT_WIDTH/2-rt.left, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
423         } else {
424                 _split_pos = 0;
425                 cx = 0;
426         }
427
428         hdwp = DeferWindowPos(hdwp, _right_hwnd, 0, rt.left+cx+1, rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
429
430         EndDeferWindowPos(hdwp);
431 }
432
433
434 WindowSet Window::s_pretranslate_windows;
435
436 void Window::register_pretranslate(HWND hwnd)
437 {
438         s_pretranslate_windows.insert(hwnd);
439 }
440
441 void Window::unregister_pretranslate(HWND hwnd)
442 {
443         s_pretranslate_windows.erase(hwnd);
444 }
445
446 BOOL Window::pretranslate_msg(LPMSG pmsg)
447 {
448         for(WindowSet::const_iterator it=Window::s_pretranslate_windows.begin(); it!=s_pretranslate_windows.end(); ++it)
449                 if (SendMessage(*it, PM_TRANSLATE_MSG, 0, (LPARAM)pmsg))
450                         return TRUE;
451
452         return FALSE;
453 }
454
455
456 WindowSet Window::s_dialogs;
457
458 void Window::register_dialog(HWND hwnd)
459 {
460         s_dialogs.insert(hwnd);
461 }
462
463 void Window::unregister_dialog(HWND hwnd)
464 {
465         s_dialogs.erase(hwnd);
466 }
467
468 BOOL Window::dispatch_dialog_msg(MSG* pmsg)
469 {
470         for(WindowSet::const_iterator it=Window::s_dialogs.begin(); it!=s_dialogs.end(); ++it)
471                 if (IsDialogMessage(*it, pmsg))
472                         return TRUE;
473
474         return FALSE;
475 }
476
477
478 int Window::MessageLoop()
479 {
480         MSG msg;
481
482         while(GetMessage(&msg, 0, 0, 0)) {
483                 try {
484                         if (pretranslate_msg(&msg))
485                                 continue;
486
487                         if (dispatch_dialog_msg(&msg))
488                                 continue;
489
490                         TranslateMessage(&msg);
491
492                         try {
493                                 DispatchMessage(&msg);
494                         } catch(COMException& e) {
495                                 HandleException(e, g_Globals._hMainWnd);
496                         }
497                 } catch(COMException& e) {
498                         HandleException(e, g_Globals._hMainWnd);
499                 }
500         }
501
502         return msg.wParam;
503 }
504
505
506 LRESULT Window::SendParent(UINT nmsg, WPARAM wparam, LPARAM lparam)
507 {
508         HWND parent = GetParent(_hwnd);
509
510         if (!parent)
511                 return 0;
512
513         return SendMessage(parent, nmsg, wparam, lparam);
514 }
515
516 LRESULT Window::PostParent(UINT nmsg, WPARAM wparam, LPARAM lparam)
517 {
518         HWND parent = GetParent(_hwnd);
519
520         if (!parent)
521                 return 0;
522
523         return PostMessage(parent, nmsg, wparam, lparam);
524 }
525
526
527 PreTranslateWindow::PreTranslateWindow(HWND hwnd)
528  :      super(hwnd)
529 {
530         register_pretranslate(hwnd);
531 }
532
533 PreTranslateWindow::~PreTranslateWindow()
534 {
535         unregister_pretranslate(_hwnd);
536 }
537
538
539 Dialog::Dialog(HWND hwnd)
540  :      super(hwnd)
541 {
542         register_dialog(hwnd);
543 }
544
545 Dialog::~Dialog()
546 {
547         unregister_dialog(_hwnd);
548 }
549
550
551 Button::Button(HWND parent, LPCTSTR title, int left, int top, int width, int height,
552                                 int id, DWORD flags, DWORD exStyle)
553  :      WindowHandle(CreateWindowEx(exStyle, TEXT("BUTTON"), title, flags, left, top, width, height,
554                                                         parent, (HMENU)id, g_Globals._hInstance, 0))
555 {
556 }
557
558
559 LRESULT OwnerdrawnButton::WndProc(UINT message, WPARAM wparam, LPARAM lparam)
560 {
561         if (message == PM_DISPATCH_DRAWITEM) {
562                 DrawItem((LPDRAWITEMSTRUCT)lparam);
563                 return TRUE;
564         } else
565                 return super::WndProc(message, wparam, lparam);
566 }
567
568
569 Static::Static(HWND parent, LPCTSTR title, int left, int top, int width, int height,
570                                 int id, DWORD flags, DWORD exStyle)
571  :      WindowHandle(CreateWindowEx(exStyle, TEXT("STATIC"), title, flags, left, top, width, height,
572                                                         parent, (HMENU)id, g_Globals._hInstance, 0))
573 {
574 }
575
576
577 static RECT s_MyDrawText_Rect = {0, 0, 0, 0};
578
579 static BOOL CALLBACK MyDrawText(HDC hdc, LPARAM data, int cnt)
580 {
581         ::DrawText(hdc, (LPCTSTR)data, cnt, &s_MyDrawText_Rect, DT_SINGLELINE);
582         return TRUE;
583 }
584
585 void OwnerdrawnButton::DrawGrayText(LPDRAWITEMSTRUCT dis, LPRECT pRect, LPCTSTR title, int dt_flags)
586 {
587         COLORREF gray = GetSysColor(COLOR_GRAYTEXT);
588
589         if (gray) {
590                 TextColor lcColor(dis->hDC, GetSysColor(COLOR_BTNHIGHLIGHT));
591                 RECT shadowRect = {pRect->left+1, pRect->top+1, pRect->right+1, pRect->bottom+1};
592                 DrawText(dis->hDC, title, -1, &shadowRect, dt_flags);
593
594                 SetTextColor(dis->hDC, gray);
595                 DrawText(dis->hDC, title, -1, pRect, dt_flags);
596         } else {
597                 int old_r = pRect->right;
598                 int old_b = pRect->bottom;
599
600                 DrawText(dis->hDC, title, -1, pRect, dt_flags|DT_CALCRECT);
601
602                 int x = pRect->left + (old_r-pRect->right)/2;
603                 int y = pRect->top + (old_b-pRect->bottom)/2;
604                 int w = pRect->right-pRect->left;
605                 int h = pRect->bottom-pRect->top;
606                 s_MyDrawText_Rect.right = w;
607                 s_MyDrawText_Rect.bottom = h;
608
609                 GrayString(dis->hDC, GetSysColorBrush(COLOR_GRAYTEXT), MyDrawText, (LPARAM)title, -1, x, y, w, h);
610         }
611 }
612
613
614 static BOOL DrawButton(HDC hdc, LPRECT prect, UINT state, HBRUSH hbrush)
615 {
616         FillRect(hdc, prect, hbrush);
617         DrawEdge(hdc, prect, EDGE_RAISED, BF_RECT|BF_SOFT);
618
619         return TRUE;
620 }
621
622
623 /* not yet used
624 void ColorButton::DrawItem(LPDRAWITEMSTRUCT dis)
625 {
626         UINT state = DFCS_BUTTONPUSH;
627
628         if (dis->itemState & ODS_DISABLED)
629                 state |= DFCS_INACTIVE;
630
631         RECT textRect = {dis->rcItem.left+2, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
632
633         if (dis->itemState & ODS_SELECTED) {
634                 state |= DFCS_PUSHED;
635                 ++textRect.left;        ++textRect.top;
636                 ++textRect.right;       ++textRect.bottom;
637         }
638
639         DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state);
640         //DrawButton(dis->hDC, &dis->rcItem, state, GetSysColorBrush(COLOR_BTNFACE));
641
642         TCHAR title[BUFFER_LEN];
643         GetWindowText(_hwnd, title, BUFFER_LEN);
644
645         BkMode bk_mode(dis->hDC, TRANSPARENT);
646
647         if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
648                 DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
649         else {
650                 TextColor lcColor(dis->hDC, _textColor);
651                 DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
652         }
653
654         if (dis->itemState & ODS_FOCUS) {
655                 RECT rect = {
656                         dis->rcItem.left+3, dis->rcItem.top+3,
657                         dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4
658                 };
659                 if (dis->itemState & ODS_SELECTED) {
660                         ++rect.left;    ++rect.top;
661                         ++rect.right;   ++rect.bottom;
662                 }
663                 DrawFocusRect(dis->hDC, &rect);
664         }
665 }
666 */
667
668
669 void PictureButton::DrawItem(LPDRAWITEMSTRUCT dis)
670 {
671         UINT state = DFCS_BUTTONPUSH;
672
673         if (dis->itemState & ODS_DISABLED)
674                 state |= DFCS_INACTIVE;
675
676         POINT iconPos = {dis->rcItem.left+2, (dis->rcItem.top+dis->rcItem.bottom-16)/2};
677         RECT textRect = {dis->rcItem.left+16+4, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
678
679         if (dis->itemState & ODS_SELECTED) {
680                 state |= DFCS_PUSHED;
681                 ++iconPos.x;            ++iconPos.y;
682                 ++textRect.left;        ++textRect.top;
683                 ++textRect.right;       ++textRect.bottom;
684         }
685
686         if (_flat) {
687                 FillRect(dis->hDC, &dis->rcItem, _hBrush);
688
689                 if (GetWindowStyle(_hwnd) & BS_FLAT)    // Only with BS_FLAT set, there will be drawn a frame without highlight.
690                         DrawEdge(dis->hDC, &dis->rcItem, EDGE_RAISED, BF_RECT|BF_FLAT);
691         } else
692                 //DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state);
693                 DrawButton(dis->hDC, &dis->rcItem, state, _hBrush);
694
695         DrawIconEx(dis->hDC, iconPos.x, iconPos.y, _hIcon, 16, 16, 0, _hBrush, DI_NORMAL);
696
697         TCHAR title[BUFFER_LEN];
698         GetWindowText(_hwnd, title, BUFFER_LEN);
699
700         BkMode bk_mode(dis->hDC, TRANSPARENT);
701
702         if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
703                 DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_VCENTER/*|DT_CENTER*/);
704         else {
705                 TextColor lcColor(dis->hDC, GetSysColor(COLOR_BTNTEXT));
706                 DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_VCENTER/*|DT_CENTER*/);
707         }
708
709         if (dis->itemState & ODS_FOCUS) {
710                 RECT rect = {
711                         dis->rcItem.left+3, dis->rcItem.top+3,
712                         dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4
713                 };
714                 if (dis->itemState & ODS_SELECTED) {
715                         ++rect.left;    ++rect.top;
716                         ++rect.right;   ++rect.bottom;
717                 }
718                 DrawFocusRect(dis->hDC, &rect);
719         }
720 }
721
722
723 ToolTip::ToolTip(HWND owner)
724  :      super(CreateWindowEx(WS_EX_TOPMOST|WS_EX_NOPARENTNOTIFY, TOOLTIPS_CLASS, 0,
725                                  WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
726                                  owner, 0, g_Globals._hInstance, 0))
727 {
728         activate();
729 }