0031067: Visualization - Aspect_Window::DoResize() should be a non-const method
[occt.git] / src / WNT / WNT_Window.cxx
1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #if defined(_WIN32)
16   // include windows.h first to have all definitions available
17   #include <windows.h>
18 #endif
19
20 #include <WNT_Window.hxx>
21
22 #if defined(_WIN32) && !defined(OCCT_UWP)
23
24 #include <Aspect_Convert.hxx>
25 #include <Aspect_WindowDefinitionError.hxx>
26 #include <Aspect_WindowError.hxx>
27 #include <Standard_Type.hxx>
28 #include <TCollection_ExtendedString.hxx>
29 #include <WNT_WClass.hxx>
30
31 IMPLEMENT_STANDARD_RTTIEXT(WNT_Window, Aspect_Window)
32
33 // =======================================================================
34 // function : WNT_Window
35 // purpose  :
36 // =======================================================================
37 WNT_Window::WNT_Window (const Standard_CString           theTitle,
38                         const Handle(WNT_WClass)&        theClass,
39                         const WNT_Dword&                 theStyle,
40                         const Standard_Integer           thePxLeft,
41                         const Standard_Integer           thePxTop,
42                         const Standard_Integer           thePxWidth,
43                         const Standard_Integer           thePxHeight,
44                         const Quantity_NameOfColor       theBackColor,
45                         const Aspect_Handle              theParent,
46                         const Aspect_Handle              theMenu,
47                         const Standard_Address           theClientStruct)
48 : Aspect_Window(),
49   aXLeft (thePxLeft),
50   aYTop (thePxTop),
51   aXRight (thePxLeft + thePxWidth),
52   aYBottom (thePxTop + thePxHeight),
53   myWClass (theClass),
54   myIsForeign (Standard_False)
55 {
56   if (thePxWidth <= 0 || thePxHeight <= 0)
57   {
58     throw Aspect_WindowDefinitionError("Coordinate(s) out of range");
59   }
60
61   DWORD aStyle = theStyle;
62   if (theParent && !(theStyle & WS_CHILD))
63   {
64     aStyle |= WS_CHILD | WS_CLIPSIBLINGS;
65   }
66   else if (!theParent && !(theStyle & WS_CLIPCHILDREN))
67   {
68     aStyle |= WS_CLIPCHILDREN;
69   }
70
71   // include decorations in the window dimensions to reproduce same behavior of Xw_Window
72   RECT aRect;
73   aRect.top    = aYTop;
74   aRect.bottom = aYBottom;
75   aRect.left   = aXLeft;
76   aRect.right  = aXRight;
77   AdjustWindowRect (&aRect, aStyle, theMenu != NULL ? TRUE : FALSE);
78   aXLeft   = aRect.left;
79   aYTop    = aRect.top;
80   aXRight  = aRect.right;
81   aYBottom = aRect.bottom;
82
83   const TCollection_ExtendedString aTitleW (theTitle);
84   const TCollection_ExtendedString aClassNameW (myWClass->Name());
85   myHWindow = CreateWindowW (aClassNameW.ToWideString(), aTitleW.ToWideString(),
86                              aStyle,
87                              aXLeft, aYTop,
88                              (aXRight - aXLeft), (aYBottom - aYTop),
89                              (HWND )theParent,
90                              (HMENU )theMenu,
91                              (HINSTANCE )myWClass->Instance(),
92                              theClientStruct);
93   if (!myHWindow)
94   {
95     throw Aspect_WindowDefinitionError("Unable to create window");
96   }
97
98   myHParentWindow = theParent;
99   SetBackground (theBackColor);
100 }
101
102 // =======================================================================
103 // function : WNT_Window
104 // purpose  :
105 // =======================================================================
106 WNT_Window::WNT_Window (const Aspect_Handle        theHandle,
107                         const Quantity_NameOfColor theBackColor)
108 : myIsForeign (Standard_True)
109 {
110   myHWindow        = theHandle;
111   myHParentWindow  = GetParent ((HWND )theHandle);
112
113   SetBackground (theBackColor);
114
115   WINDOWPLACEMENT aPlace;
116   aPlace.length = sizeof (WINDOWPLACEMENT);
117   ::GetWindowPlacement ((HWND )myHWindow, &aPlace);
118
119   aXLeft   = aPlace.rcNormalPosition.left;
120   aYTop    = aPlace.rcNormalPosition.top;
121   aXRight  = aPlace.rcNormalPosition.right;
122   aYBottom = aPlace.rcNormalPosition.bottom;
123 }
124
125 // =======================================================================
126 // function : ~WNT_Window
127 // purpose  :
128 // =======================================================================
129 WNT_Window::~WNT_Window()
130 {
131   if (myHWindow == NULL
132    || myIsForeign)
133   {
134     return;
135   }
136
137   DestroyWindow ((HWND )myHWindow);
138   myIsForeign = Standard_False;
139 }
140
141 // =======================================================================
142 // function : SetCursor
143 // purpose  :
144 // =======================================================================
145 void WNT_Window::SetCursor (const Aspect_Handle theCursor) const
146 {
147   ::SetClassLongPtrW ((HWND )myHWindow, GCLP_HCURSOR, (LONG_PTR )theCursor);
148 }
149
150 // =======================================================================
151 // function : IsMapped
152 // purpose  :
153 // =======================================================================
154 Standard_Boolean WNT_Window::IsMapped() const
155 {
156   if (IsVirtual())
157   {
158     return Standard_True;
159   }
160
161   WINDOWPLACEMENT aPlace;
162   aPlace.length = sizeof (WINDOWPLACEMENT);
163   ::GetWindowPlacement ((HWND )myHWindow, &aPlace);
164   return !(aPlace.showCmd == SW_HIDE
165         || aPlace.showCmd == SW_MINIMIZE);
166 }
167
168 // =======================================================================
169 // function : Map
170 // purpose  :
171 // =======================================================================
172 void WNT_Window::Map() const
173 {
174   if (!IsVirtual())
175   {
176     Map (SW_SHOW);
177   }
178 }
179
180 // =======================================================================
181 // function : Map
182 // purpose  :
183 // =======================================================================
184 void WNT_Window::Map (const Standard_Integer theMapMode) const
185 {
186   if (IsVirtual())
187   {
188     return;
189   }
190
191   ::ShowWindow   ((HWND )myHWindow, theMapMode);
192   ::UpdateWindow ((HWND )myHWindow);
193 }
194
195 // =======================================================================
196 // function : Unmap
197 // purpose  :
198 // =======================================================================
199 void WNT_Window::Unmap() const
200 {
201   Map (SW_HIDE);
202 }
203
204 // =======================================================================
205 // function : DoResize
206 // purpose  :
207 // =======================================================================
208 Aspect_TypeOfResize WNT_Window::DoResize()
209 {
210   if (IsVirtual())
211   {
212     return Aspect_TOR_UNKNOWN;
213   }
214
215   int                 mask = 0;
216   Aspect_TypeOfResize mode = Aspect_TOR_UNKNOWN;
217   WINDOWPLACEMENT     wp;
218
219   wp.length = sizeof ( WINDOWPLACEMENT );
220   GetWindowPlacement (  ( HWND )myHWindow, &wp  );
221
222   if (wp.showCmd != SW_SHOWMINIMIZED)
223   {
224     if (Abs ((int )wp.rcNormalPosition.left   - aXLeft  ) > 2) mask |= 1;
225     if (Abs ((int )wp.rcNormalPosition.right  - aXRight ) > 2) mask |= 2;
226     if (Abs ((int )wp.rcNormalPosition.top    - aYTop   ) > 2) mask |= 4;
227     if (Abs ((int )wp.rcNormalPosition.bottom - aYBottom) > 2) mask |= 8;
228
229     switch (mask)
230     {
231       case 0:
232         mode = Aspect_TOR_NO_BORDER;
233         break;
234       case 1:
235         mode = Aspect_TOR_LEFT_BORDER;
236         break;
237       case 2:
238         mode = Aspect_TOR_RIGHT_BORDER;
239         break;
240       case 4:
241         mode = Aspect_TOR_TOP_BORDER;
242         break;
243       case 5:
244         mode = Aspect_TOR_LEFT_AND_TOP_BORDER;
245         break;
246       case 6:
247         mode = Aspect_TOR_TOP_AND_RIGHT_BORDER;
248         break;
249       case 8:
250         mode = Aspect_TOR_BOTTOM_BORDER;
251         break;
252       case 9:
253         mode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER;
254         break;
255       case 10:
256         mode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER;
257         break;
258       default:
259         break;
260     }  // end switch
261
262     aXLeft   = wp.rcNormalPosition.left;
263     aXRight  = wp.rcNormalPosition.right;
264     aYTop    = wp.rcNormalPosition.top;
265     aYBottom = wp.rcNormalPosition.bottom;
266   }
267
268   return mode;
269 }
270
271 // =======================================================================
272 // function : Ratio
273 // purpose  :
274 // =======================================================================
275 Standard_Real WNT_Window::Ratio() const
276 {
277   if (IsVirtual())
278   {
279     return Standard_Real(aXRight - aXLeft)/ Standard_Real(aYBottom - aYTop);
280   }
281
282   RECT aRect;
283   GetClientRect ((HWND )myHWindow, &aRect);
284   return Standard_Real(aRect.right - aRect.left) / Standard_Real(aRect.bottom - aRect.top);
285 }
286
287 // =======================================================================
288 // function : Position
289 // purpose  :
290 // =======================================================================
291 void WNT_Window::Position (Standard_Integer& theX1, Standard_Integer& theY1,
292                            Standard_Integer& theX2, Standard_Integer& theY2) const
293 {
294   if (IsVirtual())
295   {
296     theX1  = aXLeft;
297     theX2  = aXRight;
298     theY1  = aYTop;
299     theY2  = aYBottom;
300     return;
301   }
302
303   RECT  aRect;
304   ::GetClientRect ((HWND )myHWindow, &aRect);
305
306   POINT aPntLeft, aPntRight;
307   aPntLeft.x = aPntLeft.y = 0;
308   ::ClientToScreen ((HWND )myHWindow, &aPntLeft);
309   aPntRight.x = aRect.right;
310   aPntRight.y = aRect.bottom;
311   ::ClientToScreen ((HWND )myHWindow, &aPntRight);
312
313   if (myHParentWindow != NULL)
314   {
315     ::ScreenToClient ((HWND )myHParentWindow, &aPntLeft);
316     ::ScreenToClient ((HWND )myHParentWindow, &aPntRight);
317   }
318
319   theX1 = aPntLeft.x;
320   theX2 = aPntRight.x;
321   theY1 = aPntLeft.y;
322   theY2 = aPntRight.y;
323 }
324
325 // =======================================================================
326 // function : Size
327 // purpose  :
328 // =======================================================================
329 void WNT_Window::Size (Standard_Integer& theWidth,
330                        Standard_Integer& theHeight) const
331 {
332   if (IsVirtual())
333   {
334     theWidth  = aXRight - aXLeft;
335     theHeight = aYBottom - aYTop;
336     return;
337   }
338
339   RECT aRect;
340   ::GetClientRect ((HWND )myHWindow, &aRect);
341   theWidth  = aRect.right;
342   theHeight = aRect.bottom;
343 }
344
345 // =======================================================================
346 // function : SetPos
347 // purpose  :
348 // =======================================================================
349 void WNT_Window::SetPos (const Standard_Integer theX,  const Standard_Integer theY,
350                          const Standard_Integer theX1, const Standard_Integer theY1)
351 {
352   aXLeft   = theX;
353   aYTop    = theY;
354   aXRight  = theX1;
355   aYBottom = theY1;
356 }
357
358 // =======================================================================
359 // function : SetTitle
360 // purpose  :
361 // =======================================================================
362 void WNT_Window::SetTitle (const TCollection_AsciiString& theTitle)
363 {
364   const TCollection_ExtendedString aTitleW (theTitle);
365   SetWindowTextW ((HWND )myHWindow, aTitleW.ToWideString());
366 }
367
368 // =======================================================================
369 // function : InvalidateContent
370 // purpose  :
371 // =======================================================================
372 void WNT_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& )
373 {
374   if (myHWindow != NULL)
375   {
376     ::InvalidateRect ((HWND )myHWindow, NULL, TRUE);
377   }
378 }
379
380 // =======================================================================
381 // function : VirtualKeyFromNative
382 // purpose  :
383 // =======================================================================
384 Aspect_VKey WNT_Window::VirtualKeyFromNative (Standard_Integer theKey)
385 {
386   if (theKey >= Standard_Integer('0')
387    && theKey <= Standard_Integer('9'))
388   {
389     return Aspect_VKey((theKey - Standard_Integer('0')) + Aspect_VKey_0);
390   }
391   if (theKey >= Standard_Integer('A')
392    && theKey <= Standard_Integer('Z'))
393   {
394     // main latin alphabet keys
395     return Aspect_VKey((theKey - Standard_Integer('A')) + Aspect_VKey_A);
396   }
397   if (theKey >= VK_F1
398    && theKey <= VK_F24)
399   {
400     // special keys
401     if (theKey <= VK_F12)
402     {
403       return Aspect_VKey((theKey - VK_F1) + Aspect_VKey_F1);
404     }
405     return Aspect_VKey_UNKNOWN;
406   }
407   if (theKey >= VK_NUMPAD0
408    && theKey <= VK_NUMPAD9)
409   {
410     // numpad keys
411     return Aspect_VKey((theKey - VK_NUMPAD0) + Aspect_VKey_Numpad0);
412   }
413
414   switch (theKey)
415   {
416     case VK_LBUTTON:
417     case VK_RBUTTON:
418     case VK_CANCEL:
419     case VK_MBUTTON:
420     case VK_XBUTTON1:
421     case VK_XBUTTON2:
422       return Aspect_VKey_UNKNOWN;
423     case VK_BACK:
424       return Aspect_VKey_Backspace;
425     case VK_TAB:
426       return Aspect_VKey_Tab;
427     case VK_CLEAR:
428       return Aspect_VKey_UNKNOWN;
429     case VK_RETURN:
430       return Aspect_VKey_Enter;
431     case VK_SHIFT:
432       return Aspect_VKey_Shift;
433     case VK_CONTROL:
434       return Aspect_VKey_Control;
435     case VK_MENU:
436       return Aspect_VKey_Alt; //Aspect_VKey_Menu;
437     case VK_PAUSE:
438     case VK_CAPITAL:
439       return Aspect_VKey_UNKNOWN;
440     case VK_ESCAPE:
441       return Aspect_VKey_Escape;
442     case VK_CONVERT:
443     case VK_NONCONVERT:
444     case VK_ACCEPT:
445     case VK_MODECHANGE:
446       return Aspect_VKey_UNKNOWN;
447     case VK_SPACE:
448       return Aspect_VKey_Space;
449     case VK_PRIOR:
450       return Aspect_VKey_PageUp;
451     case VK_NEXT:
452       return Aspect_VKey_PageDown;
453     case VK_END:
454       return Aspect_VKey_End;
455     case VK_HOME:
456       return Aspect_VKey_Home;
457     case VK_LEFT:
458       return Aspect_VKey_Left;
459     case VK_UP:
460       return Aspect_VKey_Up;
461     case VK_DOWN:
462       return Aspect_VKey_Down;
463     case VK_RIGHT:
464       return Aspect_VKey_Right;
465     case VK_SELECT:
466     case VK_PRINT:
467     case VK_EXECUTE:
468     case VK_SNAPSHOT:
469       return Aspect_VKey_UNKNOWN;
470     case VK_INSERT:
471       return Aspect_VKey_UNKNOWN; // Aspect_VKey_Insert
472     case VK_DELETE:
473       return Aspect_VKey_Delete;
474     case VK_HELP:
475     case VK_LWIN:
476     case VK_RWIN:
477     case VK_APPS:
478     case VK_SLEEP:
479       return Aspect_VKey_UNKNOWN;
480     case VK_MULTIPLY:
481       return Aspect_VKey_NumpadMultiply;
482     case VK_ADD:
483       return Aspect_VKey_NumpadAdd;
484     case VK_SEPARATOR:
485     case VK_DECIMAL:
486       return Aspect_VKey_UNKNOWN;
487     case VK_SUBTRACT:
488       return Aspect_VKey_NumpadSubtract;
489     case VK_DIVIDE:
490       return Aspect_VKey_NumpadDivide;
491     case VK_NUMLOCK:
492       return Aspect_VKey_Numlock;
493     case VK_SCROLL:
494       return Aspect_VKey_Scroll;
495     case VK_LSHIFT:
496     case VK_RSHIFT:
497     case VK_LCONTROL:
498     case VK_RCONTROL:
499     case VK_LMENU:
500     case VK_RMENU:
501       return Aspect_VKey_UNKNOWN;
502     case VK_BROWSER_BACK:
503       return Aspect_VKey_BrowserBack;
504     case VK_BROWSER_FORWARD:
505       return Aspect_VKey_BrowserForward;
506     case VK_BROWSER_REFRESH:
507       return Aspect_VKey_BrowserRefresh;
508     case VK_BROWSER_STOP:
509       return Aspect_VKey_BrowserStop;
510     case VK_BROWSER_SEARCH:
511       return Aspect_VKey_BrowserSearch;
512     case VK_BROWSER_FAVORITES:
513       return Aspect_VKey_BrowserFavorites;
514     case VK_BROWSER_HOME:
515       return Aspect_VKey_BrowserHome;
516     case VK_VOLUME_MUTE:
517       return Aspect_VKey_VolumeMute;
518     case VK_VOLUME_DOWN:
519       return Aspect_VKey_VolumeDown;
520     case VK_VOLUME_UP:
521       return Aspect_VKey_VolumeUp;
522     case VK_MEDIA_NEXT_TRACK:
523       return Aspect_VKey_MediaNextTrack;
524     case VK_MEDIA_PREV_TRACK:
525       return Aspect_VKey_MediaPreviousTrack;
526     case VK_MEDIA_STOP:
527       return Aspect_VKey_MediaStop;
528     case VK_MEDIA_PLAY_PAUSE:
529       return Aspect_VKey_MediaPlayPause;
530     case VK_OEM_1:
531       return Aspect_VKey_Semicolon;
532     case VK_OEM_PLUS:
533       return Aspect_VKey_Plus;
534     case VK_OEM_COMMA:
535       return Aspect_VKey_Comma;
536     case VK_OEM_MINUS:
537       return Aspect_VKey_Minus;
538     case VK_OEM_PERIOD:
539       return Aspect_VKey_Period;
540     case VK_OEM_2:
541       return Aspect_VKey_Slash;
542     case VK_OEM_3:
543       return Aspect_VKey_Tilde;
544     case VK_OEM_4:
545       return Aspect_VKey_BracketLeft;
546     case VK_OEM_5:
547       return Aspect_VKey_Backslash;
548     case VK_OEM_6:
549       return Aspect_VKey_BracketRight;
550     case VK_OEM_7:
551       return Aspect_VKey_Apostrophe;
552   }
553   return Aspect_VKey_UNKNOWN;
554 }
555
556 // =======================================================================
557 // function : MouseKeyFlagsFromEvent
558 // purpose  :
559 // =======================================================================
560 Aspect_VKeyFlags WNT_Window::MouseKeyFlagsFromEvent (WPARAM theKeys)
561 {
562   Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
563   if ((theKeys & MK_CONTROL) != 0)
564   {
565     aFlags |= Aspect_VKeyFlags_CTRL;
566   }
567   if ((theKeys & MK_SHIFT) != 0)
568   {
569     aFlags |= Aspect_VKeyFlags_SHIFT;
570   }
571   if (GetKeyState (VK_MENU) < 0)
572   {
573     aFlags |= Aspect_VKeyFlags_ALT;
574   }
575   return aFlags;
576 }
577
578 // =======================================================================
579 // function : MouseKeyFlagsAsync
580 // purpose  :
581 // =======================================================================
582 Aspect_VKeyFlags WNT_Window::MouseKeyFlagsAsync()
583 {
584   Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
585   if ((GetAsyncKeyState (VK_CONTROL) & 0x8000) != 0)
586   {
587     aFlags |= Aspect_VKeyFlags_CTRL;
588   }
589   if ((GetAsyncKeyState (VK_SHIFT) & 0x8000) != 0)
590   {
591     aFlags |= Aspect_VKeyFlags_SHIFT;
592   }
593   if ((GetAsyncKeyState (VK_MENU) & 0x8000) != 0)
594   {
595     aFlags |= Aspect_VKeyFlags_ALT;
596   }
597   return aFlags;
598 }
599
600 // =======================================================================
601 // function : MouseButtonsFromEvent
602 // purpose  :
603 // =======================================================================
604 Aspect_VKeyMouse WNT_Window::MouseButtonsFromEvent (WPARAM theKeys)
605 {
606   Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
607   if ((theKeys & MK_LBUTTON) != 0)
608   {
609     aButtons |= Aspect_VKeyMouse_LeftButton;
610   }
611   if ((theKeys & MK_MBUTTON) != 0)
612   {
613     aButtons |= Aspect_VKeyMouse_MiddleButton;
614   }
615   if ((theKeys & MK_RBUTTON) != 0)
616   {
617     aButtons |= Aspect_VKeyMouse_RightButton;
618   }
619   return aButtons;
620 }
621
622 // =======================================================================
623 // function : MouseButtonsAsync
624 // purpose  :
625 // =======================================================================
626 Aspect_VKeyMouse WNT_Window::MouseButtonsAsync()
627 {
628   Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
629   const bool isSwapped = GetSystemMetrics (SM_SWAPBUTTON) != 0;
630
631   if ((GetAsyncKeyState (!isSwapped ? VK_LBUTTON : VK_RBUTTON) & 0x8000) != 0)
632   {
633     aButtons |= Aspect_VKeyMouse_LeftButton;
634   }
635   if ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) != 0)
636   {
637     aButtons |= Aspect_VKeyMouse_MiddleButton;
638   }
639   if ((GetAsyncKeyState (!isSwapped ? VK_RBUTTON : VK_LBUTTON) & 0x8000) != 0)
640   {
641     aButtons |= Aspect_VKeyMouse_RightButton;
642   }
643   return aButtons;
644 }
645
646 #endif // _WIN32