1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // License Agreement:
4 //
5 // The following are Copyright � 2007, Casey Langen
6 //
7 // Sources and Binaries of: win32cpp
8 //
9 // All rights reserved.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are met:
13 //
14 //    * Redistributions of source code must retain the above copyright notice,
15 //      this list of conditions and the following disclaimer.
16 //
17 //    * Redistributions in binary form must reproduce the above copyright
18 //      notice, this list of conditions and the following disclaimer in the
19 //      documentation and/or other materials provided with the distribution.
20 //
21 //    * Neither the name of the author nor the names of other contributors may
22 //      be used to endorse or promote products derived from this software
23 //      without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 // POSSIBILITY OF SUCH DAMAGE.
36 //
37 //////////////////////////////////////////////////////////////////////////////
38 
39 #include <pch.h>
40 #include <win32cpp/Window.hpp>
41 #include <win32cpp/Color.hpp>
42 #include <win32cpp/Font.hpp>
43 #include <win32cpp/Win32Exception.hpp>
44 
45 //////////////////////////////////////////////////////////////////////////////
46 
47 using namespace win32cpp;
48 
49 //////////////////////////////////////////////////////////////////////////////
50 // Window
51 //////////////////////////////////////////////////////////////////////////////
52 
53 Window::WindowList          Window::sAllChildWindows;
54 Window::HandleToWindowMap   Window::sHandleToWindowMap;
55 FontRef                     Window::sDefaultFont(Font::Create());
56 Window::FocusDirection      Window::sFocusDirection = Window::FocusForward;
57 
58 static Window* sLastWindowUnderMouse = NULL;
59 
60 //////////////////////////////////////////////////////////////////////////////
61 // Window::Window
62 //////////////////////////////////////////////////////////////////////////////
63 
Window()64 /*ctor*/    Window::Window()
65 {
66     this->InitializeInstance();
67 }
68 
Window(LayoutFlags layoutFlags)69 /*ctor*/    Window::Window(LayoutFlags layoutFlags)
70 {
71     this->InitializeInstance();
72     this->SetLayoutFlags(layoutFlags);
73 }
74 
~Window()75 /*dtor*/    Window::~Window()
76 {
77     ::DeleteObject(this->backgroundBrush);
78 }
79 
InitializeInstance()80 void        Window::InitializeInstance()
81 {
82     this->windowHandle = NULL;
83     this->defaultWindowProc = NULL;
84     this->font = Window::sDefaultFont;
85     this->usesDefaultFont = true;
86     this->backgroundBrush = NULL;
87     this->tabStop = true;
88     this->layoutAlignment = LayoutAlignLeft;
89     this->layoutWidth = LayoutWrapContent;
90     this->layoutHeight = LayoutWrapContent;
91     this->layoutWeight = 1.0f;
92 }
93 
94 ///\brief
95 ///Used to force creation of a control. Although this can be called manually
96 ///it's generally recommended to let Container controls automatically
97 ///intialize their children.
98 ///
99 ///Unless creating a TopLevelWindow, parent should always be non-NULL
100 ///and initialized.
101 ///
102 ///\throws WindowAlreadyCreatedException, WindowCreationFailedException
103 ///
104 ///\param parent
105 ///The Window's parent.
Initialize(Window * parent)106 void        Window::Initialize(Window* parent)
107 {
108     if (this->windowHandle != NULL)
109     {
110         throw WindowAlreadyCreatedException();
111     }
112 
113     HWND result = this->Create(parent);
114     //
115     if ( ! result)
116     {
117         throw WindowCreationFailedException();
118     }
119 
120     Window::sHandleToWindowMap[result] = this;
121     this->windowHandle = result;
122     this->SetFont(this->font);
123     this->SetMenu(this->menu);
124 
125     Window::SubclassWindowProc(this);
126 
127     this->OnCreatedBase();
128 }
129 
130 ///\brief
131 ///Used to modify the visibility of a Window. Commonly used flags are SW_SHOW and SW_HIDE.
132 ///
133 ///\param showCommand
134 ///One of the flags listed here: http://msdn2.microsoft.com/en-us/library/ms633548.aspx
135 ///
136 ///\returns
137 ///true if the operation was successful, false otherwise..
Show(int showCommand)138 bool        Window::Show(int showCommand)
139 {
140     return (::ShowWindow(this->windowHandle, showCommand) == TRUE);
141 }
142 
143 ///\brief
144 ///Destroy the associated HWND.
145 ///
146 ///If this Window is a contained within a Container this method will be
147 ///called automatically.
148 ///
149 ///\returns
150 ///true if successful, false otherwise.
151 ///\see
152 ///Container
Destroy()153 bool        Window::Destroy()
154 {
155     bool returnVal = false;
156     HWND windowHandle = this->Handle();
157     //
158     if (windowHandle)
159     {
160         BOOL result = ::DestroyWindow(windowHandle);
161         //
162         if (result)
163         {
164             Window::sHandleToWindowMap.erase(windowHandle);
165             this->windowHandle = NULL;
166         }
167 
168         returnVal = (result == TRUE);
169     }
170 
171     // annoying hack for mouse events.
172     if (sLastWindowUnderMouse == this)
173     {
174         sLastWindowUnderMouse = NULL;
175     }
176 
177     return returnVal;
178 }
179 
WindowHasParent(Window * window)180 bool        Window::WindowHasParent(Window* window)
181 {
182     WindowList& allChildren = Window::sAllChildWindows;
183 
184     WindowList::iterator it =
185         std::find(allChildren.begin(), allChildren.end(), window);
186 
187     return (it != allChildren.end());
188 }
189 
WindowUnderCursor(HWND * targetHwnd)190 Window*     Window::WindowUnderCursor(HWND* targetHwnd)
191 {
192     POINT cursorPos;
193     ::GetCursorPos(&cursorPos);
194 
195     HWND windowUnderMouse = ::WindowFromPoint(cursorPos);
196 
197     if ( ! windowUnderMouse)
198     {
199         return NULL;
200     }
201 
202     // find child-most window under mouse
203     POINT ptCopy;
204     while (true)
205     {
206         ptCopy.x = cursorPos.x;
207         ptCopy.y = cursorPos.y;
208 
209         ::ScreenToClient(windowUnderMouse, &ptCopy);
210 
211         HWND temp = ::RealChildWindowFromPoint(windowUnderMouse, ptCopy);
212 
213         // http://msdn2.microsoft.com/en-us/library/ms632676.aspx
214         if ((temp == NULL) || (temp == windowUnderMouse))
215         {
216             break;
217         }
218 
219         windowUnderMouse = temp;
220     }
221 
222     if (targetHwnd != NULL)
223     {
224         *targetHwnd = windowUnderMouse;
225     }
226 
227     HandleToWindowMap::iterator it = Window::sHandleToWindowMap.find(windowUnderMouse);
228     //
229     return (it == Window::sHandleToWindowMap.end() ? NULL : it->second);
230 
231 }
232 
233 //////////////////////////////////////////////////////////////////////////////
234 // HACK 1/2: necessary to generate reliable OnMouseEnter/Leave() events.
235 //////////////////////////////////////////////////////////////////////////////
236 
BeginCapture(Window * window)237 void        Window::BeginCapture(Window* window)
238 {
239     if ((window) && (window->Handle() != ::GetCapture()))
240     {
241         ::SetCapture(window->Handle());
242     }
243 }
244 //
Capture()245 Window*     Window::Capture()
246 {
247     HandleToWindowMap::iterator it = Window::sHandleToWindowMap.find(::GetCapture());
248     if (it != Window::sHandleToWindowMap.end())
249     {
250         return it->second;
251     }
252 
253     return NULL;
254 }
255 //
EndCapture(Window * window)256 void        Window::EndCapture(Window* window)
257 {
258     if ((window) && (::GetCapture() == window->Handle()))
259     {
260         ::ReleaseCapture();
261     }
262 }
263 
WindowIsValid(Window * window)264 bool        Window::WindowIsValid(Window* window)
265 {
266     WindowList& allChildren = Window::sAllChildWindows;
267     return (std::find(allChildren.begin(), allChildren.end(), window) != allChildren.end());
268 }
269 
270 #define DISPATCH_MOUSE_EVENT(eventName)                                             \
271     {                                                                               \
272         Point mousePos = Point(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));         \
273         Window* windowToNotify = Window::Capture();                                 \
274         bool lastUnderValid = Window::WindowIsValid(sLastWindowUnderMouse);         \
275         if ( ! lastUnderValid) sLastWindowUnderMouse = NULL;                        \
276         if ( ! windowToNotify) windowToNotify = sLastWindowUnderMouse;              \
277         if ( ! windowToNotify) windowToNotify = Window::WindowUnderCursor();        \
278         if (windowToNotify)                                                         \
279         {                                                                           \
280             windowToNotify->eventName((MouseEventFlags) wParam, mousePos);          \
281         }                                                                           \
282     }                                                                               \
283 
284 //////////////////////////////////////////////////////////////////////////////
285 // ENDHACK!
286 //////////////////////////////////////////////////////////////////////////////
287 
288 //////////////////////////////////////////////////////////////////////////////
289 // HACK 2/2: remember last Window that whose measure was forced
290 //////////////////////////////////////////////////////////////////////////////
291 
292 static HWND sMeasureItemHwnd = NULL;
293 
ForceMeasureItem(HWND handle)294 void    ForceMeasureItem(HWND handle)
295 {
296     sMeasureItemHwnd = handle;
297 
298     // Hack to make Window call WM_MEASUREITEM again
299     RECT windowRect;
300     ::GetWindowRect(handle, &windowRect);
301     //
302     WINDOWPOS windowPos;
303     windowPos.hwnd = handle;
304     windowPos.cx = windowRect.right - windowRect.left;
305     windowPos.cy = windowRect.bottom - windowRect.top;
306     windowPos.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
307     //
308     ::SendMessage(handle, WM_WINDOWPOSCHANGED, 0, (LPARAM)&windowPos);
309 }
310 
LastMeasureItemHandle()311 HWND    LastMeasureItemHandle()
312 {
313     HWND handle = sMeasureItemHwnd;
314     sMeasureItemHwnd = NULL;
315     //
316     return handle;
317 }
318 
ForceMeasureItem(const Window * window)319 void        Window::ForceMeasureItem(const Window* window)
320 {
321     if (window && window->Handle())
322     {
323         ::ForceMeasureItem(window->Handle());
324     }
325 }
326 
327 //////////////////////////////////////////////////////////////////////////////
328 // ENDHACK
329 //////////////////////////////////////////////////////////////////////////////
330 
PostWindowProcBase(UINT message,WPARAM wParam,LPARAM lParam)331 void        Window::PostWindowProcBase(UINT message, WPARAM wParam, LPARAM lParam)
332 {
333     switch (message)
334     {
335     case WM_MOUSELEAVE:
336         {
337             if (sLastWindowUnderMouse == this)
338             {
339                 this->OnMouseExitBase();
340             }
341         }
342         break;
343 
344     case WM_MOUSEMOVE:
345         {
346             Point mousePos = Point(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
347 
348             // If a non-Window (an unknown HWND) is capturing. just let it be.
349             Window* currentCapture = Window::Capture();
350             if ( ! currentCapture && ::GetCapture())
351             {
352                 break;
353             }
354 
355             Window* windowToNotify = currentCapture;
356 
357             if (currentCapture)
358             {
359                 windowToNotify = currentCapture;
360             }
361             else
362             {
363                 // The window under the mouse is different than the last window
364                 // that was under the mouse, so notify the new one.
365                 Window* underMouse = Window::WindowUnderCursor();
366                 //
367                 if ((underMouse) && (underMouse != sLastWindowUnderMouse))
368                 {
369                     windowToNotify = underMouse;
370                 }
371                 // The current window under the mouse is the same as the
372                 // last window under the mouse, so notify it.
373                 else
374                 {
375                     windowToNotify = sLastWindowUnderMouse;
376                 }
377             }
378 
379             if (windowToNotify)
380             {
381                 windowToNotify->OnMouseMovedBase((MouseEventFlags) wParam, mousePos);
382             }
383         }
384         break;
385 
386     case WM_LBUTTONDOWN:
387     case WM_RBUTTONDOWN:
388     case WM_MBUTTONDOWN:
389         {
390             DISPATCH_MOUSE_EVENT(OnMouseButtonDownBase)
391         }
392         break;
393     case WM_LBUTTONUP:
394     case WM_RBUTTONUP:
395     case WM_MBUTTONUP:
396         {
397             DISPATCH_MOUSE_EVENT(OnMouseButtonUpBase)
398         }
399         break;
400     case WM_LBUTTONDBLCLK:
401     case WM_RBUTTONDBLCLK:
402     case WM_MBUTTONDBLCLK:
403         {
404             DISPATCH_MOUSE_EVENT(OnMouseButtonDoubleClickedBase)
405         }
406         break;
407 
408     case WM_KEYDOWN:
409         {
410             if(this->OnKeyDownBase((VirtualKeyCode) wParam, (KeyEventFlags) lParam))
411             {
412                 return;
413             }
414 
415             if (wParam == VK_TAB)
416             {
417                 bool focusPrev = ((::GetKeyState(VK_SHIFT) & 0x8000) != 0);
418                 Window::sFocusDirection = focusPrev ? FocusBackward : FocusForward;
419 
420                 focusPrev
421                     ? this->OnRequestFocusPrev()
422                     : this->OnRequestFocusNext();
423 
424                 return;
425             }
426         }
427         break;
428 
429     case WM_KEYUP:
430         {
431             if(this->OnKeyUpBase((VirtualKeyCode) wParam, (KeyEventFlags) lParam))
432             {
433                 return;
434             }
435         }
436         break;
437 
438     case WM_CHAR:
439         {
440             if(this->OnCharBase((VirtualKeyCode) wParam, (KeyEventFlags) lParam))
441             {
442                 return;
443             }
444         }
445         break;
446 
447     case WM_DESTROY:
448         this->OnDestroyedBase();
449         break;
450 
451     case WM_TIMER:
452         this->TimerTimeout((unsigned int) wParam);
453         break;
454 
455     case WM_SETFOCUS:
456         this->OnGainedFocusBase();
457         break;
458 
459     case WM_KILLFOCUS:
460         this->OnLostFocusBase();
461         break;
462     }
463 
464     this->PostWindowProc(message, wParam, lParam);
465 }
466 
PreWindowProcBase(UINT message,WPARAM wParam,LPARAM lParam,bool & discardMessage)467 LRESULT     Window::PreWindowProcBase(UINT message, WPARAM wParam, LPARAM lParam, bool& discardMessage)
468 {
469     return this->PreWindowProc(message, wParam, lParam, discardMessage);
470 }
471 
472 
PreWindowProc(UINT message,WPARAM wParam,LPARAM lParam,bool & discardMessage)473 LRESULT     Window::PreWindowProc(UINT message, WPARAM wParam, LPARAM lParam, bool& discardMessage)
474 {
475     switch(message)
476     {
477     // sometimes messages, such as WM_COMMAND, are automatically sent to
478     // parent controls. handling these messages here allows derived classes
479     // to recieve their messages so they can raise events.
480     case WM_COMMAND:
481         {
482             // control message
483             Window* sender = Window::sHandleToWindowMap[(HWND) lParam];
484             if (sender)
485             {
486                 sender->WindowProc(message, wParam, lParam);
487                 return 0;
488             }
489 
490             // menu message
491             if (HIWORD(wParam) == 0)
492             {
493                 Menu::ItemActivated(LOWORD(wParam));
494                 return 0;
495             }
496         }
497         break;
498     }
499 
500     return 0;
501 }
502 
PostWindowProc(UINT message,WPARAM wParam,LPARAM lParam)503 void        Window::PostWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
504 {
505 }
506 
DefaultWindowProc(UINT message,WPARAM wParam,LPARAM lParam)507 LRESULT     Window::DefaultWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
508 {
509     if (this->defaultWindowProc)
510     {
511         return ::CallWindowProc(this->defaultWindowProc, this->Handle(), message, wParam, lParam);
512     }
513 
514     return ::DefWindowProc(this->Handle(), message, wParam, lParam);
515 }
516 
StaticWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)517 LRESULT CALLBACK Window::StaticWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
518 {
519     Window::HandleToWindowMap::iterator it = Window::sHandleToWindowMap.find(hwnd);
520     //
521     if (it != Window::sHandleToWindowMap.end())
522     {
523         switch (message)
524         {
525         // forward message to sender, instead of parent
526         case WM_DRAWITEM:
527             {
528                 if (lParam)
529                 {
530                     DRAWITEMSTRUCT* drawItem = (DRAWITEMSTRUCT*) lParam;
531                     Window* sender = Window::sHandleToWindowMap[drawItem->hwndItem];
532                     if (sender)
533                     {
534                         return sender->DrawItem(*drawItem);
535                     }
536                 }
537             }
538             break;
539 
540         // forward message to sender, instead of parent
541         case WM_NOTIFY:
542             {
543                 if (lParam)
544                 {
545                     NMHDR* notifyHeader = reinterpret_cast<NMHDR*>(lParam);
546 
547                     Window* sender = Window::sHandleToWindowMap[notifyHeader->hwndFrom];
548                     if (sender)
549                     {
550                         return sender->WindowProc(message, wParam, lParam);
551                     }
552 
553                     sender = Window::sHandleToWindowMap[hwnd];
554                     if (sender)
555                     {
556                         return sender->WindowProc(message, wParam, lParam);
557                     }
558                 }
559             }
560             break;
561 
562         // TODO: move to PreWindowProc?
563         case WM_CTLCOLORBTN:
564         case WM_CTLCOLOREDIT:
565         case WM_CTLCOLORDLG:
566         case WM_CTLCOLORLISTBOX:
567         case WM_CTLCOLORSCROLLBAR:
568         case WM_CTLCOLORSTATIC:
569             {
570                 Window* sender = Window::sHandleToWindowMap[(HWND) lParam];
571 
572                 if (sender)
573                 {
574                     HBRUSH result = sender->OnControlColor((HDC) wParam);
575                     if (result)
576                     {
577                         return reinterpret_cast<LRESULT>(result);
578                     }
579                 }
580             }
581             break;
582 
583         // TODO: move to PreWindowProc?
584         // forward message to sender, instead of parent
585         case WM_MEASUREITEM:
586             {
587                 // This message is awful.  You can only artifically generate it by repositioning
588                 // the window, and then it doesn't even contain a handle to the window that
589                 // generated it. ::ForceMeasureItem() remembers the HWND of the item that triggered
590                 // the event, and ::MeasureItemHandle() retrieves it.
591                 HWND hwndToMeasure = ::LastMeasureItemHandle();
592                 //
593                 if (hwndToMeasure && lParam)
594                 {
595                     Window* sender = Window::sHandleToWindowMap[hwndToMeasure];
596                     if (sender)
597                     {
598                         sender->OnMeasureItem(reinterpret_cast<MEASUREITEMSTRUCT*>(lParam));
599                     }
600                 }
601             }
602             break;
603 
604         case WM_ERASEBKGND:
605             {
606                 it->second->OnEraseBackground((HDC) wParam);
607             }
608             return 1;
609 
610         case WM_PAINT:
611             {
612                 it->second->OnPaint();
613             }
614             return 0;
615 
616         case WM_THEMECHANGED:
617             {
618                 it->second->OnThemeChangedBase();
619             }
620             break;
621         }
622 
623         bool discardMessage = false;
624         LRESULT preResult = it->second->PreWindowProcBase(message, wParam, lParam, discardMessage);
625 
626         if (discardMessage)
627         {
628             return preResult;
629         }
630 
631         LRESULT result = it->second->WindowProc(message, wParam, lParam);
632         it->second->PostWindowProcBase(message, wParam, lParam);
633 
634         return result;
635     }
636 
637     return ::DefWindowProc(hwnd, message, wParam, lParam);
638 }
639 
WindowProc(UINT message,WPARAM wParam,LPARAM lParam)640 LRESULT     Window::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
641 {
642     return this->DefaultWindowProc(message, wParam, lParam);
643 }
644 
645 ///\brief
646 ///Moves and resizes the Window to rectangle.location and rectangle.size.
647 ///
648 ///Emits Window::Moved and Window::Resized. Note this method sets the
649 ///WindowRect, and not the ClientRect. The ClientRect cannot be set
650 ///explicitly.
651 ///
652 ///\param rectangle
653 ///Specifies the Window's new location and size.
654 ///
655 ///\returns
656 ///true if successful, false otherwise.
657 ///
658 ///\see
659 ///Window::MoveTo, Window::Resize, Window::WindowRect, Window::ClientRect
SetRectangle(const Rect & rectangle)660 bool        Window::SetRectangle(const Rect& rectangle)
661 {
662     return (this->MoveTo(rectangle.location) && this->Resize(rectangle.size));
663 }
664 
665 ///\brief
666 ///Moves the Window to the specified coordinates.
667 ///
668 ///The coordinates specified are interpreted as relative to the
669 ///control's parent window. Will emit the Window::Moved event
670 ///if successful.
671 ///
672 ///\param x
673 ///location of the window, in pixels, relative to the parent
674 ///
675 ///\param y
676 ///location of the window, in pixels, relative to the parent
677 ///
678 ///\returns
679 ///true if succesful, false otherwise.
MoveTo(int x,int y)680 bool        Window::MoveTo(int x, int y)
681 {
682     return this->MoveTo(Point(x, y));
683 }
684 
685 ///\brief
686 ///Moves the Window to the specified coordinates.
687 ///
688 ///The coordinates specified are interpreted as relative to the
689 ///control's parent window. Will emit the Window::Moved event
690 ///if successful.
691 ///
692 ///\param location
693 ///location of the window, in pixels, relative to the parent
694 ///
695 ///\returns
696 ///true if succesful, false otherwise.
MoveTo(const Point & location)697 bool        Window::MoveTo(const Point& location)
698 {
699     if (this->Location() == location)
700     {
701         return true;
702     }
703 
704     RECT windowRect;
705     if (::GetWindowRect(this->windowHandle, &windowRect))
706     {
707         BOOL result =::MoveWindow(
708             this->windowHandle,
709             location.x,
710             location.y,
711             windowRect.right - windowRect.left,
712             windowRect.bottom - windowRect.top,
713             this->Visible());
714 
715         if (result)
716         {
717             this->OnMovedBase(location);
718         }
719 
720         return (result == TRUE);
721     }
722 
723     return false;
724 }
725 
726 
727 ///\brief
728 ///Moves the Window relative to its current coordinates
729 ///
730 ///\param x
731 ///relative movement in pixels
732 ///
733 ///\param y
734 ///relative movement in pixels
735 ///
736 ///\returns
737 ///true if succesful, false otherwise.
MoveRelativeTo(int x,int y)738 bool        Window::MoveRelativeTo(int x, int y)
739 {
740     RECT windowRect;
741     if (::GetWindowRect(this->windowHandle, &windowRect))
742     {
743         OffsetRect(&windowRect, x, y);
744 
745         POINT point;
746         point.x = windowRect.left;
747         point.y = windowRect.top;
748 
749         ScreenToClient(this->Parent()->windowHandle, &point);
750 
751         BOOL result =::MoveWindow(
752             this->windowHandle,
753             point.x,
754             point.y,
755             windowRect.right - windowRect.left,
756             windowRect.bottom - windowRect.top,
757             this->Visible());
758 
759         return (result == TRUE);
760     }
761 
762     return false;
763 }
764 
765 ///\brief
766 ///Resizes the window to the specified size.
767 ///
768 ///\param width
769 ///width of the window, in pixels.
770 ///
771 ///\param height
772 ///height of the window, in pixels.
773 ///
774 ///\returns
775 ///true on success, false otherwise.
Resize(int width,int height)776 bool        Window::Resize(int width, int height)
777 {
778     return this->Resize(Size(width, height));
779 }
780 
781 ///\brief
782 ///Resizes the window to the specified size.
783 ///
784 ///\param size
785 ///size of the window, in pixels.
786 ///
787 ///\returns
788 ///true on success, false otherwise.
Resize(const Size & size)789 bool        Window::Resize(const Size& size)
790 {
791     if (this->WindowSize() == size)
792     {
793         return true;
794     }
795 
796     RECT windowRect;
797     if (::GetWindowRect(this->windowHandle, &windowRect))
798     {
799         Size saneSize = Size(
800             std::max(size.width, 0),
801             std::max(size.height, 0));
802 
803         POINT topLeft;
804         topLeft.x = windowRect.left;
805         topLeft.y = windowRect.top;
806 
807         ::ScreenToClient(::GetParent(this->windowHandle), &topLeft);
808 
809         BOOL result = ::MoveWindow(
810             this->windowHandle,
811             topLeft.x,
812             topLeft.y,
813             saneSize.width,
814             saneSize.height,
815             this->Visible());
816 
817         if (result)
818         {
819             this->OnResizedBase(saneSize);
820         }
821 
822         return (result == TRUE);
823     }
824 
825     return false;
826 }
827 
828 ///\brief
829 ///Changes the enabled state of the Window.
830 ///
831 ///\param enable
832 ///whether or not the Window is enabled.
833 ///
834 ///\returns
835 ///true if successful, false otherwise.
Enable(bool enable)836 bool        Window::Enable(bool enable)
837 {
838     return (::EnableWindow(this->windowHandle, enable) == TRUE);
839 }
840 
841 ///\brief
842 ///Returns the caption of the Window.
843 ///
844 ///Internally this method uses Win32's GetWindowText
Caption() const845 uistring    Window::Caption() const
846 {
847     static uichar text[1024];
848     //
849     if ((this->windowHandle) && (::GetWindowText(this->windowHandle, text, 1024)))
850     {
851         return uistring(text);
852     }
853 
854     return uistring();
855 }
856 
857 ///\brief
858 ///Sets the caption of the Window.
859 ///
860 ///Internally this method uses Win32's SetWindowText
861 ///
862 ///\param caption
863 ///The desired Window caption.
864 ///
865 ///\returns
866 ///true if successful, false otherwise.
SetCaption(const uistring & caption)867 bool        Window::SetCaption(const uistring& caption)
868 {
869     if (caption == this->Caption())
870     {
871         return true;
872     }
873 
874     if (this->windowHandle)
875     {
876         BOOL success = (BOOL) ::SendMessage(
877             this->windowHandle,
878             WM_SETTEXT,
879             0,
880             (LPARAM) caption.c_str());
881 
882         if (success)
883         {
884             this->OnCaptionChanged();
885             return true;
886         }
887     }
888 
889     return false;
890 }
891 
892 ///\brief
893 ///Returns the Window's client rectangle.
894 ///
895 ///The client rectangle is the portion of the Window that content can
896 ///be displayed. The Window::WindowRect is the bounding rectangle of
897 ///the entire Window, including borders.
898 ///
899 ///\returns
900 ///the Window's client rectangle.
901 ///
902 ///\see
903 ///Window::WindowRect, Window::SetRectangle
ClientRect() const904 Rect        Window::ClientRect() const
905 {
906     static RECT clientRect;
907     //
908     if ((this->windowHandle) && (::GetClientRect(this->windowHandle, &clientRect)))
909     {
910         return Rect(clientRect);
911     }
912 
913     return Rect();
914 }
915 
916 ///\brief
917 ///Returns the Window's rectangle.
918 ///
919 ///The Window::WindowRect is the bounding rectangle of the entire Window
920 ///including borders. Not to be confused with Windodw::ClientRect.
921 ///
922 ///\returns
923 ///the Window's rectangle.
924 ///
925 ///\see
926 ///Window::ClientRect, Window::SetRectangle
WindowRect() const927 Rect        Window::WindowRect() const
928 {
929     static RECT windowRect;
930     //
931     if ((this->windowHandle) && (::GetWindowRect(this->windowHandle, &windowRect)))
932     {
933         return Rect(windowRect);
934     }
935 
936     return Rect();
937 }
938 
939 ///\brief
940 ///Returns the size of the Window.
941 ///
942 ///Not to be confused with Window::ClientSize, Window::WindowSize returns
943 ///the size of the entire window, not just the content area.
944 ///
945 ///\returns
946 ///the size of the Window.
947 ///
948 ///\see
949 ///Window::ClientSize
WindowSize() const950 Size        Window::WindowSize() const
951 {
952     Rect windowRect = this->WindowRect();
953     return windowRect.size;
954 }
955 
956 ///\brief
957 ///Returns the client (content) size of the Window.
958 ///
959 ///Not to be confused with Window::WindowSize, Window::ClientSize returns
960 ///the size of the content area, and doesn't include any borders.
961 ///
962 ///\returns
963 ///the size of the client area of the Window.
964 ///
965 ///\see
966 ///Window::WindowSize
ClientSize() const967 Size        Window::ClientSize() const
968 {
969     Rect clientRect = this->ClientRect();
970     return clientRect.size;
971 }
972 
973 ///\brief
974 ///Returns the location of the window, relative to its parent Window.
975 ///
976 ///\returns
977 ///the location of the window, relative to its parent Window.
Location() const978 Point       Window::Location() const
979 {
980     Rect windowRect = this->WindowRect();
981     return windowRect.location;
982 }
983 
984 ///\brief
985 ///Returns the position of the cursor, relative to the Window.
986 ///
987 ///\returns
988 ///the position of the cursor, relative to the Window.
CursorPosition() const989 Point       Window::CursorPosition() const
990 {
991     POINT cursorPos;
992     ::GetCursorPos(&cursorPos);
993     ::ScreenToClient(this->Handle(), &cursorPos);
994 
995     return cursorPos;
996 }
997 
998 ///\brief
999 ///Returns a pointer to the Window's parent.
1000 ///
1001 ///This method will throw a WindowNotCreatedException if the Window has
1002 ///not been created yet. It may also return NULL if the Window is
1003 ///created but currently has no parent.
1004 ///
1005 ///\throws WindowNotCreatedException
1006 ///
1007 ///\returns
1008 ///Write description of return value here.
1009 ///
1010 ///\throws WindowNotCreatedException
Parent() const1011 Window*     Window::Parent() const
1012 {
1013     if ( ! this->windowHandle)
1014     {
1015         throw WindowNotCreatedException();
1016     }
1017 
1018     HandleToWindowMap::iterator it = Window::sHandleToWindowMap.find(this->windowHandle);
1019     //
1020     if (it != Window::sHandleToWindowMap.end())
1021     {
1022         HWND parentHwnd = ::GetParent(this->windowHandle);
1023         it = Window::sHandleToWindowMap.find(parentHwnd);
1024         //
1025         if (it != Window::sHandleToWindowMap.end())
1026         {
1027             return it->second;
1028         }
1029     }
1030 
1031     return NULL;
1032 }
1033 
1034 ///\brief
1035 ///Synchronously invokes a message on the Window.
1036 ///
1037 ///See: http://msdn2.microsoft.com/en-us/library/ms644950.aspx
1038 ///
1039 ///\param message
1040 ///The message ID
1041 ///
1042 ///\param wParam
1043 ///The wParam value
1044 ///
1045 ///\param lParam
1046 ///The lParam value.
1047 ///
1048 ///\returns
1049 ///Value varies based on the message. See MSDN for more information.
1050 ///
1051 ///\see
1052 ///Window::PostMessage
SendMessage(UINT message,WPARAM wParam,LPARAM lParam)1053 LRESULT     Window::SendMessage(UINT message, WPARAM wParam, LPARAM lParam)
1054 {
1055     if ( ! this->windowHandle)
1056     {
1057         return 0;
1058     }
1059 
1060     return ::SendMessage(this->windowHandle, message, wParam, lParam);
1061 }
1062 
1063 ///\brief
1064 ///Asynchronously invokes a message on the Window.
1065 ///
1066 ///See: http://msdn2.microsoft.com/en-us/library/ms644944.aspx
1067 ///
1068 ///\param message
1069 ///The message ID
1070 ///
1071 ///\param wParam
1072 ///The wParam value
1073 ///
1074 ///\param lParam
1075 ///The lParam value.
1076 ///
1077 ///\returns
1078 ///Value varies based on the message. See MSDN for more information.
1079 ///
1080 ///\see
1081 ///Window::SendMessage
PostMessage(UINT message,WPARAM wParam,LPARAM lParam)1082 bool        Window::PostMessage(UINT message, WPARAM wParam, LPARAM lParam)
1083 {
1084     if ( ! this->windowHandle)
1085     {
1086         return 0;
1087     }
1088 
1089     return (::PostMessage(this->windowHandle, message, wParam, lParam) == TRUE);
1090 }
1091 
1092 ///\brief
1093 ///Returns the HWND that the Window wraps.
1094 ///
1095 ///\returns
1096 ///the HWND that the Window wraps.
1097 ///
1098 ///\see
1099 ///Window::SendMessage(), Window::PostMessage
Handle() const1100 HWND        Window::Handle() const
1101 {
1102     return this->windowHandle;
1103 }
1104 
1105 ///\brief
1106 ///Redraws the Window.
1107 ///
1108 ///Internally this method calls ::InvalidateRect(Handle(), NULL, FALSE)
Redraw() const1109 void        Window::Redraw() const
1110 {
1111     ::InvalidateRect(this->Handle(), NULL, FALSE);
1112 }
1113 
1114 ///\brief
1115 ///Sets the Font the Window uses to draw its caption.
1116 ///
1117 ///\param font
1118 ///A shared pointer to a Font object. A FontRef can be shared amongst
1119 ///different controls.
1120 ///
1121 ///\see
1122 ///Font, FontRef
SetFont(FontRef font)1123 void        Window::SetFont(FontRef font)
1124 {
1125     this->usesDefaultFont = (font == Window::sDefaultFont);
1126 
1127     bool isNewFont = (this->font != font);
1128     if (isNewFont) this->font = font;
1129 
1130     if (this->Handle())
1131     {
1132         ::SendMessage(this->Handle(), WM_SETFONT, (WPARAM) font->GetHFONT(), 1); // 1 = redraw
1133     }
1134 
1135     if (isNewFont) this->OnFontChanged();
1136 }
1137 
1138 ///\brief
1139 ///Sets the Window's Menu.
1140 ///
1141 ///\see
1142 ///Menu, MenuRef, Window::Menu
SetMenu(MenuRef menu)1143 void        Window::SetMenu(MenuRef menu)
1144 {
1145     this->menu = menu;
1146 
1147     if (this->Handle() && this->menu)
1148     {
1149         if ( ! ::SetMenu(this->Handle(), this->menu->Handle()))
1150         {
1151             throw Win32Exception();
1152         }
1153     }
1154 }
1155 
1156 ///\brief
1157 ///Returns the Window's Menu.
1158 ///
1159 ///\see
1160 ///Menu, MenuRef, Window::SetMenu
Menu()1161 MenuRef     Window::Menu()
1162 {
1163     return this->menu;
1164 }
1165 
1166 ///\brief
1167 ///Shows or hides the window.
1168 ///
1169 ///\param visible
1170 ///If true the window will be made visible, otherwise it will be hidden.
1171 ///
1172 ///\see
1173 ///Windowd::Visible
SetVisible(bool visible)1174 void        Window::SetVisible(bool visible)
1175 {
1176     if (this->Handle())
1177     {
1178         ::ShowWindow(this->Handle(), visible ? SW_SHOW : SW_HIDE);
1179         this->OnVisibilityChangedBase(visible);
1180     }
1181 }
1182 
1183 ///\brief
1184 ///Returns true if the window is visible.
1185 ///
1186 ///\see
1187 ///Windowd::SetVisible
Visible()1188 bool        Window::Visible()
1189 {
1190     if (this->Handle())
1191     {
1192         LONG style = ::GetWindowLong(this->Handle(), GWL_STYLE);
1193         return ((style & WS_VISIBLE) != 0);
1194     }
1195 
1196     return false;
1197 }
1198 
1199 ///\brief
1200 ///Returns a shared pointer to the Font the Window uses to draw its text.
1201 ///
1202 ///\returns
1203 ///a shared pointer to the Font the Window uses to draw its text
1204 ///different controls.
1205 ///
1206 ///\see
1207 ///Font, FontRef
Font() const1208 FontRef     Window::Font() const
1209 {
1210     return this->font;
1211 }
1212 
1213 ///\brief
1214 ///Sets the background color of the ListView.
1215 ///
1216 ///\param color
1217 ///The color to use.
1218 ///
1219 ///\see
1220 ///Window::BackgroundColor
SetBackgroundColor(const Color & color)1221 void        Window::SetBackgroundColor(const Color& color)
1222 {
1223     this->backgroundColor.reset(new Color(color));
1224 
1225     ::DeleteObject(this->backgroundBrush);
1226     this->backgroundBrush = ::CreateSolidBrush(*this->backgroundColor);
1227 }
1228 
1229 ///\brief
1230 ///Returns the Window's background color.
1231 ///
1232 ///\see
1233 ///Window::SetBackgroundColor
BackgroundColor() const1234 Color       Window::BackgroundColor() const
1235 {
1236     return this->backgroundColor
1237         ? *this->backgroundColor
1238         : Color::SystemColor(COLOR_BTNFACE);
1239 }
1240 
1241 ///\brief
1242 ///Focuses the Window.
SetFocus()1243 bool        Window::SetFocus()
1244 {
1245     bool success = false;
1246     if ((this->windowHandle) && (this->Visible()))
1247     {
1248         success = (::SetFocus(this->windowHandle) != NULL);
1249     }
1250 
1251     return success;
1252 }
1253 
1254 ///\brief
1255 ///Returns true if this control should be focused via the Tab key
TabStop()1256 bool        Window::TabStop()
1257 {
1258     return this->tabStop;
1259 }
1260 
1261 ///\brief
1262 ///Sets whether or not this control can be focused via Tab key
1263 ///\param enabled
1264 ///If true this control can be focused via the Tab key
SetTabStop(bool enabled)1265 void        Window::SetTabStop(bool enabled)
1266 {
1267     this->tabStop = enabled;
1268 }
1269 
IsWindowSubclassed(Window * window)1270 bool        Window::IsWindowSubclassed(Window* window)
1271 {
1272     Window::HandleToWindowMap& hwndToWindow = Window::sHandleToWindowMap;
1273 
1274     return (hwndToWindow.find(window->Handle()) != hwndToWindow.end());
1275 }
1276 
SubclassedWindowFromHWND(HWND hwnd)1277 Window*      Window::SubclassedWindowFromHWND(HWND hwnd)
1278 {
1279     Window::HandleToWindowMap& hwndToWindow = Window::sHandleToWindowMap;
1280 
1281     HandleToWindowMap::iterator it = hwndToWindow.find(hwnd);
1282     if (it != hwndToWindow.end())
1283     {
1284         return it->second;
1285     }
1286 
1287     return NULL;
1288 }
1289 
1290 #pragma warning(push)
1291 #pragma warning(disable: 4244)
1292 #pragma warning(disable: 4312)
SubclassWindowProc(Window * window)1293 void         Window::SubclassWindowProc(Window* window)
1294 {
1295     WindowProcFunc currentWindowProc = reinterpret_cast<WindowProcFunc>(
1296         ::GetWindowLongPtr(window->Handle(), GWLP_WNDPROC));
1297 
1298     if (currentWindowProc != &Window::StaticWindowProc)
1299     {
1300         // remember its old WndProc
1301         window->defaultWindowProc = currentWindowProc;
1302 
1303         // subclass the window
1304         ::SetWindowLongPtr(
1305             window->Handle(),
1306             GWLP_WNDPROC,
1307             reinterpret_cast<LONG_PTR>(Window::StaticWindowProc));
1308     }
1309 }
1310 #pragma warning(pop)
1311 
1312 #pragma warning(push)
1313 #pragma warning(disable: 4244)
1314 #pragma warning(disable: 4312)
UnSubclassWindowProc(Window * window)1315 void        Window::UnSubclassWindowProc(Window* window)
1316 {
1317     WindowProcFunc currentWindowProc = reinterpret_cast<WindowProcFunc>(
1318         ::GetWindowLongPtr(window->Handle(), GWLP_WNDPROC));
1319 
1320     if (currentWindowProc == &Window::StaticWindowProc)
1321     {
1322         // unsubclass the window
1323         ::SetWindowLongPtr(
1324             window->Handle(),
1325             GWLP_WNDPROC,
1326             reinterpret_cast<LONG_PTR>(window->defaultWindowProc));
1327 
1328         window->defaultWindowProc = NULL;
1329     }
1330 }
1331 #pragma warning(pop)
1332 
1333 //////////////////////////////////////////////////////////////////////////////
1334 // Win32 event wrappers (using the template pattern)
1335 //////////////////////////////////////////////////////////////////////////////
1336 
1337 #define EMIT_SIGNAL_IF_NOT_SUPPRESSED(signal, ...)                                  \
1338     {                                                                               \
1339         if (this->suppressedSignals.find(&signal) == this->suppressedSignals.end()) \
1340             signal(__VA_ARGS__);                                                    \
1341         this->suppressedSignals.clear();                                            \
1342     }                                                                               \
1343 
SuppressSignal(SignalBase & signal)1344 void        Window::SuppressSignal(SignalBase& signal)
1345 {
1346     this->suppressedSignals.insert(&signal);
1347 }
1348 
OnDestroyedBase()1349 void        Window::OnDestroyedBase()
1350 {
1351     this->OnDestroyed();
1352     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->Destroyed, this);
1353 }
1354 
OnCreatedBase()1355 void        Window::OnCreatedBase()
1356 {
1357     this->OnCreated();
1358     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->Created, this);
1359 }
1360 
OnMovedBase(const Point & location)1361 void        Window::OnMovedBase(const Point& location)
1362 {
1363     this->OnMoved(location);
1364     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->Moved, this, location);
1365 }
1366 
OnResizedBase(const Size & newSize)1367 void        Window::OnResizedBase(const Size& newSize)
1368 {
1369     this->OnResized(newSize);
1370     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->Resized, this, newSize);
1371 }
1372 
OnMouseMovedBase(MouseEventFlags flags,const Point & location)1373 void        Window::OnMouseMovedBase(MouseEventFlags flags, const Point& location)
1374 {
1375     if (sLastWindowUnderMouse != this)
1376     {
1377         if (sLastWindowUnderMouse)
1378         {
1379             sLastWindowUnderMouse->OnMouseExitBase();
1380         }
1381 
1382         this->OnMouseEnterBase();
1383     }
1384     //
1385     sLastWindowUnderMouse = this;
1386 
1387     this->OnMouseMoved(flags, location);
1388     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->MouseMoved, this, flags, location);
1389 }
1390 
OnMouseButtonDownBase(MouseEventFlags flags,const Point & location)1391 void        Window::OnMouseButtonDownBase(MouseEventFlags flags, const Point& location)
1392 {
1393     this->OnMouseButtonDown(flags, location);
1394     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->MouseButtonDown, this, flags, location);
1395 }
1396 
OnMouseButtonUpBase(MouseEventFlags flags,const Point & location)1397 void        Window::OnMouseButtonUpBase(MouseEventFlags flags, const Point& location)
1398 {
1399     this->OnMouseButtonUp(flags, location);
1400     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->MouseButtonUp, this, flags, location);
1401 }
1402 
OnMouseButtonDoubleClickedBase(MouseEventFlags flags,const Point & location)1403 void        Window::OnMouseButtonDoubleClickedBase(MouseEventFlags flags, const Point& location)
1404 {
1405     this->OnMouseButtonDoubleClicked(flags, location);
1406     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->MouseButtonDoubleClicked, this, flags, location);
1407 }
1408 
OnMouseEnterBase()1409 void        Window::OnMouseEnterBase()
1410 {
1411 #if 0 && _DEBUG
1412     uistring output = _T("mouse enter: ") + this->Caption() + _T("\n");
1413     OutputDebugString(output.c_str());
1414 #endif
1415 
1416     this->OnMouseEnter();
1417     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->MouseEnter, this);
1418 
1419     if (::GetCapture() != this->Handle())
1420     {
1421         TRACKMOUSEEVENT tme;
1422         tme.cbSize = sizeof(TRACKMOUSEEVENT);
1423         tme.dwFlags = TME_LEAVE;
1424         tme.dwHoverTime = 0;
1425         tme.hwndTrack = this->Handle();
1426         ::TrackMouseEvent(&tme);
1427     }
1428 }
1429 
OnMouseExitBase()1430 void        Window::OnMouseExitBase()
1431 {
1432 #if 0 && _DEBUG
1433     uistring output = _T("mouse exit: ") + this->Caption() + _T("\n");
1434     OutputDebugString(output.c_str());
1435 #endif
1436 
1437     sLastWindowUnderMouse = NULL;
1438 
1439     this->OnMouseExit();
1440     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->MouseExit, this);
1441 }
1442 
OnGainedFocusBase()1443 void        Window::OnGainedFocusBase()
1444 {
1445     this->SendMessage(WM_CHANGEUISTATE, MAKELPARAM(UIS_CLEAR, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0);
1446     this->SendMessage(WM_CHANGEUISTATE, MAKELPARAM(UIS_SET, UISF_ACTIVE), 0);
1447 
1448     this->OnGainedFocus();
1449     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->GainedFocus, this);
1450 }
1451 
OnLostFocusBase()1452 void        Window::OnLostFocusBase()
1453 {
1454     this->SendMessage(WM_CHANGEUISTATE, MAKELPARAM(UIS_SET, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0);
1455     this->SendMessage(WM_CHANGEUISTATE, MAKELPARAM(UIS_CLEAR, UISF_ACTIVE), 0);
1456 
1457     this->OnLostFocus();
1458     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->LostFocus, this);
1459 }
1460 
OnThemeChangedBase()1461 void        Window::OnThemeChangedBase()
1462 {
1463     this->OnThemeChanged();
1464     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->ThemeChanged, this);
1465 }
1466 
OnParentChangedBase(Window * oldParent,Window * newParent)1467 void        Window::OnParentChangedBase(Window* oldParent, Window* newParent)
1468 {
1469     this->OnParentChanged(oldParent, newParent);
1470     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->ParentChanged, oldParent, newParent);
1471 }
1472 
OnKeyDownBase(VirtualKeyCode keyCode,KeyEventFlags flags)1473 bool        Window::OnKeyDownBase(VirtualKeyCode keyCode, KeyEventFlags flags)
1474 {
1475     bool result = this->OnKeyDown(keyCode, flags);
1476     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->KeyDown, this, keyCode, flags);
1477     return result;
1478 }
1479 
OnKeyUpBase(VirtualKeyCode keyCode,KeyEventFlags flags)1480 bool        Window::OnKeyUpBase(VirtualKeyCode keyCode, KeyEventFlags flags)
1481 {
1482     bool result = this->OnKeyUp(keyCode, flags);
1483     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->KeyUp, this, keyCode, flags);
1484     return result;
1485 }
1486 
OnCharBase(VirtualKeyCode keyCode,KeyEventFlags flags)1487 bool        Window::OnCharBase(VirtualKeyCode keyCode, KeyEventFlags flags)
1488 {
1489     bool result = this->OnChar(keyCode, flags);
1490     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->Char, this, keyCode, flags);
1491     return result;
1492 }
1493 
1494 
OnVisibilityChangedBase(bool visible)1495 void        Window::OnVisibilityChangedBase(bool visible)
1496 {
1497     this->OnVisibilityChanged(visible);
1498     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->VisibilityChanged, this, visible);
1499 }
1500 
OnLayoutParametersChangedBase()1501 void        Window::OnLayoutParametersChangedBase()
1502 {
1503     this->OnLayoutParametersChanged();
1504     EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->LayoutParametersChanged, this);
1505 }
1506 
OnThemeChanged()1507 void        Window::OnThemeChanged()
1508 {
1509     // If we're the first window to notice the theme change then update
1510     // the default font.
1511     if (this->font == Window::sDefaultFont)
1512     {
1513         Window::sDefaultFont = Font::Create();
1514     }
1515 
1516     if (this->usesDefaultFont)
1517     {
1518         this->SetFont(Window::sDefaultFont);
1519     }
1520 
1521     Window::ForceMeasureItem(this);
1522 }
1523 
1524 
OnPaint()1525 void        Window::OnPaint()
1526 {
1527     /*
1528     PAINTSTRUCT paintStruct;
1529     HDC hdc = ::BeginPaint(this->Handle(), &paintStruct);
1530     //
1531     {
1532         MemoryDC memDC(hdc, paintStruct.rcPaint);
1533         //
1534         ::SetBkColor(memDC, this->BackgroundColor());
1535         this->PaintToHDC(memDC, paintStruct.rcPaint);
1536     }
1537     //
1538     ::EndPaint(this->Handle(), &paintStruct);
1539     */
1540     this->DefaultWindowProc(WM_PAINT, NULL, NULL);
1541 }
1542 
OnEraseBackground(HDC hdc)1543 void        Window::OnEraseBackground(HDC hdc)
1544 {
1545     /*
1546     ::InvalidateRect(this->Handle(), NULL, FALSE);
1547     */
1548     this->DefaultWindowProc(WM_ERASEBKGND, (WPARAM) hdc, NULL);
1549 }
1550 
OnRequestFocusNext()1551 void        Window::OnRequestFocusNext()
1552 {
1553     this->RequestFocusNext(this);
1554 }
1555 
OnRequestFocusPrev()1556 void        Window::OnRequestFocusPrev()
1557 {
1558     this->RequestFocusPrev(this);
1559 }
1560 
1561 
OnControlColor(HDC hdc)1562 HBRUSH      Window::OnControlColor(HDC hdc)
1563 {
1564     if (this->backgroundColor)
1565     {
1566         Color bgColor = this->BackgroundColor();
1567         if ( ! this->backgroundBrush)
1568         {
1569             this->backgroundBrush = ::CreateSolidBrush(bgColor);
1570         }
1571 
1572         return this->backgroundBrush;
1573     }
1574 
1575     return NULL;
1576 }
1577 
PaintToHDC(HDC hdc,const Rect & rect)1578 void        Window::PaintToHDC(HDC hdc, const Rect& rect)
1579 {
1580     this->WindowProc(WM_PRINT, (WPARAM) (HDC) hdc, PRF_CLIENT);
1581 }
1582 
SetParent(Window * child,Window * newParent)1583 void         Window::SetParent(Window* child, Window* newParent)
1584 {
1585     // Only alow the reparent if both windows have been created
1586     // and the new parent is different than the current.
1587     if (child && newParent)
1588     {
1589         Window* oldParent = child->Parent();
1590 
1591         if (oldParent)
1592         {
1593             if ((child->Handle() && newParent->Handle()) && (oldParent != newParent))
1594             {
1595                 if (::SetParent(child->Handle(), newParent->Handle()))
1596                 {
1597                     child->OnParentChangedBase(oldParent, newParent);
1598                 }
1599             }
1600         }
1601     }
1602 }
1603 
1604 /*!< */
LayoutWidth() const1605 LayoutFlags     Window::LayoutWidth() const
1606 {
1607     return this->layoutWidth;
1608 }
1609 
1610 /*!< */
LayoutHeight() const1611 LayoutFlags     Window::LayoutHeight() const
1612 {
1613     return this->layoutHeight;
1614 }
1615 
1616 /*!< */
LayoutAlignment() const1617 LayoutAlignFlag Window::LayoutAlignment() const
1618 {
1619     return this->layoutAlignment;
1620 }
1621 
1622 /*!< */
SetLayoutFlags(LayoutFlags width,LayoutFlags height)1623 void            Window::SetLayoutFlags(LayoutFlags width, LayoutFlags height)
1624 {
1625     if (((width != LayoutWrapContent) && (width != LayoutFillParent))
1626     || ((height != LayoutWrapContent) && (height != LayoutFillParent)))
1627     {
1628         throw InvalidLayoutFlagsException();
1629     }
1630 
1631     if ((width != this->layoutWidth) || (height != this->layoutHeight))
1632     {
1633         this->layoutWidth = width;
1634         this->layoutHeight = height;
1635         this->OnLayoutParametersChangedBase();
1636     }
1637 }
1638 
1639 /*!< */
SetLayoutFlags(LayoutFlags flags)1640 void            Window::SetLayoutFlags(LayoutFlags flags)
1641 {
1642     switch (flags)
1643     {
1644     case LayoutWrapWrap:
1645         this->SetLayoutFlags(LayoutWrapContent, LayoutWrapContent);
1646         break;
1647 
1648     case LayoutFillWrap:
1649         this->SetLayoutFlags(LayoutFillParent, LayoutWrapContent);
1650         break;
1651 
1652     case LayoutWrapFill:
1653         this->SetLayoutFlags(LayoutWrapContent, LayoutFillParent);
1654         break;
1655 
1656     case LayoutFillFill:
1657         this->SetLayoutFlags(LayoutFillParent, LayoutFillParent);
1658         break;
1659 
1660     default:
1661         throw InvalidLayoutFlagsException();
1662     }
1663 }
1664 
1665 /*!< */
SetLayoutAlignment(LayoutAlignFlag alignment)1666 void            Window::SetLayoutAlignment(LayoutAlignFlag alignment)
1667 {
1668     if (this->layoutAlignment != alignment)
1669     {
1670         this->layoutAlignment = alignment;
1671         this->OnLayoutParametersChangedBase();
1672     }
1673 }
1674 
1675 /*!< */
LayoutWeight() const1676 float           Window::LayoutWeight() const
1677 {
1678     return this->layoutWeight;
1679 }
1680 
1681 /*!< */
SetLayoutWeight(float weight)1682 void            Window::SetLayoutWeight(float weight)
1683 {
1684     if (weight < 0.0f)
1685     {
1686         throw InvalidLayoutWeightException();
1687     }
1688 
1689     if (this->layoutWeight != weight)
1690     {
1691         this->layoutWeight = weight;
1692         this->OnLayoutParametersChangedBase();
1693     }
1694 }