1/* 2Copyright (c) 2003-2017 Sony Pictures Imageworks Inc., et al. 3All Rights Reserved. 4 5Redistribution and use in source and binary forms, with or without 6modification, are permitted provided that the following conditions are 7met: 8* Redistributions of source code must retain the above copyright 9 notice, this list of conditions and the following disclaimer. 10* Redistributions in binary form must reproduce the above copyright 11 notice, this list of conditions and the following disclaimer in the 12 documentation and/or other materials provided with the distribution. 13* Neither the name of Sony Pictures Imageworks nor the names of its 14 contributors may be used to endorse or promote products derived from 15 this software without specific prior written permission. 16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27*/ 28 29#import "OpenColorIO_PS_Dialog_Controller.h" 30 31#import "OpenColorIO_AE_MonitorProfileChooser_Controller.h" 32 33#include <fstream> 34#include <map> 35#include <cstdlib> 36 37#include "OpenColorIO_PS_Context.h" 38 39#include "OpenColorIO_AE_Dialogs.h" 40 41#include "ocioicc.h" 42 43 44 45static NSString *standardPath = @"/Library/Application Support/OpenColorIO"; 46 47 48@implementation OpenColorIO_PS_Dialog_Controller 49 50- (NSString *)pathForStandardConfig:(NSString *)config 51{ 52 return [[standardPath stringByAppendingPathComponent:config] stringByAppendingPathComponent:@"config.ocio"]; 53} 54 55- (id)initWithSource:(ControllerSource)initSource 56 configuration:(NSString *)initConfiguration 57 action:(ControllerAction)initAction 58 invert:(BOOL)initInvert 59 interpolation:(ControllerInterp)initInterpolation 60 inputSpace:(NSString *)initInputSpace 61 outputSpace:(NSString *)initOutputSpace 62 device:(NSString *)initDevice 63 transform:(NSString *)initTransform 64{ 65 self = [super init]; 66 67 if(self) 68 { 69 if(!([NSBundle loadNibNamed:@"OpenColorIO_PS_Dialog" owner:self])) 70 return nil; 71 72 source = initSource; 73 74 if(source == CSOURCE_CUSTOM) 75 { 76 customPath = [initConfiguration retain]; 77 } 78 else if(source == CSOURCE_STANDARD) 79 { 80 configuration = [initConfiguration retain]; 81 } 82 83 action = initAction; 84 inputSpace = [initInputSpace retain]; 85 outputSpace = [initOutputSpace retain]; 86 device = [initDevice retain]; 87 transform = [initTransform retain]; 88 interpolation = initInterpolation; 89 invert = initInvert; 90 91 92 // configuration menu 93 [configurationMenu removeAllItems]; 94 95 [configurationMenu setAutoenablesItems:NO]; 96 97 [configurationMenu addItemWithTitle:@"$OCIO"]; 98 99 [[configurationMenu lastItem] setTag:CSOURCE_ENVIRONMENT]; 100 101 char *envFile = std::getenv("OCIO"); 102 103 if(envFile == NULL || strlen(envFile) == 0) 104 [[configurationMenu lastItem] setEnabled:FALSE]; 105 106 107 [[configurationMenu menu] addItem:[NSMenuItem separatorItem]]; 108 109 110 NSArray *standardConfigs = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:standardPath error:NULL]; 111 112 if([standardConfigs count] > 0) 113 { 114 for(NSString *configName in standardConfigs) 115 { 116 NSAssert([configName isKindOfClass:[NSString class]], @"expected NSString"); 117 118 NSString *configFilePath = [self pathForStandardConfig:configName]; 119 120 if([[NSFileManager defaultManager] isReadableFileAtPath:configFilePath]) 121 { 122 [configurationMenu addItemWithTitle:configName]; 123 124 [[configurationMenu lastItem] setTag:CSOURCE_STANDARD]; 125 } 126 } 127 } 128 else 129 { 130 NSString *noConfigsMessage = [NSString stringWithFormat:@"No configs in %@", standardPath]; 131 132 [configurationMenu addItemWithTitle:noConfigsMessage]; 133 134 [[configurationMenu lastItem] setTag:CSOURCE_STANDARD]; 135 [[configurationMenu lastItem] setEnabled:FALSE]; 136 } 137 138 139 [[configurationMenu menu] addItem:[NSMenuItem separatorItem]]; 140 141 142 [configurationMenu addItemWithTitle:@"Custom…"]; 143 144 [[configurationMenu lastItem] setTag:CSOURCE_CUSTOM]; 145 146 147 [invertCheck setHidden:YES]; 148 149 [menu1 removeAllItems]; 150 [menu2 removeAllItems]; 151 [menu3 removeAllItems]; 152 153 [label3 setHidden:YES]; 154 [menu3 setHidden:YES]; 155 156 157 [self trackConfigMenu:nil]; 158 } 159 160 return self; 161} 162 163- (void)dealloc 164{ 165 OpenColorIO_PS_Context *context = (OpenColorIO_PS_Context *)contextPtr; 166 167 delete context; 168 169 [configuration release]; 170 [customPath release]; 171 [inputSpace release]; 172 [outputSpace release]; 173 [device release]; 174 [transform release]; 175 176 [super dealloc]; 177} 178 179- (IBAction)clickedOK:(id)sender 180{ 181 [NSApp stopModal]; 182} 183 184- (IBAction)clickedCancel:(id)sender 185{ 186 [NSApp abortModal]; 187} 188 189/* 190- (void)profileChooserDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo 191{ 192 NSAssert(profileController != nil, @"profileController is nil"); 193 194 195 [sheet orderOut:self]; 196 197 198 if(returnCode == NSRunStoppedResponse) 199 { 200 NSString *path = (NSString *)contextInfo; 201 202 NSAssert([path isKindOfClass:[NSString class]], @"expected NSString"); 203 204 try 205 { 206 OpenColorIO_PS_Context *context = (OpenColorIO_PS_Context *)contextPtr; 207 208 NSAssert(context != NULL, @"context was NULL"); 209 210 211 char display_icc_path[256]; 212 213 const BOOL gotICC = [profileController getMonitorProfile:display_icc_path bufferSize:255]; 214 215 if(!gotICC) 216 throw OCIO::Exception("Failed to get ICC profile"); 217 218 219 OCIO::ConstProcessorRcPtr processor; 220 221 if(action == CACTION_CONVERT) 222 { 223 processor = context->getConvertProcessor([inputSpace UTF8String], [outputSpace UTF8String]); 224 } 225 else if(action == CACTION_DISPLAY) 226 { 227 processor = context->getDisplayProcessor([inputSpace UTF8String], [device UTF8String], [transform UTF8String]); 228 } 229 else 230 { 231 NSAssert(action == CACTION_LUT, @"expected CACTION_LUT"); 232 233 const OCIO::Interpolation interp = (interpolation == CINTERP_NEAREST ? OCIO::INTERP_NEAREST : 234 interpolation == CINTERP_LINEAR ? OCIO::INTERP_LINEAR : 235 interpolation == CINTERP_TETRAHEDRAL ? OCIO::INTERP_TETRAHEDRAL : 236 OCIO::INTERP_BEST); 237 238 const OCIO::TransformDirection direction = (invert ? OCIO::TRANSFORM_DIR_INVERSE : OCIO::TRANSFORM_DIR_FORWARD); 239 240 processor = context->getLUTProcessor(interp, direction); 241 } 242 243 244 int cubesize = 32; 245 int whitepointtemp = 6505; 246 std::string copyright = "OpenColorIO, Sony Imageworks"; 247 248 // create a description tag from the filename 249 std::string description = [[[path lastPathComponent] stringByDeletingPathExtension] UTF8String]; 250 251 SaveICCProfileToFile([path UTF8String], processor, cubesize, whitepointtemp, 252 display_icc_path, description, copyright, false); 253 } 254 catch(const std::exception &e) 255 { 256 NSBeep(); 257 258 NSString *ocioString = [NSString stringWithUTF8String:e.what()]; 259 260 NSAlert *alert = [NSAlert alertWithMessageText:@"OpenColorIO error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", ocioString]; 261 262 [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; 263 } 264 catch(...) 265 { 266 NSBeep(); 267 268 NSString *ocioString = @"Some unknown error"; 269 270 NSAlert *alert = [NSAlert alertWithMessageText:@"OpenColorIO error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", ocioString]; 271 272 [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; 273 } 274 275 [path release]; 276 } 277 278 279 [profileController release]; 280 281 profileController = nil; 282} 283*/ 284- (void)exportPanelDidEnd:(NSSavePanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo 285{ 286 if(returnCode == NSOKButton) 287 { 288 OpenColorIO_PS_Context *context = (OpenColorIO_PS_Context *)contextPtr; 289 290 NSAssert(context != NULL, @"context was NULL"); 291 292 293 NSString *path = [[panel URL] path]; 294 295 NSString *extension = [path pathExtension]; 296 297 if([extension isEqualToString:@"icc"]) 298 { 299 OpenColorIO_AE_MonitorProfileChooser_Controller *profileController = [[OpenColorIO_AE_MonitorProfileChooser_Controller alloc] init]; 300 301 // the sheet is still active, so can't run another one...will settle for modal 302 const NSInteger modal_result = [NSApp runModalForWindow:[profileController getWindow]]; 303 304 305 if(modal_result == NSRunStoppedResponse) 306 { 307 try 308 { 309 char display_icc_path[256]; 310 311 const BOOL gotICC = [profileController getMonitorProfile:display_icc_path bufferSize:255]; 312 313 if(!gotICC) 314 throw OCIO::Exception("Failed to get ICC profile"); 315 316 317 OCIO::ConstProcessorRcPtr processor; 318 319 if(action == CACTION_CONVERT) 320 { 321 processor = context->getConvertProcessor([inputSpace UTF8String], [outputSpace UTF8String]); 322 } 323 else if(action == CACTION_DISPLAY) 324 { 325 processor = context->getDisplayProcessor([inputSpace UTF8String], [device UTF8String], [transform UTF8String]); 326 } 327 else 328 { 329 NSAssert(action == CACTION_LUT, @"expected CACTION_LUT"); 330 331 const OCIO::Interpolation interp = (interpolation == CINTERP_NEAREST ? OCIO::INTERP_NEAREST : 332 interpolation == CINTERP_LINEAR ? OCIO::INTERP_LINEAR : 333 interpolation == CINTERP_TETRAHEDRAL ? OCIO::INTERP_TETRAHEDRAL : 334 OCIO::INTERP_BEST); 335 336 const OCIO::TransformDirection direction = (invert ? OCIO::TRANSFORM_DIR_INVERSE : OCIO::TRANSFORM_DIR_FORWARD); 337 338 processor = context->getLUTProcessor(interp, direction); 339 } 340 341 342 int cubesize = 32; 343 int whitepointtemp = 6505; 344 std::string copyright = "OpenColorIO, Sony Imageworks"; 345 346 // create a description tag from the filename 347 std::string description = [[[path lastPathComponent] stringByDeletingPathExtension] UTF8String]; 348 349 SaveICCProfileToFile([path UTF8String], processor, cubesize, whitepointtemp, 350 display_icc_path, description, copyright, false); 351 } 352 catch(const std::exception &e) 353 { 354 NSBeep(); 355 356 NSString *ocioString = [NSString stringWithUTF8String:e.what()]; 357 358 NSAlert *alert = [NSAlert alertWithMessageText:@"OpenColorIO error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", ocioString]; 359 360 [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; 361 } 362 catch(...) 363 { 364 NSBeep(); 365 366 NSString *ocioString = @"Some unknown error"; 367 368 NSAlert *alert = [NSAlert alertWithMessageText:@"OpenColorIO error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", ocioString]; 369 370 [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; 371 } 372 } 373 374 [[profileController getWindow] close]; 375 376 [profileController release]; 377 } 378 else 379 { 380 try 381 { 382 // need an extension->format map 383 std::map<std::string, std::string> extensions; 384 385 for(int i=0; i < OCIO::Baker::getNumFormats(); ++i) 386 { 387 const char *extension = OCIO::Baker::getFormatExtensionByIndex(i); 388 const char *format = OCIO::Baker::getFormatNameByIndex(i); 389 390 extensions[ extension ] = format; 391 } 392 393 const std::string the_extension = [extension UTF8String]; 394 395 std::string format = extensions[ the_extension ]; 396 397 398 OCIO::BakerRcPtr baker; 399 400 if(action == CACTION_CONVERT) 401 { 402 baker = context->getConvertBaker([inputSpace UTF8String], [outputSpace UTF8String]); 403 } 404 else if(action == CACTION_DISPLAY) 405 { 406 baker = context->getDisplayBaker([inputSpace UTF8String], [device UTF8String], [transform UTF8String]); 407 } 408 else 409 { 410 NSAssert(action == CACTION_LUT, @"expected CACTION_LUT"); 411 412 const OCIO::Interpolation interp = (interpolation == CINTERP_NEAREST ? OCIO::INTERP_NEAREST : 413 interpolation == CINTERP_LINEAR ? OCIO::INTERP_LINEAR : 414 interpolation == CINTERP_TETRAHEDRAL ? OCIO::INTERP_TETRAHEDRAL : 415 OCIO::INTERP_BEST); 416 417 const OCIO::TransformDirection direction = (invert ? OCIO::TRANSFORM_DIR_INVERSE : OCIO::TRANSFORM_DIR_FORWARD); 418 419 baker = context->getLUTBaker(interp, direction); 420 } 421 422 baker->setFormat( format.c_str() ); 423 424 std::ofstream f([path UTF8String]); 425 baker->bake(f); 426 } 427 catch(const std::exception &e) 428 { 429 NSBeep(); 430 431 NSString *ocioString = [NSString stringWithUTF8String:e.what()]; 432 433 NSAlert *alert = [NSAlert alertWithMessageText:@"OpenColorIO error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", ocioString]; 434 435 [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; 436 } 437 catch(...) 438 { 439 NSBeep(); 440 441 NSString *ocioString = @"Some unknown error"; 442 443 NSAlert *alert = [NSAlert alertWithMessageText:@"OpenColorIO error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", ocioString]; 444 445 [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; 446 } 447 } 448 } 449} 450 451- (IBAction)clickedExport:(id)sender 452{ 453 NSSavePanel *panel = [NSSavePanel savePanel]; 454 455 NSMutableString *message = [NSMutableString stringWithString:@"Formats: ICC Profile (.icc)"]; 456 457 NSMutableArray *extensionArray = [NSMutableArray arrayWithObject:@"icc"]; 458 459 for(int i=0; i < OCIO::Baker::getNumFormats(); ++i) 460 { 461 const char *extension = OCIO::Baker::getFormatExtensionByIndex(i); 462 const char *format = OCIO::Baker::getFormatNameByIndex(i); 463 464 [extensionArray addObject:[NSString stringWithUTF8String:extension]]; 465 466 [message appendFormat:@", %s (.%s)", format, extension]; 467 } 468 469 [panel setAllowedFileTypes:extensionArray]; 470 [panel setMessage:message]; 471 472 [panel beginSheetForDirectory:nil 473 file:nil 474 modalForWindow:window 475 modalDelegate:self 476 didEndSelector:@selector(exportPanelDidEnd:returnCode:contextInfo:) 477 contextInfo:NULL]; 478} 479 480- (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo 481{ 482 if(returnCode == NSOKButton) 483 { 484 source = CSOURCE_CUSTOM; 485 486 NSURL *url = [panel URL]; 487 488 [customPath release]; 489 490 customPath = [[url path] retain]; 491 } 492 493 [self trackConfigMenu:nil]; 494} 495 496- (IBAction)trackConfigMenu:(id)sender 497{ 498 const ControllerSource previousSource = source; 499 500 if(sender == nil) 501 { 502 // set menu from values 503 if(source == CSOURCE_STANDARD) 504 { 505 [configurationMenu selectItemWithTitle:configuration]; 506 } 507 else 508 { 509 [configurationMenu selectItemWithTag:source]; 510 } 511 } 512 else 513 { 514 // set value from menu 515 source = (ControllerSource)[[configurationMenu selectedItem] tag]; 516 } 517 518 519 NSString *configPath = nil; 520 521 if(source == CSOURCE_ENVIRONMENT) 522 { 523 char *envFile = std::getenv("OCIO"); 524 525 if(envFile != NULL && strlen(envFile) > 0) 526 { 527 configPath = [NSString stringWithUTF8String:envFile]; 528 } 529 } 530 else if(source == CSOURCE_CUSTOM) 531 { 532 if(sender != nil) 533 { 534 source = previousSource; // we'll re-set to the previous source in case dialog is canceled 535 536 // do file open dialog 537 NSOpenPanel *panel = [NSOpenPanel openPanel]; 538 539 [panel setCanChooseDirectories:NO]; 540 [panel setAllowsMultipleSelection:NO]; 541 542 NSMutableArray *extensions = [NSMutableArray arrayWithObject:@"ocio"]; 543 544 for(int i=0; i < OCIO::FileTransform::getNumFormats(); ++i) 545 { 546 const char *extension = OCIO::FileTransform::getFormatExtensionByIndex(i); 547 //const char *format = OCIO::FileTransform::getFormatNameByIndex(i); 548 549 NSString *extensionString = [NSString stringWithUTF8String:extension]; 550 551 if(![extensionString isEqualToString:@"ccc"]) // .ccc files require an ID parameter 552 [extensions addObject:[NSString stringWithUTF8String:extension]]; 553 } 554 555 556 NSMutableString *message = [NSMutableString stringWithString:@"Formats: "]; 557 558 for(int i=0; i < [extensions count]; i++) 559 { 560 NSString *extension = [extensions objectAtIndex:i]; 561 562 if(i != 0) 563 [message appendString:@", "]; 564 565 [message appendString:@"."]; 566 [message appendString:extension]; 567 } 568 569 [panel setMessage:message]; 570 [panel setAllowedFileTypes:extensions]; 571 572 [panel beginSheetForDirectory:nil 573 file:nil 574 modalForWindow:window 575 modalDelegate:self 576 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) 577 contextInfo:NULL]; 578 579 return; 580 } 581 else 582 { 583 configPath = customPath; 584 } 585 } 586 else 587 { 588 NSAssert(source == CSOURCE_STANDARD, @"expected TAG_STANDARD"); 589 590 [configuration release]; 591 592 configuration = [[configurationMenu titleOfSelectedItem] retain]; 593 594 configPath = [self pathForStandardConfig:configuration]; 595 } 596 597 598 if(configPath != nil && [[NSFileManager defaultManager] isReadableFileAtPath:configPath]) 599 { 600 try 601 { 602 OpenColorIO_PS_Context *oldContext = (OpenColorIO_PS_Context *)contextPtr; 603 604 delete oldContext; 605 606 607 OpenColorIO_PS_Context *context = new OpenColorIO_PS_Context([configPath UTF8String]); 608 609 contextPtr = context; 610 611 612 if( context->isLUT() ) 613 { 614 action = CACTION_LUT; 615 616 [invertCheck setHidden:NO]; 617 618 if( context->canInvertLUT() ) 619 { 620 [invertCheck setEnabled:YES]; 621 } 622 else 623 { 624 [invertCheck setEnabled:NO]; 625 626 invert = NO; 627 } 628 629 [invertCheck setState:(invert ? NSOnState : NSOffState)]; 630 631 [actionRadios setHidden:YES]; 632 633 634 NSTextField *interpolationLabel = label1; 635 NSPopUpButton *interpolationMenu = menu1; 636 637 [interpolationLabel setStringValue:@"Interpolation"]; 638 639 // interpolation menu 640 [interpolationMenu removeAllItems]; 641 642 [interpolationMenu addItemWithTitle:@"Nearest Neighbor"]; 643 [[interpolationMenu lastItem] setTag:CINTERP_NEAREST]; 644 645 [interpolationMenu addItemWithTitle:@"Linear"]; 646 [[interpolationMenu lastItem] setTag:CINTERP_LINEAR]; 647 648 [interpolationMenu addItemWithTitle:@"Tetrahedral"]; 649 [[interpolationMenu lastItem] setTag:CINTERP_TETRAHEDRAL]; 650 651 const bool canTetrahedral = !context->canInvertLUT(); 652 653 if(!canTetrahedral) 654 { 655 [interpolationMenu setAutoenablesItems:NO]; 656 657 [[interpolationMenu lastItem] setEnabled:NO]; 658 659 if(interpolation == CINTERP_TETRAHEDRAL) 660 interpolation = CINTERP_LINEAR; 661 } 662 663 [[interpolationMenu menu] addItem:[NSMenuItem separatorItem]]; 664 665 [interpolationMenu addItemWithTitle:@"Best"]; 666 [[interpolationMenu lastItem] setTag:CINTERP_BEST]; 667 668 [interpolationMenu selectItemWithTag:interpolation]; 669 670 [inputSpaceButton setHidden:YES]; 671 672 [label2 setHidden:YES]; 673 [menu2 setHidden:YES]; 674 [outputSpaceButton setHidden:YES]; 675 676 [label3 setHidden:YES]; 677 [menu3 setHidden:YES]; 678 } 679 else 680 { 681 [invertCheck setHidden:YES]; 682 683 if(action == CACTION_LUT) 684 { 685 action = CACTION_CONVERT; 686 } 687 688 [actionRadios setHidden:NO]; 689 690 691 const SpaceVec &colorSpaces = context->getColorSpaces(); 692 693 if(inputSpace == nil || -1 == FindSpace(colorSpaces, [inputSpace UTF8String])) 694 { 695 [inputSpace release]; 696 697 inputSpace = [[NSString alloc] initWithUTF8String:context->getDefaultColorSpace().c_str()]; 698 } 699 700 if(outputSpace == nil || -1 == FindSpace(colorSpaces, [outputSpace UTF8String])) 701 { 702 [outputSpace release]; 703 704 outputSpace = [[NSString alloc] initWithUTF8String:context->getDefaultColorSpace().c_str()]; 705 } 706 707 708 const SpaceVec &devices = context->getDevices(); 709 710 if(device == nil || -1 == FindSpace(devices, [device UTF8String])) 711 { 712 [device release]; 713 714 device = [[NSString alloc] initWithUTF8String:context->getDefaultDevice().c_str()]; 715 } 716 717 718 const SpaceVec transforms = context->getTransforms([device UTF8String]); 719 720 if(transform == nil || -1 == FindSpace(transforms, [transform UTF8String])) 721 { 722 [transform release]; 723 724 transform = [[NSString alloc] initWithUTF8String:context->getDefaultTransform([device UTF8String]).c_str()]; 725 } 726 727 728 [self trackActionRadios:nil]; 729 } 730 } 731 catch(const std::exception &e) 732 { 733 NSBeep(); 734 735 NSString *ocioString = [NSString stringWithUTF8String:e.what()]; 736 737 NSAlert *alert = [NSAlert alertWithMessageText:@"OpenColorIO error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", ocioString]; 738 739 [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; 740 741 if(source != CSOURCE_ENVIRONMENT) 742 { 743 source = CSOURCE_ENVIRONMENT; 744 745 [self trackConfigMenu:nil]; 746 } 747 } 748 catch(...) 749 { 750 NSBeep(); 751 752 NSString *ocioString = @"Some unknown error"; 753 754 NSAlert *alert = [NSAlert alertWithMessageText:@"OpenColorIO error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", ocioString]; 755 756 [alert beginSheetModalForWindow:window modalDelegate:nil didEndSelector:NULL contextInfo:NULL]; 757 758 if(source != CSOURCE_ENVIRONMENT) 759 { 760 source = CSOURCE_ENVIRONMENT; 761 762 [self trackConfigMenu:nil]; 763 } 764 } 765 } 766 767 [configurationMenu setToolTip:configPath]; 768} 769 770- (IBAction)trackActionRadios:(id)sender; 771{ 772 if(sender == nil) 773 { 774 // set radios from values 775 NSAssert(action != CACTION_LUT, @"should not be a LUT"); 776 777 const NSUInteger selectedColumn = (action == CACTION_DISPLAY ? 1 : 0); 778 779 [actionRadios selectCellAtRow:0 column:selectedColumn]; 780 } 781 else 782 { 783 // set values from radios 784 action = ([actionRadios selectedColumn] == 1 ? CACTION_DISPLAY : CACTION_CONVERT); 785 } 786 787 788 OpenColorIO_PS_Context *context = (OpenColorIO_PS_Context *)contextPtr; 789 790 NSAssert(context != NULL, @"context was NULL"); 791 792 793 NSTextField *inputLabel = label1; 794 NSPopUpButton *inputMenu = menu1; 795 796 [inputLabel setStringValue:@"Input Space:"]; 797 798 [inputMenu removeAllItems]; 799 800 const SpaceVec &colorSpaces = context->getColorSpaces(); 801 802 for(SpaceVec::const_iterator i = colorSpaces.begin(); i != colorSpaces.end(); ++i) 803 { 804 NSString *colorSpace = [NSString stringWithUTF8String:i->c_str()]; 805 806 [inputMenu addItemWithTitle:colorSpace]; 807 } 808 809 NSAssert([inputMenu itemWithTitle:inputSpace] != nil, @"don't have the input space"); 810 811 [inputMenu selectItemWithTitle:inputSpace]; 812 813 [inputSpaceButton setHidden:NO]; 814 815 816 if(action == CACTION_DISPLAY) 817 { 818 NSTextField *deviceLabel = label2; 819 NSPopUpButton *deviceMenu = menu2; 820 821 NSTextField *transformLabel = label3; 822 NSPopUpButton *transformMenu = menu3; 823 824 825 [deviceLabel setStringValue:@"Device:"]; 826 [deviceLabel setHidden:NO]; 827 828 [deviceMenu setHidden:NO]; 829 830 [deviceMenu removeAllItems]; 831 832 const SpaceVec &devices = context->getDevices(); 833 834 for(SpaceVec::const_iterator i = devices.begin(); i != devices.end(); ++i) 835 { 836 NSString *deviceName = [NSString stringWithUTF8String:i->c_str()]; 837 838 [deviceMenu addItemWithTitle:deviceName]; 839 } 840 841 [outputSpaceButton setHidden:YES]; 842 843 844 [transformLabel setStringValue:@"Transform:"]; 845 [transformLabel setHidden:NO]; 846 847 [transformMenu setHidden:NO]; 848 849 850 [self trackMenu2:nil]; 851 } 852 else 853 { 854 NSAssert(action == CACTION_CONVERT, @"expected Convert"); 855 856 NSTextField *outputLabel = label2; 857 NSPopUpButton *outputMenu = menu2; 858 859 [outputLabel setHidden:NO]; 860 [outputLabel setStringValue:@"Output Space:"]; 861 862 [outputMenu setHidden:NO]; 863 864 [outputMenu removeAllItems]; 865 866 for(SpaceVec::const_iterator i = colorSpaces.begin(); i != colorSpaces.end(); ++i) 867 { 868 NSString *colorSpace = [NSString stringWithUTF8String:i->c_str()]; 869 870 [outputMenu addItemWithTitle:colorSpace]; 871 } 872 873 NSAssert([outputMenu itemWithTitle:outputSpace] != nil, @"don't have the input space"); 874 875 [outputMenu selectItemWithTitle:outputSpace]; 876 877 [outputSpaceButton setHidden:NO]; 878 879 880 NSTextField *transformLabel = label3; 881 NSPopUpButton *transformMenu = menu3; 882 883 [transformLabel setHidden:YES]; 884 [transformMenu setHidden:YES]; 885 886 NSAssert([[transformLabel stringValue] isEqualToString:@"Transform:"], @"expected Transform:"); 887 } 888} 889 890- (IBAction)trackMenu1:(id)sender 891{ 892 NSAssert(sender == menu1, @"always from the UI"); 893 894 if(action == CACTION_LUT) 895 { 896 interpolation = (ControllerInterp)[[menu1 selectedItem] tag]; 897 } 898 else 899 { 900 [inputSpace release]; 901 902 inputSpace = [[menu1 titleOfSelectedItem] retain]; 903 } 904} 905 906- (IBAction)trackMenu2:(id)sender 907{ 908 if(action == CACTION_DISPLAY) 909 { 910 NSPopUpButton *deviceMenu = menu2; 911 912 if(sender == nil) 913 { 914 // set menu from values 915 NSAssert([deviceMenu itemWithTitle:device] != nil, @"don't have the device"); 916 917 [deviceMenu selectItemWithTitle:device]; 918 } 919 else 920 { 921 // set values from menu 922 [device release]; 923 924 device = [[deviceMenu titleOfSelectedItem] retain]; 925 } 926 } 927 else 928 { 929 NSAssert(action == CACTION_CONVERT, @"expected Convert"); 930 931 NSPopUpButton *outputMenu = menu2; 932 933 if(sender == nil) 934 { 935 // set menu from values 936 NSAssert([outputMenu itemWithTitle:outputSpace] != nil, @"don't have the device"); 937 938 [outputMenu selectItemWithTitle:outputSpace]; 939 } 940 else 941 { 942 // set values from menu 943 [outputSpace release]; 944 945 outputSpace = [[outputMenu titleOfSelectedItem] retain]; 946 } 947 } 948 949 950 if(action == CACTION_DISPLAY) 951 { 952 OpenColorIO_PS_Context *context = (OpenColorIO_PS_Context *)contextPtr; 953 954 NSAssert(context != NULL, @"context was NULL"); 955 956 const SpaceVec transforms = context->getTransforms([device UTF8String]); 957 958 NSPopUpButton *transformMenu = menu3; 959 960 [transformMenu removeAllItems]; 961 962 for(SpaceVec::const_iterator i = transforms.begin(); i != transforms.end(); ++i) 963 { 964 NSString *transformName = [NSString stringWithUTF8String:i->c_str()]; 965 966 [transformMenu addItemWithTitle:transformName]; 967 } 968 969 [self trackMenu3:nil]; 970 } 971} 972 973- (IBAction)trackMenu3:(id)sender 974{ 975 NSAssert(action == CACTION_DISPLAY, @"expected Display"); 976 NSAssert([[label3 stringValue] isEqualToString:@"Transform:"], @"expected Transform:"); 977 978 NSPopUpButton *transformMenu = menu3; 979 980 if(sender == nil) 981 { 982 // set menu from value 983 NSMenuItem *valueItem = [transformMenu itemWithTitle:transform]; 984 985 if(valueItem != nil) 986 { 987 [transformMenu selectItem:valueItem]; 988 } 989 else 990 { 991 OpenColorIO_PS_Context *context = (OpenColorIO_PS_Context *)contextPtr; 992 993 NSAssert(context != NULL, @"context was NULL"); 994 995 const std::string defaultTransform = context->getDefaultTransform([device UTF8String]); 996 997 NSMenuItem *defaultItem = [transformMenu itemWithTitle:[NSString stringWithUTF8String:defaultTransform.c_str()]]; 998 999 NSAssert(defaultItem != nil, @"where's that default item?"); 1000 1001 [transformMenu selectItem:defaultItem]; 1002 1003 1004 [transform release]; 1005 1006 transform = [[transformMenu titleOfSelectedItem] retain]; 1007 } 1008 } 1009 else 1010 { 1011 // set value from menu 1012 [transform release]; 1013 1014 transform = [[transformMenu titleOfSelectedItem] retain]; 1015 } 1016} 1017 1018- (IBAction)trackInvert:(id)sender 1019{ 1020 NSAssert(sender == invertCheck, @"expected invertCheck"); 1021 1022 invert = ([invertCheck state] == NSOnState); 1023} 1024 1025- (IBAction)popInputSpaceMenu:(id)sender 1026{ 1027 OpenColorIO_PS_Context *context = (OpenColorIO_PS_Context *)contextPtr; 1028 1029 if(context != NULL) 1030 { 1031 std::string colorSpace = [inputSpace UTF8String]; 1032 1033 const bool chosen = ColorSpacePopUpMenu(context->getConfig(), colorSpace, false, NULL); 1034 1035 if(chosen) 1036 { 1037 [inputSpace release]; 1038 1039 inputSpace = [[NSString alloc] initWithUTF8String:colorSpace.c_str()]; 1040 1041 [menu1 selectItemWithTitle:inputSpace]; 1042 } 1043 } 1044} 1045 1046- (IBAction)popOutputSpaceMenu:(id)sender 1047{ 1048 OpenColorIO_PS_Context *context = (OpenColorIO_PS_Context *)contextPtr; 1049 1050 if(context != NULL) 1051 { 1052 std::string colorSpace = [outputSpace UTF8String]; 1053 1054 const bool chosen = ColorSpacePopUpMenu(context->getConfig(), colorSpace, false, NULL); 1055 1056 if(chosen) 1057 { 1058 [outputSpace release]; 1059 1060 outputSpace = [[NSString alloc] initWithUTF8String:colorSpace.c_str()]; 1061 1062 [menu2 selectItemWithTitle:outputSpace]; 1063 } 1064 } 1065} 1066 1067- (NSWindow *)window 1068{ 1069 return window; 1070} 1071 1072- (ControllerSource)source 1073{ 1074 return source; 1075} 1076 1077- (NSString *)configuration 1078{ 1079 if(source == CSOURCE_CUSTOM) 1080 { 1081 return customPath; 1082 } 1083 else 1084 { 1085 return configuration; 1086 } 1087} 1088 1089- (ControllerAction)action 1090{ 1091 return action; 1092} 1093 1094- (BOOL)invert 1095{ 1096 return invert; 1097} 1098 1099- (ControllerInterp)interpolation 1100{ 1101 return interpolation; 1102} 1103 1104- (NSString *)inputSpace 1105{ 1106 return inputSpace; 1107} 1108 1109- (NSString *)outputSpace 1110{ 1111 return outputSpace; 1112} 1113 1114- (NSString *)device 1115{ 1116 return device; 1117} 1118 1119- (NSString *)transform 1120{ 1121 return transform; 1122} 1123 1124@end 1125