0032308: Configuration - make Xlib dependency optional
[occt.git] / src / ViewerTest / ViewerTest_ViewerCommands_1.mm
1 // Copyright (c) 2013-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #if defined(__APPLE__) && !defined(HAVE_XLIB)
15
16 #import <Cocoa/Cocoa.h>
17
18 #include <Cocoa_Window.hxx>
19 #include <ViewerTest.hxx>
20 #include <ViewerTest_EventManager.hxx>
21 #include <V3d_View.hxx>
22 #include <V3d_Viewer.hxx>
23 #include <AIS_InteractiveContext.hxx>
24 #include <TCollection_AsciiString.hxx>
25 #include <NCollection_DoubleMap.hxx>
26
27 #if !defined(MAC_OS_X_VERSION_10_12) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12)
28   // replacements for macOS versions before 10.12
29   #define NSEventModifierFlagControl  NSControlKeyMask
30   #define NSEventModifierFlagShift    NSShiftKeyMask
31   #define NSEventModifierFlagOption   NSAlternateKeyMask
32   #define NSEventModifierFlagCommand  NSCommandKeyMask
33   #define NSEventModifierFlagFunction NSFunctionKeyMask
34 #endif
35
36 //! Custom Cocoa view to handle events
37 @interface ViewerTest_CocoaEventManagerView : NSView
38 @end
39
40 //! Custom Cocoa window delegate to handle window events
41 @interface Cocoa_WindowController : NSObject <NSWindowDelegate>
42 @end
43
44 extern void ActivateView (const TCollection_AsciiString& theViewName,
45                           Standard_Boolean theToUpdate = Standard_True);
46
47 extern NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
48
49 // =======================================================================
50 // function : GetCocoaScreenResolution
51 // purpose  :
52 // =======================================================================
53 void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight)
54 {
55   NSRect aRect = [[NSScreen mainScreen] visibleFrame];
56   theWidth = (Standard_Integer )aRect.size.width;
57   theHeight = (Standard_Integer )aRect.size.height;
58 }
59
60 // =======================================================================
61 // function : FindViewId
62 // purpose  :
63 // =======================================================================
64 TCollection_AsciiString FindViewId (const NSWindow* theWindow)
65 {
66   TCollection_AsciiString aViewId = "";
67   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter(ViewerTest_myViews);
68   for (;anIter.More();anIter.Next())
69   {
70     NSView* aView = Handle(Cocoa_Window)::DownCast
71                    (anIter.Value()->Window())->HView();
72     NSWindow* aWindow = [aView window];
73     if (aWindow == theWindow)
74     {
75       aViewId = anIter.Key1();
76       return aViewId;
77     }
78   }
79   return aViewId;
80 }
81
82 @implementation Cocoa_WindowController
83
84 - (void )windowWillClose: (NSNotification* )theNotification
85 {
86   (void )theNotification;
87   TCollection_AsciiString aViewId = "";
88   if (ViewerTest_myViews.IsBound2 (ViewerTest::CurrentView()))
89   {
90     aViewId = ViewerTest_myViews.Find2 (ViewerTest::CurrentView());
91   }
92   ViewerTest::RemoveView (aViewId);
93 }
94
95 - (void )windowDidBecomeKey: (NSNotification* )theNotification
96 {
97   NSWindow *aWindow = [theNotification object];
98   ActivateView (FindViewId (aWindow));
99 }
100
101 @end
102
103 // =======================================================================
104 // function : ViewerMainLoop
105 // purpose  :
106 // =======================================================================
107 int ViewerMainLoop (Standard_Integer, const char** )
108 {
109   // unused
110   return 0;
111 }
112
113 // =======================================================================
114 // function : ViewerTest_SetCocoaEventManagerView
115 // purpose  :
116 // =======================================================================
117 void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow)
118 {
119   if (theWindow.IsNull())
120   {
121     return;
122   }
123
124   NSWindow* aWin = [theWindow->HView() window];
125   NSRect aBounds = [[aWin contentView] bounds];
126
127   ViewerTest_CocoaEventManagerView* aView = [[ViewerTest_CocoaEventManagerView alloc] initWithFrame: aBounds];
128
129   // replace content view in the window
130   theWindow->SetHView (aView);
131
132   // set delegate for window
133   Cocoa_WindowController* aWindowController = [[[Cocoa_WindowController alloc] init] autorelease];
134   [aWin setDelegate: aWindowController];
135   
136   // make view as first responder in winow to capture all useful events
137   [aWin makeFirstResponder: aView];
138   [aWin setAcceptsMouseMovedEvents: YES];
139
140   // should be retained by parent NSWindow
141   [aView release];
142 }
143
144 //! Retrieve cursor position
145 static Graphic3d_Vec2i getMouseCoords (NSView*  theView,
146                                        NSEvent* theEvent)
147 {
148   NSPoint aMouseLoc = [theView convertPoint: [theEvent locationInWindow] fromView: nil];
149   NSRect  aBounds   = [theView bounds];
150   return Graphic3d_Vec2i (Standard_Integer(aMouseLoc.x),
151                           Standard_Integer(aBounds.size.height - aMouseLoc.y));
152 }
153
154 //! Convert key flags from mouse event.
155 static Aspect_VKeyFlags getMouseKeyFlags (NSEvent* theEvent)
156 {
157   Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
158   if (([theEvent modifierFlags] & NSEventModifierFlagShift) != 0)
159   {
160     aFlags |= Aspect_VKeyFlags_SHIFT;
161   }
162   if (([theEvent modifierFlags] & NSEventModifierFlagControl) != 0)
163   {
164     aFlags |= Aspect_VKeyFlags_CTRL;
165   }
166   if (([theEvent modifierFlags] & NSEventModifierFlagOption) != 0)
167   {
168     aFlags |= Aspect_VKeyFlags_ALT;
169   }
170   if (([theEvent modifierFlags] & NSEventModifierFlagFunction) != 0)
171   {
172     //aFlags |= Aspect_VKeyFlags_FUNC;
173   }
174   if (([theEvent modifierFlags] & NSEventModifierFlagCommand) != 0)
175   {
176     //aFlags |= Aspect_VKeyFlags_CMD;
177   }
178   return aFlags;
179 }
180
181 @implementation ViewerTest_CocoaEventManagerView
182
183 // =======================================================================
184 // function : setFrameSize
185 // purpose  :
186 // =======================================================================
187 - (void )setFrameSize: (NSSize )theNewSize
188 {
189   [super setFrameSize: theNewSize];
190   ViewerTest::CurrentEventManager()->ProcessConfigure();
191 }
192
193 // =======================================================================
194 // function : drawRect
195 // purpose  :
196 // =======================================================================
197 - (void )drawRect: (NSRect )theDirtyRect
198 {
199   (void )theDirtyRect;
200   if (!ViewerTest::CurrentEventManager().IsNull())
201   {
202     ViewerTest::CurrentEventManager()->ProcessExpose();
203   }
204 }
205
206 // =======================================================================
207 // function : mouseMoved
208 // purpose  :
209 // =======================================================================
210 - (void )mouseMoved: (NSEvent* )theEvent
211 {
212   const Graphic3d_Vec2i  aPos   = getMouseCoords (self, theEvent);
213   const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent);
214   const Aspect_VKeyMouse aButtons = ViewerTest::CurrentEventManager()->PressedMouseButtons();
215   ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
216   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
217 }
218
219 // =======================================================================
220 // function : acceptsFirstResponder
221 // purpose  :
222 // =======================================================================
223 - (BOOL )acceptsFirstResponder
224 {
225   return YES;
226 }
227
228 // =======================================================================
229 // function : mouseDown
230 // purpose  :
231 // =======================================================================
232 - (void )mouseDown: (NSEvent* )theEvent
233 {
234   const Graphic3d_Vec2i  aPos   = getMouseCoords (self, theEvent);
235   const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent);
236   ViewerTest::CurrentEventManager()->PressMouseButton (aPos, Aspect_VKeyMouse_LeftButton, aFlags, false);
237   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
238 }
239
240 // =======================================================================
241 // function : mouseUp
242 // purpose  :
243 // =======================================================================
244 - (void )mouseUp: (NSEvent* )theEvent
245 {
246   const Graphic3d_Vec2i  aPos   = getMouseCoords (self, theEvent);
247   const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent);
248   ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, Aspect_VKeyMouse_LeftButton, aFlags, false);
249   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
250 }
251
252 // =======================================================================
253 // function : mouseDragged
254 // purpose  :
255 // =======================================================================
256 - (void )mouseDragged: (NSEvent* )theEvent
257 {
258   const Graphic3d_Vec2i  aPos   = getMouseCoords (self, theEvent);
259   const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent);
260   const Aspect_VKeyMouse aButtons = ViewerTest::CurrentEventManager()->PressedMouseButtons();
261   ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
262   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
263 }
264
265 // =======================================================================
266 // function : rightMouseDown
267 // purpose  :
268 // =======================================================================
269 - (void )rightMouseDown: (NSEvent* )theEvent
270 {
271   const Graphic3d_Vec2i  aPos   = getMouseCoords (self, theEvent);
272   const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent);
273   ViewerTest::CurrentEventManager()->PressMouseButton (aPos, Aspect_VKeyMouse_RightButton, aFlags, false);
274   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
275 }
276
277 // =======================================================================
278 // function : rightMouseUp
279 // purpose  :
280 // =======================================================================
281 - (void )rightMouseUp: (NSEvent* )theEvent
282 {
283   const Graphic3d_Vec2i  aPos   = getMouseCoords (self, theEvent);
284   const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent);
285   ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, Aspect_VKeyMouse_RightButton, aFlags, false);
286   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
287 }
288
289 // =======================================================================
290 // function : rightMouseDragged
291 // purpose  :
292 // =======================================================================
293 - (void )rightMouseDragged: (NSEvent* )theEvent
294 {
295   const Graphic3d_Vec2i  aPos   = getMouseCoords (self, theEvent);
296   const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent);
297   const Aspect_VKeyMouse aButtons = ViewerTest::CurrentEventManager()->PressedMouseButtons();
298   ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
299   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
300 }
301
302 // =======================================================================
303 // function : scrollWheel
304 // purpose  :
305 // =======================================================================
306 - (void )scrollWheel: (NSEvent* )theEvent
307 {
308   const Graphic3d_Vec2i  aPos   = getMouseCoords (self, theEvent);
309   const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent);
310
311   const Standard_Real aDelta = [theEvent deltaY];
312   if (Abs (aDelta) < 0.001)
313   {
314     // a lot of values near zero can be generated by touchpad
315     return;
316   }
317
318   ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDelta, aFlags));
319   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
320 }
321
322 // =======================================================================
323 // function : keyDown
324 // purpose  :
325 // =======================================================================
326 - (void )keyDown: (NSEvent* )theEvent
327 {
328   unsigned int aKeyCode = [theEvent keyCode];
329   const Aspect_VKey aVKey = Cocoa_Window::VirtualKeyFromNative (aKeyCode);
330   if (aVKey != Aspect_VKey_UNKNOWN)
331   {
332     const double aTimeStamp = [theEvent timestamp];
333     ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
334     ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
335   }
336
337   //NSString* aStringNs = [theEvent characters];
338   //if (aStringNs != NULL && [aStringNs length] != 1)
339   //{
340   //  const Standard_CString aString = [aStringNs UTF8String];
341   //}
342 }
343
344 // =======================================================================
345 // function : keyUp
346 // purpose  :
347 // =======================================================================
348 - (void )keyUp: (NSEvent* )theEvent
349 {
350   unsigned int aKeyCode = [theEvent keyCode];
351   const Aspect_VKey aVKey = Cocoa_Window::VirtualKeyFromNative (aKeyCode);
352   if (aVKey != Aspect_VKey_UNKNOWN)
353   {
354     const double aTimeStamp = [theEvent timestamp];
355     ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
356     ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
357   }
358 }
359
360 @end
361
362 #endif