0029528: Visualization, TKOpenGl - allow defining sRGB textures
[occt.git] / src / Cocoa / Cocoa_Window.mm
CommitLineData
6aca4d39 1// Created on: 2012-11-12
4fe56619 2// Created by: Kirill GAVRILOV
6aca4d39 3// Copyright (c) 2012-2014 OPEN CASCADE SAS
4fe56619 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
4fe56619 6//
d5f74e42 7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
4fe56619 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
4fe56619 15
a2e4f780 16#import <TargetConditionals.h>
17
18#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
19 #import <UIKit/UIKit.h>
20#else
21 #import <Cocoa/Cocoa.h>
22#endif
4fe56619 23
24#include <Cocoa_Window.hxx>
25
26#include <Cocoa_LocalPool.hxx>
27
28#include <Image_AlienPixMap.hxx>
29#include <Aspect_Convert.hxx>
4fe56619 30#include <Aspect_WindowDefinitionError.hxx>
31
f5f4ebd0 32IMPLEMENT_STANDARD_RTTIEXT(Cocoa_Window,Aspect_Window)
33
a2e4f780 34#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
35 //
36#else
e2b4dea2 37
38#if !defined(MAC_OS_X_VERSION_10_12) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12)
39 // replacements for macOS versions before 10.12
40 #define NSWindowStyleMaskResizable NSResizableWindowMask
41 #define NSWindowStyleMaskClosable NSClosableWindowMask
42 #define NSWindowStyleMaskTitled NSTitledWindowMask
43#endif
44
4fe56619 45static Standard_Integer getScreenBottom()
46{
47 Cocoa_LocalPool aLocalPool;
48 NSArray* aScreens = [NSScreen screens];
49 if (aScreens == NULL || [aScreens count] == 0)
50 {
51 return 0;
52 }
53
54 NSScreen* aScreen = (NSScreen* )[aScreens objectAtIndex: 0];
55 NSDictionary* aDict = [aScreen deviceDescription];
56 NSNumber* aNumber = [aDict objectForKey: @"NSScreenNumber"];
57 if (aNumber == NULL
58 || [aNumber isKindOfClass: [NSNumber class]] == NO)
59 {
60 return 0;
61 }
62
63 CGDirectDisplayID aDispId = [aNumber unsignedIntValue];
64 CGRect aRect = CGDisplayBounds(aDispId);
65 return Standard_Integer(aRect.origin.y + aRect.size.height);
66}
a2e4f780 67#endif
4fe56619 68
8693dfd0 69//! Extension for Cocoa_Window::InvalidateContent().
70#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
71 @interface UIView (UIViewOcctAdditions)
72 - (void )invalidateContentOcct: (id )theSender;
73 @end
74 @implementation UIView (UIViewOcctAdditions)
75 - (void )invalidateContentOcct: (id )theSender
76 {
77 (void )theSender;
78 [self setNeedsDisplay];
79 }
80 @end
81#else
82 @interface NSView (NSViewOcctAdditions)
83 - (void )invalidateContentOcct: (id )theSender;
84 @end
85 @implementation NSView (NSViewOcctAdditions)
86 - (void )invalidateContentOcct: (id )theSender
87 {
88 (void )theSender;
89 [self setNeedsDisplay: YES];
90 }
91 @end
92#endif
93
4fe56619 94// =======================================================================
95// function : Cocoa_Window
96// purpose :
97// =======================================================================
98Cocoa_Window::Cocoa_Window (const Standard_CString theTitle,
99 const Standard_Integer thePxLeft,
100 const Standard_Integer thePxTop,
101 const Standard_Integer thePxWidth,
102 const Standard_Integer thePxHeight)
dc3fe572 103: Aspect_Window (),
a2e4f780 104#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
4fe56619 105 myHWindow (NULL),
a2e4f780 106#endif
4fe56619 107 myHView (NULL),
108 myXLeft (thePxLeft),
109 myYTop (thePxTop),
110 myXRight (thePxLeft + thePxWidth),
111 myYBottom (thePxTop + thePxHeight)
112{
a2e4f780 113#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
114 //
115#else
4fe56619 116 if (thePxWidth <= 0 || thePxHeight <= 0)
117 {
9775fa61 118 throw Aspect_WindowDefinitionError("Coordinate(s) out of range");
4fe56619 119 }
120 else if (NSApp == NULL)
121 {
9775fa61 122 throw Aspect_WindowDefinitionError("Cocoa application should be instantiated before window");
4fe56619 123 return;
124 }
125
126 // convert top-bottom coordinates to bottom-top (Cocoa)
127 myYTop = getScreenBottom() - myYBottom;
128 myYBottom = myYTop + thePxHeight;
129
130 Cocoa_LocalPool aLocalPool;
e2b4dea2 131 NSUInteger aWinStyle = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable;
4fe56619 132 NSRect aRectNs = NSMakeRect (float(myXLeft), float(myYTop), float(thePxWidth), float(thePxHeight));
133 myHWindow = [[NSWindow alloc] initWithContentRect: aRectNs
134 styleMask: aWinStyle
135 backing: NSBackingStoreBuffered
136 defer: NO];
137 if (myHWindow == NULL)
138 {
9775fa61 139 throw Aspect_WindowDefinitionError("Unable to create window");
4fe56619 140 }
ba00aab7 141 // for the moment, OpenGL renderer is expected to output sRGB colorspace
142 [myHWindow setColorSpace: [NSColorSpace sRGBColorSpace]];
4fe56619 143 myHView = [[myHWindow contentView] retain];
144
145 NSString* aTitleNs = [[NSString alloc] initWithUTF8String: theTitle];
146 [myHWindow setTitle: aTitleNs];
147 [aTitleNs release];
148
149 // do not destroy NSWindow on close - we didn't handle it!
150 [myHWindow setReleasedWhenClosed: NO];
a2e4f780 151#endif
4fe56619 152}
153
154// =======================================================================
155// function : Cocoa_Window
156// purpose :
157// =======================================================================
a2e4f780 158#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
159Cocoa_Window::Cocoa_Window (UIView* theViewNS)
160: Aspect_Window(),
161#else
4fe56619 162Cocoa_Window::Cocoa_Window (NSView* theViewNS)
a2e4f780 163: Aspect_Window(),
4fe56619 164 myHWindow (NULL),
a2e4f780 165#endif
166 myHView (NULL),
4fe56619 167 myXLeft (0),
168 myYTop (0),
169 myXRight (512),
170 myYBottom (512)
171{
a2e4f780 172#if defined(HAVE_OBJC_ARC)
173 myHView = theViewNS;
174#else
175 myHView = [theViewNS retain];
176#endif
4fe56619 177 DoResize();
178}
179
180// =======================================================================
e6f550da 181// function : ~Cocoa_Window
4fe56619 182// purpose :
183// =======================================================================
e6f550da 184Cocoa_Window::~Cocoa_Window()
4fe56619 185{
a2e4f780 186#if !defined(HAVE_OBJC_ARC)
4fe56619 187 Cocoa_LocalPool aLocalPool;
a2e4f780 188#endif
189#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
4fe56619 190 if (myHWindow != NULL)
191 {
a2e4f780 192 #if !defined(HAVE_OBJC_ARC)
4fe56619 193 //[myHWindow close];
194 [myHWindow release];
a2e4f780 195 #endif
4fe56619 196 myHWindow = NULL;
197 }
a2e4f780 198#endif
4fe56619 199 if (myHView != NULL)
200 {
a2e4f780 201 #if !defined(HAVE_OBJC_ARC)
4fe56619 202 [myHView release];
a2e4f780 203 #endif
4fe56619 204 myHView = NULL;
205 }
206}
207
4fe56619 208// =======================================================================
209// function : SetHView
210// purpose :
211// =======================================================================
a2e4f780 212#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
213void Cocoa_Window::SetHView (UIView* theView)
214{
215#else
4fe56619 216void Cocoa_Window::SetHView (NSView* theView)
217{
218 if (myHWindow != NULL)
219 {
220 [myHWindow setContentView: theView];
221 }
a2e4f780 222#endif
223
224#if defined(HAVE_OBJC_ARC)
225 myHView = theView;
226#else
4fe56619 227 if (myHView != NULL)
228 {
229 [myHView release];
230 myHView = NULL;
231 }
232 myHView = [theView retain];
a2e4f780 233#endif
4fe56619 234}
235
4fe56619 236// =======================================================================
237// function : IsMapped
238// purpose :
239// =======================================================================
240Standard_Boolean Cocoa_Window::IsMapped() const
241{
242 if (IsVirtual())
243 {
244 return Standard_True;
245 }
246
a2e4f780 247#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
248 return myHView != NULL;
249#else
250 return myHView != NULL
251 && [[myHView window] isVisible];
252#endif
4fe56619 253}
254
255// =======================================================================
256// function : Map
257// purpose :
258// =======================================================================
259void Cocoa_Window::Map() const
260{
261 if (IsVirtual())
262 {
263 return;
264 }
265
266 if (myHView != NULL)
267 {
a2e4f780 268 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
269 //
270 #else
4fe56619 271 [[myHView window] orderFront: NULL];
a2e4f780 272 #endif
4fe56619 273 }
274}
275
276// =======================================================================
277// function : Unmap
278// purpose :
279// =======================================================================
280void Cocoa_Window::Unmap() const
281{
282 if (myHView != NULL)
283 {
a2e4f780 284 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
285 //
286 #else
4fe56619 287 [[myHView window] orderOut: NULL];
a2e4f780 288 #endif
4fe56619 289 }
290}
291
292// =======================================================================
293// function : DoResize
294// purpose :
295// =======================================================================
296Aspect_TypeOfResize Cocoa_Window::DoResize() const
297{
298 if (myHView == NULL)
299 {
300 return Aspect_TOR_UNKNOWN;
301 }
302
a2e4f780 303#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
304 CGRect aBounds = [myHView bounds];
305#else
4fe56619 306 NSRect aBounds = [myHView bounds];
a2e4f780 307#endif
4fe56619 308 Standard_Integer aMask = 0;
309 Aspect_TypeOfResize aMode = Aspect_TOR_UNKNOWN;
310
311 if (Abs ((Standard_Integer )aBounds.origin.x - myXLeft ) > 2) aMask |= 1;
312 if (Abs ((Standard_Integer )(aBounds.origin.x + aBounds.size.width) - myXRight ) > 2) aMask |= 2;
313 if (Abs ((Standard_Integer )aBounds.origin.y - myYTop ) > 2) aMask |= 4;
314 if (Abs ((Standard_Integer )(aBounds.origin.y + aBounds.size.height) - myYBottom) > 2) aMask |= 8;
315 switch (aMask)
316 {
317 case 0: aMode = Aspect_TOR_NO_BORDER; break;
318 case 1: aMode = Aspect_TOR_LEFT_BORDER; break;
319 case 2: aMode = Aspect_TOR_RIGHT_BORDER; break;
320 case 4: aMode = Aspect_TOR_TOP_BORDER; break;
321 case 5: aMode = Aspect_TOR_LEFT_AND_TOP_BORDER; break;
322 case 6: aMode = Aspect_TOR_TOP_AND_RIGHT_BORDER; break;
323 case 8: aMode = Aspect_TOR_BOTTOM_BORDER; break;
324 case 9: aMode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER; break;
325 case 10: aMode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER; break;
326 default: break;
327 }
328
329 *((Standard_Integer* )&myXLeft ) = (Standard_Integer )aBounds.origin.x;
330 *((Standard_Integer* )&myXRight ) = (Standard_Integer )(aBounds.origin.x + aBounds.size.width);
331 *((Standard_Integer* )&myYTop ) = (Standard_Integer )aBounds.origin.y;
332 *((Standard_Integer* )&myYBottom ) = (Standard_Integer )(aBounds.origin.y + aBounds.size.height);
333 return aMode;
334}
335
336// =======================================================================
337// function : DoMapping
338// purpose :
339// =======================================================================
340Standard_Boolean Cocoa_Window::DoMapping() const
341{
342 return Standard_True;
343}
344
4fe56619 345// =======================================================================
346// function : Ratio
347// purpose :
348// =======================================================================
ee2be2a8 349Standard_Real Cocoa_Window::Ratio() const
4fe56619 350{
351 if (myHView == NULL)
352 {
353 return 1.0;
354 }
355
a2e4f780 356#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
357 CGRect aBounds = [myHView bounds];
358#else
4fe56619 359 NSRect aBounds = [myHView bounds];
a2e4f780 360#endif
ee2be2a8 361 return Standard_Real (aBounds.size.width / aBounds.size.height);
4fe56619 362}
363
4fe56619 364// =======================================================================
365// function : Position
366// purpose :
367// =======================================================================
368void Cocoa_Window::Position (Standard_Integer& X1, Standard_Integer& Y1,
369 Standard_Integer& X2, Standard_Integer& Y2) const
370{
a2e4f780 371#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
372 CGRect aBounds = [myHView bounds];
373 X1 = 0;
374 Y1 = 0;
375 X2 = (Standard_Integer )aBounds.size.width;
376 Y2 = (Standard_Integer )aBounds.size.height;
377#else
18d715bd 378 NSWindow* aWindow = [myHView window];
379 NSRect aWindowRect = [aWindow frame];
380 X1 = (Standard_Integer) aWindowRect.origin.x;
381 Y1 = getScreenBottom() - (Standard_Integer) aWindowRect.origin.y - (Standard_Integer) aWindowRect.size.height;
382 X2 = X1 + (Standard_Integer) aWindowRect.size.width;
383 Y2 = Y1 + (Standard_Integer) aWindowRect.size.height;
a2e4f780 384#endif
4fe56619 385}
386
4fe56619 387// =======================================================================
388// function : Size
389// purpose :
390// =======================================================================
391void Cocoa_Window::Size (Standard_Integer& theWidth,
392 Standard_Integer& theHeight) const
393{
394 if (myHView == NULL)
395 {
396 return;
397 }
398
a2e4f780 399#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
400 CGRect aBounds = [myHView bounds];
401#else
4fe56619 402 NSRect aBounds = [myHView bounds];
a2e4f780 403#endif
4fe56619 404 theWidth = (Standard_Integer )aBounds.size.width;
405 theHeight = (Standard_Integer )aBounds.size.height;
406}
8693dfd0 407
49582f9d 408// =======================================================================
409// function : SetTitle
410// purpose :
411// =======================================================================
412void Cocoa_Window::SetTitle (const TCollection_AsciiString& theTitle)
413{
414 if (myHView == NULL)
415 {
416 return;
417 }
418
419#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
420 (void )theTitle;
421#else
422 NSWindow* aWindow = [myHView window];
423 NSString* aTitleNS = [[NSString alloc] initWithUTF8String: theTitle.ToCString()];
424 [aWindow setTitle: aTitleNS];
425 [aTitleNS release];
426#endif
427}
428
8693dfd0 429// =======================================================================
430// function : InvalidateContent
431// purpose :
432// =======================================================================
433void Cocoa_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& )
434{
435 if (myHView == NULL)
436 {
437 return;
438 }
439
440 if ([NSThread isMainThread])
441 {
442 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
443 [myHView setNeedsDisplay];
444 #else
445 [myHView setNeedsDisplay: YES];
446 #endif
447 }
448 else
449 {
450 [myHView performSelectorOnMainThread: @selector(invalidateContentOcct:)
451 withObject: NULL
452 waitUntilDone: NO];
453 }
454}
49582f9d 455
456// =======================================================================
457// function : VirtualKeyFromNative
458// purpose :
459// =======================================================================
460Aspect_VKey Cocoa_Window::VirtualKeyFromNative (Standard_Integer theKey)
461{
462 switch (theKey)
463 {
464 case 0x00: return Aspect_VKey_A;
465 case 0x01: return Aspect_VKey_S;
466 case 0x02: return Aspect_VKey_D;
467 case 0x03: return Aspect_VKey_F;
468 case 0x04: return Aspect_VKey_H;
469 case 0x05: return Aspect_VKey_G;
470 case 0x06: return Aspect_VKey_Z;
471 case 0x07: return Aspect_VKey_X;
472 case 0x08: return Aspect_VKey_C;
473 case 0x09: return Aspect_VKey_V;
474 case 0x0A: return Aspect_VKey_UNKNOWN;
475 case 0x0B: return Aspect_VKey_B;
476 case 0x0C: return Aspect_VKey_Q;
477 case 0x0D: return Aspect_VKey_W;
478 case 0x0E: return Aspect_VKey_E;
479 case 0x0F: return Aspect_VKey_R;
480 case 0x10: return Aspect_VKey_Y;
481 case 0x11: return Aspect_VKey_T;
482 case 0x12: return Aspect_VKey_1;
483 case 0x13: return Aspect_VKey_2;
484 case 0x14: return Aspect_VKey_3;
485 case 0x15: return Aspect_VKey_4;
486 case 0x16: return Aspect_VKey_6;
487 case 0x17: return Aspect_VKey_5;
488 case 0x18: return Aspect_VKey_Plus;
489 case 0x19: return Aspect_VKey_9;
490 case 0x1A: return Aspect_VKey_7;
491 case 0x1B: return Aspect_VKey_Minus;
492 case 0x1C: return Aspect_VKey_8;
493 case 0x1D: return Aspect_VKey_0;
494 case 0x1E: return Aspect_VKey_BracketRight;
495 case 0x1F: return Aspect_VKey_O;
496 case 0x20: return Aspect_VKey_U;
497 case 0x21: return Aspect_VKey_BracketLeft;
498 case 0x22: return Aspect_VKey_I;
499 case 0x23: return Aspect_VKey_P;
500 case 0x24: return Aspect_VKey_Enter;
501 case 0x25: return Aspect_VKey_L;
502 case 0x26: return Aspect_VKey_J;
503 case 0x27: return Aspect_VKey_Apostrophe;
504 case 0x28: return Aspect_VKey_K;
505 case 0x29: return Aspect_VKey_Semicolon;
506 case 0x2A: return Aspect_VKey_Backslash;
507 case 0x2B: return Aspect_VKey_Comma; // 43, ',<'
508 case 0x2C: return Aspect_VKey_Slash; //ST_VK_OEM_2, // 44, '?/'
509 case 0x2D: return Aspect_VKey_N;
510 case 0x2E: return Aspect_VKey_M;
511 case 0x2F: return Aspect_VKey_Period; // 47, '.>'
512 case 0x30: return Aspect_VKey_Tab;
513 case 0x31: return Aspect_VKey_Space;
514 case 0x32: return Aspect_VKey_Tilde; // '~`'
515 case 0x33: return Aspect_VKey_Backspace;
516 case 0x34: return Aspect_VKey_UNKNOWN;
517 case 0x35: return Aspect_VKey_Escape;
518 case 0x36: return Aspect_VKey_UNKNOWN; // Aspect_VKey_Cmd, right Command
519 case 0x37: return Aspect_VKey_UNKNOWN; // Aspect_VKey_Cmd, left Command
520 case 0x38: return Aspect_VKey_Shift; // left shift
521 case 0x39: return Aspect_VKey_UNKNOWN;
522 case 0x3A: return Aspect_VKey_Alt; // left alt/option
523 case 0x3B: return Aspect_VKey_Control;
524 case 0x3C: return Aspect_VKey_Shift; // right shift
525 case 0x3D: return Aspect_VKey_Alt; // right alt/option
526 case 0x3E: return Aspect_VKey_UNKNOWN;
527 case 0x3F: return Aspect_VKey_UNKNOWN; // Aspect_VKey_Func, fn
528 case 0x40:
529 case 0x41:
530 case 0x42:
531 case 0x43:
532 case 0x44:
533 case 0x45:
534 case 0x46:
535 case 0x47:
536 case 0x48:
537 case 0x49:
538 case 0x4A:
539 case 0x4B: return Aspect_VKey_UNKNOWN;
540 case 0x4C: return Aspect_VKey_Enter; // fn + return
541 case 0x4D:
542 case 0x4E:
543 case 0x4F:
544 case 0x50:
545 case 0x51:
546 case 0x52:
547 case 0x53:
548 case 0x54:
549 case 0x55:
550 case 0x56:
551 case 0x57:
552 case 0x58:
553 case 0x59:
554 case 0x5A:
555 case 0x5B:
556 case 0x5C:
557 case 0x5D:
558 case 0x5E:
559 case 0x5F: return Aspect_VKey_UNKNOWN;
560 case 0x60: return Aspect_VKey_F5;
561 case 0x61: return Aspect_VKey_F6;
562 case 0x62: return Aspect_VKey_F7;
563 case 0x63: return Aspect_VKey_F3;
564 case 0x64: return Aspect_VKey_F8;
565 case 0x65: return Aspect_VKey_F9;
566 //case 0x66: return Aspect_VKey_UNKNOWN;
567 case 0x67: return Aspect_VKey_F11;
568 //case 0x68: return Aspect_VKey_UNKNOWN;
569 //case 0x69: return Aspect_VKey_UNKNOWN;
570 //case 0x6A: return Aspect_VKey_UNKNOWN;
571 //case 0x6B: return Aspect_VKey_UNKNOWN;
572 //case 0x6C: return Aspect_VKey_UNKNOWN;
573 case 0x6D: return Aspect_VKey_F10;
574 //case 0x6E: return Aspect_VKey_UNKNOWN;
575 case 0x6F: return Aspect_VKey_F12;
576 //case 0x70: return Aspect_VKey_UNKNOWN;
577 //case 0x71: return Aspect_VKey_UNKNOWN;
578 //case 0x72: return Aspect_VKey_UNKNOWN;
579 case 0x73: return Aspect_VKey_Home;
580 case 0x74: return Aspect_VKey_PageUp;
581 case 0x75: return Aspect_VKey_Delete;
582 case 0x76: return Aspect_VKey_F4;
583 case 0x77: return Aspect_VKey_End;
584 case 0x78: return Aspect_VKey_F2;
585 case 0x79: return Aspect_VKey_PageDown;
586 case 0x7A: return Aspect_VKey_F1;
587 case 0x7B: return Aspect_VKey_Left;
588 case 0x7C: return Aspect_VKey_Right;
589 case 0x7D: return Aspect_VKey_Down;
590 case 0x7E: return Aspect_VKey_Up;
591 case 0x7F: return Aspect_VKey_UNKNOWN;
592 }
593 return Aspect_VKey_UNKNOWN;
594}