ce12c46d3bf374d1816766f865b8a5a0117c2320
[occt.git] / src / Draw / Draw_Window_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 <Draw_Window.hxx>
19 #include <Cocoa_LocalPool.hxx>
20
21 #if !defined(MAC_OS_X_VERSION_10_12) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12)
22   // replacements for macOS versions before 10.12
23   #define NSEventTypeLeftMouseDown    NSLeftMouseDown
24   #define NSEventTypeRightMouseDown   NSRightMouseDown
25   #define NSEventTypeLeftMouseDragged NSLeftMouseDragged
26   #define NSEventTypeMouseMoved       NSMouseMoved
27
28   #define NSEventMaskLeftMouseDragged NSLeftMouseDraggedMask
29   #define NSEventMaskMouseMoved       NSMouseMovedMask
30   #define NSEventMaskLeftMouseDown    NSLeftMouseDownMask
31   #define NSEventMaskRightMouseDown   NSRightMouseDownMask
32
33   #define NSWindowStyleMaskResizable  NSResizableWindowMask
34   #define NSWindowStyleMaskClosable   NSClosableWindowMask
35   #define NSWindowStyleMaskTitled     NSTitledWindowMask
36
37   #define NSCompositingOperationSourceOver NSCompositeSourceOver
38 #endif
39 #if !defined(MAC_OS_X_VERSION_10_14) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_14)
40   #define NSBitmapImageFileTypePNG  NSPNGFileType
41   #define NSBitmapImageFileTypeBMP  NSBMPFileType
42   #define NSBitmapImageFileTypeJPEG NSJPEGFileType
43   #define NSBitmapImageFileTypeGIF  NSGIFFileType
44 #endif
45
46 @interface Draw_CocoaView : NSView
47 {
48   NSImage* myImage;
49 }
50
51 - (void )setImage: (NSImage* )theImage;
52 - (void )redraw;
53 @end
54
55 @implementation Draw_CocoaView
56
57 - (void )setImage: (NSImage* )theImage
58 {
59   [theImage retain];
60   [myImage release];
61   myImage = theImage;
62 }
63
64 - (BOOL )isFlipped
65 {
66   return YES; // for drawing image from left-top corner
67 }
68
69 - (void )redraw
70 {
71   [self setNeedsDisplay: YES];
72 }
73
74 - (void )drawRect: (NSRect )theRect
75 {
76   (void )theRect;
77   NSRect aBounds = NSMakeRect (0.0, 0.0, myImage.size.width, myImage.size.height);
78
79   [myImage drawInRect: aBounds
80              fromRect: NSZeroRect
81             operation: NSCompositingOperationSourceOver
82              fraction: 1
83        respectFlipped: YES
84                 hints: nil];
85 }
86
87 - (void )dealloc
88 {
89   [myImage release];
90   [super dealloc];
91 }
92 @end
93
94 static Standard_Integer getScreenBottom()
95 {
96   NSRect aRect = [[[NSScreen screens] objectAtIndex:0] frame];
97   Standard_Integer aScreenBottom = Standard_Integer(aRect.size.height + aRect.origin.y);
98   return aScreenBottom;
99 }
100
101 extern Standard_Boolean Draw_VirtualWindows;
102 static Standard_Boolean Draw_IsInZoomingMode = Standard_False;
103
104 Standard_Real Draw_RGBColorsArray[MAXCOLOR][3] = {{1.0,  1.0,  1.0},
105                                                   {1.0,  0.0,  0.0},
106                                                   {0.0,  1.0,  0.0},
107                                                   {0.0,  0.0,  1.0},
108                                                   {0.0,  1.0,  1.0},
109                                                   {1.0,  0.84, 0.0},
110                                                   {1.0,  0.0,  1.0},
111                                                   {1.0,  0.2,  0.7},
112                                                   {1.0,  0.65, 0.0},
113                                                   {1.0,  0.89, 0.88},
114                                                   {1.0,  0.63, 0.48},
115                                                   {0.78, 0.08, 0.52},
116                                                   {1.0,  1.0,  0.0},
117                                                   {0.94, 0.9,  0.55},
118                                                   {1.0,  0.5,  0.31}};
119
120 //=======================================================================
121 //function : Draw_Window
122 //purpose  :
123 //=======================================================================
124 Draw_Window::Draw_Window() :
125   myWindow (NULL),
126   myView (NULL),
127   myImageBuffer (NULL),
128   myUseBuffer (Standard_False),
129   nextWindow (firstWindow),
130   previousWindow (NULL)
131 {
132   if (firstWindow != NULL) firstWindow->previousWindow = this;
133   firstWindow = this;
134 }
135
136 //=======================================================================
137 //function : Draw_Window
138 //purpose  :
139 //=======================================================================
140 Draw_Window::Draw_Window (Standard_CString theTitle,
141                           const Standard_Integer& theXLeft, const Standard_Integer& theYTop,
142                           const Standard_Integer& theWidth, const Standard_Integer& theHeight):
143   myWindow (NULL),
144   myView (NULL),
145   myImageBuffer (NULL),
146   myUseBuffer (Standard_False),
147   nextWindow (firstWindow),
148   previousWindow (NULL)
149 {
150   if (firstWindow != NULL) firstWindow->previousWindow = this;
151   firstWindow = this;
152   Init (theXLeft, theYTop, theWidth, theHeight);
153   SetTitle (theTitle);
154 }
155
156 Draw_Window::Draw_Window (NSWindow*               theWindow, Standard_CString        theTitle,
157                           const Standard_Integer& theXLeft,  const Standard_Integer& theYTop,
158                           const Standard_Integer& theWidth,  const Standard_Integer& theHeight):
159   myWindow (NULL),
160   myView (NULL),
161   myImageBuffer (NULL),
162   myUseBuffer (Standard_False),
163   nextWindow (firstWindow),
164   previousWindow (NULL)
165 {
166   myWindow = [theWindow retain];
167   if (firstWindow != NULL) firstWindow->previousWindow = this;
168   firstWindow = this;
169   Init (theXLeft, theYTop, theWidth, theHeight);
170   SetTitle (theTitle);
171 }
172
173 //=======================================================================
174 //function : ~Draw_Window
175 //purpose  :
176 //=======================================================================
177 Draw_Window::~Draw_Window()
178 {
179   if (previousWindow != NULL)
180   {
181     previousWindow->nextWindow = nextWindow;
182   }
183   else
184   {
185     firstWindow = nextWindow;
186   }
187
188   if (nextWindow != NULL)
189   {
190     nextWindow->previousWindow = previousWindow;
191   }
192
193   if (myWindow != NULL)
194   { 
195     [myWindow release];
196     myWindow = NULL;
197   }
198
199   if (myView != NULL)
200   {
201     [myView release];
202     myView = NULL;
203   }
204
205   if (myImageBuffer != NULL)
206   {
207     [myImageBuffer release];
208     myImageBuffer = NULL;
209   }
210 }
211
212 //=======================================================================
213 //function : Init
214 //purpose  :
215 //=======================================================================
216 void Draw_Window::Init (const Standard_Integer& theXLeft, const Standard_Integer& theYTop,
217                         const Standard_Integer& theWidth, const Standard_Integer& theHeight)
218 {
219   Cocoa_LocalPool aLocalPool;
220
221   // converting left-bottom coordinate to left-top coordinate
222   Standard_Integer anYTop = getScreenBottom() - theYTop - theHeight;
223
224   if (myWindow == NULL)
225   {
226     NSRect     aRectNs   = NSMakeRect (theXLeft, anYTop, theWidth, theHeight);
227     NSUInteger aWinStyle = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable;
228
229     myWindow = [[NSWindow alloc] initWithContentRect: aRectNs
230                                            styleMask: aWinStyle
231                                              backing: NSBackingStoreBuffered
232                                                defer: NO];
233   }
234
235   if (myView == NULL)
236   {
237     NSRect aBounds = [[myWindow contentView] bounds];
238     
239     myView = [[Draw_CocoaView alloc] initWithFrame: aBounds];
240     [myWindow setContentView: myView];
241   }
242
243   if (myImageBuffer == NULL)
244   {
245     NSRect aRectNs = [myView bounds];
246     myImageBuffer  = [[NSImage alloc] initWithSize: aRectNs.size];
247   }
248
249   [myView setImage: myImageBuffer];
250
251   myUseBuffer = Draw_VirtualWindows;
252
253   myCurrentColor = 3;
254
255   [myWindow setBackgroundColor: NSColor.blackColor];
256   [myWindow setReleasedWhenClosed: NO];
257 }
258
259 //=======================================================================
260 //function : InitBuffer
261 //purpose  :
262 //=======================================================================
263 void Draw_Window::InitBuffer()
264 {
265   //
266 }
267
268 //=======================================================================
269 //function : SetPosition
270 //purpose  :
271 //=======================================================================
272 void Draw_Window::SetPosition (const Standard_Integer& theNewXpos,
273                                const Standard_Integer& theNewYpos)
274 {
275   NSPoint aNewPosition = NSMakePoint (theNewXpos, theNewYpos);
276   [myWindow setFrameTopLeftPoint: aNewPosition];
277 }
278
279 //=======================================================================
280 //function : SetDimension
281 //purpose  :
282 //=======================================================================
283 void Draw_Window::SetDimension (const Standard_Integer& theNewWidth,
284                                 const Standard_Integer& theNewHeight)
285 {
286   NSRect aWindowRect = [myWindow frame];
287   Standard_Integer aNewY = aWindowRect.origin.y + aWindowRect.size.height - theNewHeight;
288   NSRect aNewContentRect = NSMakeRect (aWindowRect.origin.x, aNewY,
289                                        theNewWidth, theNewHeight);
290   [myWindow setFrame: aNewContentRect display: YES];
291 }
292
293 //=======================================================================
294 //function : GetPosition
295 //purpose  :
296 //=======================================================================
297 void Draw_Window::GetPosition (Standard_Integer &thePosX,
298                                Standard_Integer &thePosY)
299 {
300   NSRect aWindowRect = [myWindow frame];
301   thePosX = aWindowRect.origin.x;
302   thePosY = getScreenBottom() - aWindowRect.origin.y - aWindowRect.size.height;
303 }
304
305 //=======================================================================
306 //function : HeightWin
307 //purpose  :
308 //=======================================================================
309 Standard_Integer Draw_Window::HeightWin() const
310 {
311   NSRect aViewBounds = [myView bounds];
312   return aViewBounds.size.height;
313 }
314
315 //=======================================================================
316 //function : WidthWin
317 //purpose  :
318 //=======================================================================
319 Standard_Integer Draw_Window::WidthWin() const
320 {
321   NSRect aViewBounds = [myView bounds];
322   return aViewBounds.size.width;
323 }
324
325 //=======================================================================
326 //function : SetTitle
327 //purpose  :
328 //=======================================================================
329 void Draw_Window::SetTitle (const TCollection_AsciiString& theTitle)
330 {
331   NSString* aTitleNs = [[NSString alloc] initWithUTF8String: theTitle.ToCString()];
332   [myWindow setTitle: aTitleNs];
333   [aTitleNs release];
334 }
335
336 //=======================================================================
337 //function : GetTitle
338 //purpose  :
339 //=======================================================================
340 TCollection_AsciiString Draw_Window::GetTitle() const
341 {
342   Standard_CString aTitle = [[myWindow title] UTF8String];
343   return TCollection_AsciiString (aTitle);
344 }
345
346 //=======================================================================
347 //function :DefineColor
348 //purpose  :
349 //=======================================================================
350 Standard_Boolean Draw_Window::DefineColor (const Standard_Integer&, Standard_CString)
351 {
352   return Standard_True; // unused
353 }
354
355 //=======================================================================
356 //function : IsMapped
357 //purpose  :
358 //=======================================================================
359 bool Draw_Window::IsMapped() const
360 {
361   if (Draw_VirtualWindows
362    || myWindow == NULL)
363   {
364     return false;
365   }
366
367   return [myWindow isVisible];
368 }
369
370 //=======================================================================
371 //function : DisplayWindow
372 //purpose  :
373 //=======================================================================
374 void Draw_Window::DisplayWindow()
375 {
376   if (Draw_VirtualWindows)
377   {
378     return;
379   }
380
381   if (myWindow != NULL)
382   {
383     [myWindow orderFront: NULL];
384   }
385 }
386
387 //=======================================================================
388 //function : Hide
389 //purpose  :
390 //=======================================================================
391 void Draw_Window::Hide()
392 {
393   if (myWindow != NULL)
394   {
395     [myWindow orderOut: NULL];
396   }
397 }
398
399 //=======================================================================
400 //function : Destroy
401 //purpose  :
402 //=======================================================================
403 void Draw_Window::Destroy()
404 {  
405   if (myWindow != NULL)
406   { 
407     [myWindow release];
408     myWindow = NULL;
409   }
410
411   if (myView != NULL)
412   {
413     [myView release];
414     myView = NULL;
415   }
416
417   if (myImageBuffer != NULL)
418   {
419     [myImageBuffer release];
420     myImageBuffer = NULL;
421   }
422 }
423
424 //=======================================================================
425 //function : Clear
426 //purpose  :
427 //=======================================================================
428 void Draw_Window::Clear()
429 {
430   [myImageBuffer lockFocus];
431   [[NSColor blackColor] set];
432   NSRect anImageBounds = NSMakeRect (0.0, 0.0, myImageBuffer.size.width, myImageBuffer.size.height);
433   NSRectFill (anImageBounds);
434   [myImageBuffer unlockFocus];
435
436   if (!myUseBuffer)
437   {
438     [myView redraw];
439   }
440 }
441
442 //=======================================================================
443 //function : Flush
444 //purpose  :
445 //=======================================================================
446 void Draw_Window::Flush()
447 {
448   //
449 }
450
451 //=======================================================================
452 //function : DrawString
453 //purpose  :
454 //=======================================================================
455 void Draw_Window::DrawString (const Standard_Integer& theXLeft, const Standard_Integer& theYTop, char* theText)
456 {
457   Cocoa_LocalPool aLocalPool;
458
459   NSString* aTextNs = [[[NSString alloc] initWithUTF8String: theText] autorelease];
460   NSColor*  aColor  = [NSColor colorWithDeviceRed: Draw_RGBColorsArray[myCurrentColor][0]
461                                             green: Draw_RGBColorsArray[myCurrentColor][1]
462                                              blue: Draw_RGBColorsArray[myCurrentColor][2]
463                                             alpha: 1.0f];
464   NSDictionary* anAttributes = [[[NSDictionary alloc] initWithObjectsAndKeys: aColor, NSForegroundColorAttributeName, nil] autorelease];
465
466   [myImageBuffer lockFocus];
467   [aTextNs drawAtPoint: NSMakePoint (theXLeft, myImageBuffer.size.height - theYTop) withAttributes: anAttributes];
468   [myImageBuffer unlockFocus];
469
470   if (!myUseBuffer)
471   {
472     [myView redraw];
473   }
474 }
475
476 //=======================================================================
477 //function : DrawSegments
478 //purpose  :
479 //=======================================================================
480 void Draw_Window::DrawSegments (Segment *theSegment, const Standard_Integer& theNumberOfElements)
481 {
482   Cocoa_LocalPool aLocalPool;
483
484   NSBezierPath* aPath = [[[NSBezierPath alloc] init] autorelease];
485
486   NSImage* anImage;
487   Standard_Integer anIter = 0;
488   
489   if (Draw_IsInZoomingMode)
490   {
491     // workaround for rectangle drawing when zooming
492     anImage = [[myImageBuffer copy] autorelease];
493     anIter  = 4;
494   }
495   else
496   {
497     anImage = myImageBuffer;
498   }
499
500
501   for (; anIter < theNumberOfElements; anIter++)
502   {
503     NSPoint aPoint = NSMakePoint (theSegment[anIter].myXStart, myImageBuffer.size.height - theSegment[anIter].myYStart);
504     [aPath moveToPoint: aPoint];
505     aPoint = NSMakePoint (theSegment[anIter].myXEnd, myImageBuffer.size.height - theSegment[anIter].myYEnd);
506     [aPath lineToPoint: aPoint];
507   }
508
509   [anImage lockFocus];
510   NSColor* aColor = [NSColor colorWithDeviceRed: Draw_RGBColorsArray[myCurrentColor][0]
511                                           green: Draw_RGBColorsArray[myCurrentColor][1]
512                                            blue: Draw_RGBColorsArray[myCurrentColor][2]
513                                           alpha: 1.0f];
514   [aColor set];
515   [aPath stroke];
516   [anImage unlockFocus];
517
518   if (!myUseBuffer)
519   {
520     [myView setImage: anImage];
521     [myView redraw];
522   }
523   
524   Draw_IsInZoomingMode = Standard_False;
525 }
526
527 //=======================================================================
528 //function : Redraw
529 //purpose  :
530 //=======================================================================
531 void Draw_Window::Redraw()
532 {
533   if (myUseBuffer)
534   {
535     [myView redraw];
536   }
537 }
538
539 //=======================================================================
540 //function : SetColor
541 //purpose  :
542 //=======================================================================
543 void Draw_Window::SetColor (const Standard_Integer& theColor)
544 {
545   myCurrentColor = theColor;
546 }
547
548 //=======================================================================
549 //function : SetMode
550 //purpose  :
551 //=======================================================================
552 void Draw_Window::SetMode (const Standard_Integer& theMode)
553 {
554   // unsupported
555   (void )theMode;
556 }
557
558 //=======================================================================
559 //function : Save
560 //purpose  :
561 //=======================================================================
562 Standard_Boolean Draw_Window::Save (Standard_CString theFileName) const
563 {
564   Cocoa_LocalPool aLocalPool;
565
566   NSString* aFileName = [[[NSString alloc] initWithUTF8String: theFileName] autorelease];
567   NSString* aFileExtension = [[aFileName pathExtension] lowercaseString];
568
569   NSDictionary* aFileTypeDict = [NSDictionary dictionaryWithObjectsAndKeys:
570                                   [NSNumber numberWithInt: NSBitmapImageFileTypePNG],  @"png",
571                                   [NSNumber numberWithInt: NSBitmapImageFileTypeBMP],  @"bmp",
572                                   [NSNumber numberWithInt: NSBitmapImageFileTypeJPEG], @"jpg",
573                                   [NSNumber numberWithInt: NSBitmapImageFileTypeGIF],  @"gif",
574                                   nil];
575   if ([aFileTypeDict valueForKey: aFileExtension] == NULL)
576   {
577     return Standard_False; // unsupported image extension
578   }
579
580   NSBitmapImageFileType aFileType = (NSBitmapImageFileType )[[aFileTypeDict valueForKey: aFileExtension] intValue];
581   NSBitmapImageRep* anImageRep = [NSBitmapImageRep imageRepWithData: [myImageBuffer TIFFRepresentation]];
582
583   NSDictionary* anImgProps = [NSDictionary dictionaryWithObject: [NSNumber numberWithFloat: 0.8]
584                                                          forKey: NSImageCompressionFactor];
585
586   NSData* aData = [anImageRep representationUsingType: aFileType 
587                                            properties: anImgProps];
588
589   Standard_Boolean isSuccess = [aData writeToFile: aFileName
590                                        atomically: NO];
591
592   return isSuccess;
593 }
594
595 Standard_Boolean Draw_Window::IsEqualWindows (const Standard_Integer& theWindowNumber)
596 {
597   return ([myWindow windowNumber] == theWindowNumber);
598 }
599
600 void GetNextEvent (Standard_Boolean  theWait,
601                    Standard_Integer& theWindowNumber,
602                    Standard_Integer& theX,
603                    Standard_Integer& theY,
604                    Standard_Integer& theButton)
605 {
606   Cocoa_LocalPool aLocalPool;
607
608   unsigned int anEventMatchMask = NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown;
609
610   if (!theWait)
611   {
612     anEventMatchMask = anEventMatchMask | NSEventMaskMouseMoved | NSEventMaskLeftMouseDragged;
613     Draw_IsInZoomingMode = Standard_True;
614   }
615
616   NSEvent* anEvent = [NSApp nextEventMatchingMask: anEventMatchMask
617                                         untilDate: [NSDate distantFuture]
618                                            inMode: NSEventTrackingRunLoopMode
619                                           dequeue: YES];
620
621   NSWindow* aWindow = [anEvent window];
622   NSView*   aView   = [aWindow contentView];
623   theWindowNumber   = [aWindow windowNumber];
624
625   NSPoint aMouseLoc = [aView convertPoint: [anEvent locationInWindow] fromView: nil];
626
627   theX = Standard_Integer (aMouseLoc.x);
628   theY = Standard_Integer (aMouseLoc.y);
629
630   NSEventType anEventType = [anEvent type];
631
632   if (anEventType == NSEventTypeLeftMouseDown)
633   {
634     theButton = 1;
635   }
636   else if (anEventType == NSEventTypeRightMouseDown)
637   {
638     theButton = 3;
639   }
640   else if ((anEventType == NSEventTypeMouseMoved || anEventType == NSEventTypeLeftMouseDragged) && !theWait)
641   {
642     theButton = 0;
643   }
644 }
645 #endif // __APPLE__