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 }