1 // Copyright (c) 2013-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
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.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #if defined(__APPLE__) && !defined(MACOSX_USE_GLX)
16 #import <Cocoa/Cocoa.h>
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>
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
32 //! Custom Cocoa view to handle events
33 @interface ViewerTest_CocoaEventManagerView : NSView
36 //! Custom Cocoa window delegate to handle window events
37 @interface Cocoa_WindowController : NSObject <NSWindowDelegate>
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);
56 extern NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
57 extern int X_Motion; // Current cursor position
59 extern int X_ButtonPress; // Last ButtonPress position
60 extern int Y_ButtonPress;
61 extern Standard_Boolean IsDragged;
63 // =======================================================================
64 // function : SetCocoaWindowTitle
66 // =======================================================================
67 void SetCocoaWindowTitle (const Handle(Cocoa_Window)& theWindow, Standard_CString theTitle)
69 NSView* aView = theWindow->HView();
70 NSWindow* aWindow = [aView window];
72 NSString* aTitleNS = [[NSString alloc] initWithUTF8String: theTitle];
73 [aWindow setTitle: aTitleNS];
78 // =======================================================================
79 // function : GetCocoaScreenResolution
81 // =======================================================================
82 void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight)
84 NSRect aRect = [[NSScreen mainScreen] visibleFrame];
85 theWidth = (Standard_Integer )aRect.size.width;
86 theHeight = (Standard_Integer )aRect.size.height;
89 // =======================================================================
90 // function : FindViewId
92 // =======================================================================
93 TCollection_AsciiString FindViewId (const NSWindow* theWindow)
95 TCollection_AsciiString aViewId = "";
96 NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter(ViewerTest_myViews);
97 for (;anIter.More();anIter.Next())
99 NSView* aView = Handle(Cocoa_Window)::DownCast
100 (anIter.Value()->Window())->HView();
101 NSWindow* aWindow = [aView window];
102 if (aWindow == theWindow)
104 aViewId = anIter.Key1();
111 @implementation Cocoa_WindowController
113 - (void )windowWillClose: (NSNotification* )theNotification
115 (void )theNotification;
116 TCollection_AsciiString aViewId = "";
117 if (ViewerTest_myViews.IsBound2 (ViewerTest::CurrentView()))
119 aViewId = ViewerTest_myViews.Find2 (ViewerTest::CurrentView());
121 ViewerTest::RemoveView (aViewId);
124 - (void )windowDidBecomeKey: (NSNotification* )theNotification
126 NSWindow *aWindow = [theNotification object];
127 ActivateView (FindViewId (aWindow));
132 // =======================================================================
133 // function : ViewerMainLoop
135 // =======================================================================
136 int ViewerMainLoop (Standard_Integer, const char** )
142 // =======================================================================
143 // function : ViewerTest_SetCocoaEventManagerView
145 // =======================================================================
146 void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow)
148 if (theWindow.IsNull())
153 NSWindow* aWin = [theWindow->HView() window];
154 NSRect aBounds = [[aWin contentView] bounds];
156 ViewerTest_CocoaEventManagerView* aView = [[ViewerTest_CocoaEventManagerView alloc] initWithFrame: aBounds];
158 // replace content view in the window
159 theWindow->SetHView (aView);
161 // set delegate for window
162 Cocoa_WindowController* aWindowController = [[[Cocoa_WindowController alloc] init] autorelease];
163 [aWin setDelegate: aWindowController];
165 // make view as first responder in winow to capture all useful events
166 [aWin makeFirstResponder: aView];
167 [aWin setAcceptsMouseMovedEvents: YES];
169 // should be retained by parent NSWindow
173 // =======================================================================
174 // function : getMouseCoords
175 // purpose : Retrieve cursor position
176 // =======================================================================
177 static void getMouseCoords (NSView* theView,
179 Standard_Integer& theX,
180 Standard_Integer& theY)
182 NSPoint aMouseLoc = [theView convertPoint: [theEvent locationInWindow] fromView: nil];
183 NSRect aBounds = [theView bounds];
185 theX = Standard_Integer(aMouseLoc.x);
186 theY = Standard_Integer(aBounds.size.height - aMouseLoc.y);
189 @implementation ViewerTest_CocoaEventManagerView
191 // =======================================================================
192 // function : setFrameSize
194 // =======================================================================
195 - (void )setFrameSize: (NSSize )theNewSize
197 [super setFrameSize: theNewSize];
198 VT_ProcessConfigure();
201 // =======================================================================
202 // function : drawRect
204 // =======================================================================
205 - (void )drawRect: (NSRect )theDirtyRect
211 // =======================================================================
212 // function : mouseMoved
214 // =======================================================================
215 - (void )mouseMoved: (NSEvent* )theEvent
217 getMouseCoords (self, theEvent, X_Motion, Y_Motion);
221 // =======================================================================
222 // function : acceptsFirstResponder
224 // =======================================================================
225 - (BOOL )acceptsFirstResponder
230 // =======================================================================
231 // function : mouseDown
233 // =======================================================================
234 - (void )mouseDown: (NSEvent* )theEvent
236 getMouseCoords (self, theEvent, X_ButtonPress, Y_ButtonPress);
237 VT_ProcessButton1Press (0, NULL, Standard_False, [theEvent modifierFlags] & NSEventModifierFlagShift);
240 // =======================================================================
241 // function : mouseUp
243 // =======================================================================
244 - (void )mouseUp: (NSEvent* )theEvent
246 getMouseCoords (self, theEvent, X_Motion, Y_Motion);
247 VT_ProcessButton1Release([theEvent modifierFlags] & NSEventModifierFlagShift);
251 // =======================================================================
252 // function : mouseDragged
254 // =======================================================================
255 - (void )mouseDragged: (NSEvent* )theEvent
257 IsDragged = Standard_True;
258 if ([theEvent modifierFlags] & NSEventModifierFlagControl)
260 getMouseCoords (self, theEvent, X_Motion, Y_Motion);
261 VT_ProcessControlButton2Motion();
265 // =======================================================================
266 // function : rightMouseDown
268 // =======================================================================
269 - (void )rightMouseDown: (NSEvent* )theEvent
271 getMouseCoords (self, theEvent, X_ButtonPress, Y_ButtonPress);
272 VT_ProcessButton3Press(); // Start rotation
275 // =======================================================================
276 // function : rightMouseUp
278 // =======================================================================
279 - (void )rightMouseUp: (NSEvent* )theEvent
282 VT_ProcessButton3Release();
285 // =======================================================================
286 // function : rightMouseDragged
288 // =======================================================================
289 - (void )rightMouseDragged: (NSEvent* )theEvent
291 if ([theEvent modifierFlags] & NSEventModifierFlagControl)
293 getMouseCoords (self, theEvent, X_Motion, Y_Motion);
294 VT_ProcessControlButton3Motion();
298 // =======================================================================
299 // function : scrollWheel
301 // =======================================================================
302 - (void )scrollWheel: (NSEvent* )theEvent
304 float aDelta = [theEvent deltaY];
305 if (Abs (aDelta) < 0.001)
307 // a lot of values near zero can be generated by touchpad
311 ViewerTest::CurrentView()->Zoom (0, 0, aDelta, aDelta);
314 // =======================================================================
315 // function : keyDown
317 // =======================================================================
318 - (void )keyDown: (NSEvent* )theEvent
320 NSString* aStringNs = [theEvent characters];
321 if (aStringNs == NULL || [aStringNs length] == 0)
326 const Standard_CString aString = [aStringNs UTF8String];
327 VT_ProcessKeyPress (aString);