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