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