7d0eb93ad6ea3e18f98dfeba0acf0c8ff1d03e5a
[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 <V3d_View.hxx>
21 #include <V3d_Viewer.hxx>
22 #include <AIS_InteractiveContext.hxx>
23 #include <TCollection_AsciiString.hxx>
24 #include <NCollection_DoubleMap.hxx>
25
26 #if !defined(MAC_OS_X_VERSION_10_12) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12)
27   // replacements for macOS versions before 10.12
28   #define NSEventModifierFlagControl NSControlKeyMask
29   #define NSEventModifierFlagShift   NSShiftKeyMask
30 #endif
31
32 //! Custom Cocoa view to handle events
33 @interface ViewerTest_CocoaEventManagerView : NSView
34 @end
35
36 //! Custom Cocoa window delegate to handle window events
37 @interface Cocoa_WindowController : NSObject <NSWindowDelegate>
38 @end
39
40 extern void ActivateView (const TCollection_AsciiString& theViewName,
41                           Standard_Boolean theToUpdate = Standard_True);
42 extern void VT_ProcessExpose();
43 extern void VT_ProcessConfigure();
44 extern void VT_ProcessKeyPress (const char* theBuffer);
45 extern void VT_ProcessMotion();
46 extern void VT_ProcessButton3Press();
47 extern void VT_ProcessButton3Release();
48 extern void VT_ProcessControlButton2Motion();
49 extern void VT_ProcessControlButton3Motion();
50 extern Standard_Boolean VT_ProcessButton1Press (Standard_Integer theArgsNb,
51                                                 const char**     theArgsVec,
52                                                 Standard_Boolean theToPick,
53                                                 Standard_Boolean theIsShift);
54 extern void VT_ProcessButton1Release(Standard_Boolean theIsShift);
55
56 extern NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
57 extern int X_Motion; // Current cursor position
58 extern int Y_Motion;
59 extern int X_ButtonPress; // Last ButtonPress position
60 extern int Y_ButtonPress;
61 extern Standard_Boolean IsDragged;
62
63 // =======================================================================
64 // function : SetCocoaWindowTitle
65 // purpose  :
66 // =======================================================================
67 void SetCocoaWindowTitle (const Handle(Cocoa_Window)& theWindow, Standard_CString theTitle)
68 {
69   NSView* aView = theWindow->HView();
70   NSWindow* aWindow = [aView window];
71
72   NSString* aTitleNS = [[NSString alloc] initWithUTF8String: theTitle];
73   [aWindow setTitle: aTitleNS];
74   [aTitleNS release];
75   
76 }
77
78 // =======================================================================
79 // function : GetCocoaScreenResolution
80 // purpose  :
81 // =======================================================================
82 void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight)
83 {
84   NSRect aRect = [[NSScreen mainScreen] visibleFrame];
85   theWidth = (Standard_Integer )aRect.size.width;
86   theHeight = (Standard_Integer )aRect.size.height;
87 }
88
89 // =======================================================================
90 // function : FindViewId
91 // purpose  :
92 // =======================================================================
93 TCollection_AsciiString FindViewId (const NSWindow* theWindow)
94 {
95   TCollection_AsciiString aViewId = "";
96   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter(ViewerTest_myViews);
97   for (;anIter.More();anIter.Next())
98   {
99     NSView* aView = Handle(Cocoa_Window)::DownCast
100                    (anIter.Value()->Window())->HView();
101     NSWindow* aWindow = [aView window];
102     if (aWindow == theWindow)
103     {
104       aViewId = anIter.Key1();
105       return aViewId;
106     }
107   }
108   return aViewId;
109 }
110
111 @implementation Cocoa_WindowController
112
113 - (void )windowWillClose: (NSNotification* )theNotification
114 {
115   (void )theNotification;
116   TCollection_AsciiString aViewId = "";
117   if (ViewerTest_myViews.IsBound2 (ViewerTest::CurrentView()))
118   {
119     aViewId = ViewerTest_myViews.Find2 (ViewerTest::CurrentView());
120   }
121   ViewerTest::RemoveView (aViewId);
122 }
123
124 - (void )windowDidBecomeKey: (NSNotification* )theNotification
125 {
126   NSWindow *aWindow = [theNotification object];
127   ActivateView (FindViewId (aWindow));
128 }
129
130 @end
131
132 // =======================================================================
133 // function : ViewerMainLoop
134 // purpose  :
135 // =======================================================================
136 int ViewerMainLoop (Standard_Integer, const char** )
137 {
138   // unused
139   return 0;
140 }
141
142 // =======================================================================
143 // function : ViewerTest_SetCocoaEventManagerView
144 // purpose  :
145 // =======================================================================
146 void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow)
147 {
148   if (theWindow.IsNull())
149   {
150     return;
151   }
152
153   NSWindow* aWin = [theWindow->HView() window];
154   NSRect aBounds = [[aWin contentView] bounds];
155
156   ViewerTest_CocoaEventManagerView* aView = [[ViewerTest_CocoaEventManagerView alloc] initWithFrame: aBounds];
157
158   // replace content view in the window
159   theWindow->SetHView (aView);
160
161   // set delegate for window
162   Cocoa_WindowController* aWindowController = [[[Cocoa_WindowController alloc] init] autorelease];
163   [aWin setDelegate: aWindowController];
164   
165   // make view as first responder in winow to capture all useful events
166   [aWin makeFirstResponder: aView];
167   [aWin setAcceptsMouseMovedEvents: YES];
168
169   // should be retained by parent NSWindow
170   [aView release];
171 }
172
173 // =======================================================================
174 // function : getMouseCoords
175 // purpose  : Retrieve cursor position
176 // =======================================================================
177 static void getMouseCoords (NSView*           theView,
178                             NSEvent*          theEvent,
179                             Standard_Integer& theX,
180                             Standard_Integer& theY)
181 {
182   NSPoint aMouseLoc = [theView convertPoint: [theEvent locationInWindow] fromView: nil];
183   NSRect  aBounds   = [theView bounds];
184
185   theX = Standard_Integer(aMouseLoc.x);
186   theY = Standard_Integer(aBounds.size.height - aMouseLoc.y);
187 }
188
189 @implementation ViewerTest_CocoaEventManagerView
190
191 // =======================================================================
192 // function : setFrameSize
193 // purpose  :
194 // =======================================================================
195 - (void )setFrameSize: (NSSize )theNewSize
196 {
197   [super setFrameSize: theNewSize];
198   VT_ProcessConfigure();
199 }
200
201 // =======================================================================
202 // function : drawRect
203 // purpose  :
204 // =======================================================================
205 - (void )drawRect: (NSRect )theDirtyRect
206 {
207   (void )theDirtyRect;
208   VT_ProcessExpose();
209 }
210
211 // =======================================================================
212 // function : mouseMoved
213 // purpose  :
214 // =======================================================================
215 - (void )mouseMoved: (NSEvent* )theEvent
216 {
217   getMouseCoords (self, theEvent, X_Motion, Y_Motion);
218   VT_ProcessMotion();
219 }
220
221 // =======================================================================
222 // function : acceptsFirstResponder
223 // purpose  :
224 // =======================================================================
225 - (BOOL )acceptsFirstResponder
226 {
227   return YES;
228 }
229
230 // =======================================================================
231 // function : mouseDown
232 // purpose  :
233 // =======================================================================
234 - (void )mouseDown: (NSEvent* )theEvent
235 {
236   getMouseCoords (self, theEvent, X_ButtonPress, Y_ButtonPress);
237   VT_ProcessButton1Press (0, NULL, Standard_False, [theEvent modifierFlags] & NSEventModifierFlagShift);
238 }
239
240 // =======================================================================
241 // function : mouseUp
242 // purpose  :
243 // =======================================================================
244 - (void )mouseUp: (NSEvent* )theEvent
245 {
246   getMouseCoords (self, theEvent, X_Motion, Y_Motion);
247   VT_ProcessButton1Release([theEvent modifierFlags] & NSEventModifierFlagShift);
248 }
249
250
251 // =======================================================================
252 // function : mouseDragged
253 // purpose  :
254 // =======================================================================
255 - (void )mouseDragged: (NSEvent* )theEvent
256 {
257   IsDragged = Standard_True;
258   if ([theEvent modifierFlags] & NSEventModifierFlagControl)
259   {
260     getMouseCoords (self, theEvent, X_Motion, Y_Motion);
261     VT_ProcessControlButton2Motion();
262   }
263 }
264
265 // =======================================================================
266 // function : rightMouseDown
267 // purpose  :
268 // =======================================================================
269 - (void )rightMouseDown: (NSEvent* )theEvent
270 {
271   getMouseCoords (self, theEvent, X_ButtonPress, Y_ButtonPress);
272   VT_ProcessButton3Press(); // Start rotation
273 }
274
275 // =======================================================================
276 // function : rightMouseUp
277 // purpose  :
278 // =======================================================================
279 - (void )rightMouseUp: (NSEvent* )theEvent
280 {
281   (void )theEvent;
282   VT_ProcessButton3Release();
283 }
284
285 // =======================================================================
286 // function : rightMouseDragged
287 // purpose  :
288 // =======================================================================
289 - (void )rightMouseDragged: (NSEvent* )theEvent
290 {
291   if ([theEvent modifierFlags] & NSEventModifierFlagControl)
292   {
293     getMouseCoords (self, theEvent, X_Motion, Y_Motion);
294     VT_ProcessControlButton3Motion();
295   }
296 }
297
298 // =======================================================================
299 // function : scrollWheel
300 // purpose  :
301 // =======================================================================
302 - (void )scrollWheel: (NSEvent* )theEvent
303 {
304   float aDelta = [theEvent deltaY];
305   if (Abs (aDelta) < 0.001)
306   {
307     // a lot of values near zero can be generated by touchpad
308     return;
309   }
310
311   ViewerTest::CurrentView()->Zoom (0, 0, aDelta, aDelta);
312 }
313
314 // =======================================================================
315 // function : keyDown
316 // purpose  :
317 // =======================================================================
318 - (void )keyDown: (NSEvent* )theEvent
319 {
320   NSString* aStringNs = [theEvent characters];
321   if (aStringNs == NULL || [aStringNs length] == 0)
322   {
323     return;
324   }
325
326   const Standard_CString aString = [aStringNs UTF8String];
327   VT_ProcessKeyPress (aString);
328 }
329
330 @end
331
332 #endif