1 /* $Id: PictureController.mm,v 1.11 2005/08/01 15:10:44 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.fr/>.
5 It may be used under the terms of the GNU General Public License. */
7 #import "PictureController.h"
9 #import "HBPreviewController.h"
13 @implementation PictureController
17 if (self = [super initWithWindowNibName:@"PictureSettings"])
19 // NSWindowController likes to lazily load its window. However since
20 // this controller tries to set all sorts of outlets before the window
21 // is displayed, we need it to load immediately. The correct way to do
22 // this, according to the documentation, is simply to invoke the window
25 // If/when we switch a lot of this stuff to bindings, this can probably
29 fPreviewController = [[PreviewController alloc] init];
34 //------------------------------------------------------------------------------------
35 // Displays and brings the picture window to the front
36 //------------------------------------------------------------------------------------
37 - (IBAction) showPictureWindow: (id)sender
39 if ([fPreviewController fullScreen] == YES)
41 [self showWindow:sender];
42 [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PictureSizeWindowIsOpen"];
43 [self setToFullScreenMode];
47 if ([[self window] isVisible])
49 [[self window] close];
53 [self showWindow:sender];
54 [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PictureSizeWindowIsOpen"];
55 [self setToWindowedMode];
60 - (BOOL) previewFullScreenMode
62 return [fPreviewController fullScreen];
65 - (IBAction) previewGoWindowed: (id)sender
67 [fPreviewController goWindowedScreen:self];
70 - (IBAction) showPreviewWindow: (id)sender
72 [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PreviewWindowIsOpen"];
73 [fPreviewController showWindow:sender];
79 - (void) setToFullScreenMode
81 int32_t shieldLevel = CGShieldingWindowLevel();
83 [fPictureWindow setLevel:shieldLevel + 1];
85 [fPictureWindow makeKeyAndOrderFront:self];
88 - (void) setToWindowedMode
90 /* Set the window back to Floating Window mode
91 * This will put the window always on top, but
92 * since we have Hide on Deactivate set in our
93 * xib, if other apps are put in focus we will
94 * hide properly to stay out of the way
96 [[self window] setLevel:NSFloatingWindowLevel];
99 - (void)setHBController: (HBController *)controller
101 fHBController = controller;
102 [fPreviewController setHBController: controller];
108 [fPictureWindow setDelegate:self];
109 if( ![[self window] setFrameUsingName:@"PictureSizing"] )
110 [[self window] center];
111 [self setWindowFrameAutosaveName:@"PictureSizing"];
112 [[self window] setExcludedFromWindowsMenu:YES];
114 [self setInitialPictureFilters];
116 /* Setup our layers for core animation */
117 [fSizeFilterView setWantsLayer:YES];
121 - (void)windowWillClose:(NSNotification *)aNotification
123 [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"PictureSizeWindowIsOpen"];
126 - (BOOL)windowShouldClose:(id)fPictureWindow
133 [fPreviewController release];
137 - (void) SetHandle: (hb_handle_t *) handle
141 [fWidthStepper setValueWraps: NO];
142 [fWidthStepper setIncrement: 16];
143 [fWidthStepper setMinValue: 64];
144 [fHeightStepper setValueWraps: NO];
145 [fHeightStepper setIncrement: 16];
146 [fHeightStepper setMinValue: 64];
148 [fCropTopStepper setIncrement: 2];
149 [fCropTopStepper setMinValue: 0];
150 [fCropBottomStepper setIncrement: 2];
151 [fCropBottomStepper setMinValue: 0];
152 [fCropLeftStepper setIncrement: 2];
153 [fCropLeftStepper setMinValue: 0];
154 [fCropRightStepper setIncrement: 2];
155 [fCropRightStepper setMinValue: 0];
157 [fPreviewController SetHandle: fHandle];
160 - (void) SetTitle: (hb_title_t *) title
162 hb_job_t * job = title->job;
168 [fWidthStepper setMaxValue: title->width];
169 [fWidthStepper setIntValue: job->width];
170 [fWidthField setIntValue: job->width];
171 [fHeightStepper setMaxValue: title->height];
172 [fHeightStepper setIntValue: job->height];
173 [fHeightField setIntValue: job->height];
174 [fRatioCheck setState: job->keep_ratio ? NSOnState : NSOffState];
175 [fCropTopStepper setMaxValue: title->height/2-2];
176 [fCropBottomStepper setMaxValue: title->height/2-2];
177 [fCropLeftStepper setMaxValue: title->width/2-2];
178 [fCropRightStepper setMaxValue: title->width/2-2];
180 /* Populate the Anamorphic NSPopUp button here */
181 [fAnamorphicPopUp removeAllItems];
182 [fAnamorphicPopUp addItemWithTitle: @"None"];
183 [fAnamorphicPopUp addItemWithTitle: @"Strict"];
184 if (allowLooseAnamorphic)
186 [fAnamorphicPopUp addItemWithTitle: @"Loose"];
188 [fAnamorphicPopUp selectItemAtIndex: job->anamorphic.mode];
190 /* We initially set the previous state of keep ar to on */
191 keepAspectRatioPreviousState = 1;
194 [fCropMatrix selectCellAtRow: 1 column:0];
195 /* If auto, lets set the crop steppers according to current job->crop values */
196 [fCropTopStepper setIntValue: job->crop[0]];
197 [fCropTopField setIntValue: job->crop[0]];
198 [fCropBottomStepper setIntValue: job->crop[1]];
199 [fCropBottomField setIntValue: job->crop[1]];
200 [fCropLeftStepper setIntValue: job->crop[2]];
201 [fCropLeftField setIntValue: job->crop[2]];
202 [fCropRightStepper setIntValue: job->crop[3]];
203 [fCropRightField setIntValue: job->crop[3]];
207 [fCropMatrix selectCellAtRow: 0 column:0];
210 /* Set filters widgets according to the filters struct */
211 [fDetelecinePopUp selectItemAtIndex:fPictureFilterSettings.detelecine];
212 [fDecombPopUp selectItemAtIndex:fPictureFilterSettings.decomb];
213 [fDeinterlacePopUp selectItemAtIndex: fPictureFilterSettings.deinterlace];
214 [fDenoisePopUp selectItemAtIndex: fPictureFilterSettings.denoise];
215 [fDeblockSlider setFloatValue:fPictureFilterSettings.deblock];
216 [fGrayscaleCheck setState:fPictureFilterSettings.grayscale];
218 [self deblockSliderChanged: nil];
221 MaxOutputWidth = title->width - job->crop[2] - job->crop[3];
222 MaxOutputHeight = title->height - job->crop[0] - job->crop[1];
224 [self SettingsChanged: nil];
229 - (IBAction) SettingsChanged: (id) sender
231 hb_job_t * job = fTitle->job;
233 autoCrop = ( [fCropMatrix selectedRow] == 0 );
234 [fCropTopStepper setEnabled: !autoCrop];
235 [fCropBottomStepper setEnabled: !autoCrop];
236 [fCropLeftStepper setEnabled: !autoCrop];
237 [fCropRightStepper setEnabled: !autoCrop];
241 memcpy( job->crop, fTitle->crop, 4 * sizeof( int ) );
245 job->crop[0] = [fCropTopStepper intValue];
246 job->crop[1] = [fCropBottomStepper intValue];
247 job->crop[2] = [fCropLeftStepper intValue];
248 job->crop[3] = [fCropRightStepper intValue];
251 if( [fAnamorphicPopUp indexOfSelectedItem] > 0 )
253 if ([fAnamorphicPopUp indexOfSelectedItem] == 2) // Loose anamorphic
255 job->anamorphic.mode = 2;
256 [fWidthStepper setEnabled: YES];
257 [fWidthField setEnabled: YES];
258 /* We set job->width and call hb_set_anamorphic_size in libhb to do a "dry run" to get
259 * the values to be used by libhb for loose anamorphic
261 /* if the sender is the anamorphic popup, then we know that loose anamorphic has just
262 * been turned on, so snap the width to full width for the source.
264 if (sender == fAnamorphicPopUp)
266 [fWidthStepper setIntValue: fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3]];
267 [fWidthField setIntValue: fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3]];
269 job->width = [fWidthStepper intValue];
270 hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height);
271 [fHeightStepper setIntValue: output_height];
272 [fHeightField setIntValue: output_height];
273 job->height = [fHeightStepper intValue];
276 else // must be "1" or strict anamorphic
278 [fWidthStepper setIntValue: fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3]];
279 [fWidthField setIntValue: fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3]];
281 /* This will show correct anamorphic height values, but
282 show distorted preview picture ratio */
283 [fHeightStepper setIntValue: fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1]];
284 [fHeightField setIntValue: fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1]];
285 job->width = [fWidthStepper intValue];
286 job->height = [fHeightStepper intValue];
288 job->anamorphic.mode = 1;
289 [fWidthStepper setEnabled: NO];
290 [fWidthField setEnabled: NO];
293 /* if the sender is the Anamorphic checkbox, record the state
294 of KeepAspect Ratio so it can be reset if Anamorphic is unchecked again */
295 if (sender == fAnamorphicPopUp)
297 keepAspectRatioPreviousState = [fRatioCheck state];
299 [fRatioCheck setState:NSOffState];
300 [fRatioCheck setEnabled: NO];
303 [fHeightStepper setEnabled: NO];
304 [fHeightField setEnabled: NO];
309 job->width = [fWidthStepper intValue];
310 job->height = [fHeightStepper intValue];
311 job->anamorphic.mode = 0;
312 [fWidthStepper setEnabled: YES];
313 [fWidthField setEnabled: YES];
314 [fHeightStepper setEnabled: YES];
315 [fHeightField setEnabled: YES];
316 [fRatioCheck setEnabled: YES];
317 /* if the sender is the Anamorphic checkbox, we return the
318 keep AR checkbox to its previous state */
319 if (sender == fAnamorphicPopUp)
321 [fRatioCheck setState:keepAspectRatioPreviousState];
326 job->keep_ratio = ( [fRatioCheck state] == NSOnState );
328 if( job->keep_ratio )
330 if( sender == fWidthStepper || sender == fRatioCheck ||
331 sender == fCropTopStepper || sender == fCropBottomStepper )
333 hb_fix_aspect( job, HB_KEEP_WIDTH );
334 if( job->height > fTitle->height )
336 job->height = fTitle->height;
337 hb_fix_aspect( job, HB_KEEP_HEIGHT );
342 hb_fix_aspect( job, HB_KEEP_HEIGHT );
343 if( job->width > fTitle->width )
345 job->width = fTitle->width;
346 hb_fix_aspect( job, HB_KEEP_WIDTH );
349 // hb_get_preview can't handle sizes that are larger than the original title
351 if( job->width > fTitle->width )
352 job->width = fTitle->width;
354 if( job->height > fTitle->height )
355 job->height = fTitle->height;
358 [fWidthStepper setIntValue: job->width];
359 [fWidthField setIntValue: job->width];
360 if( [fAnamorphicPopUp indexOfSelectedItem] < 2 )
362 [fHeightStepper setIntValue: job->height];
363 [fHeightField setIntValue: job->height];
365 [fCropTopStepper setIntValue: job->crop[0]];
366 [fCropTopField setIntValue: job->crop[0]];
367 [fCropBottomStepper setIntValue: job->crop[1]];
368 [fCropBottomField setIntValue: job->crop[1]];
369 [fCropLeftStepper setIntValue: job->crop[2]];
370 [fCropLeftField setIntValue: job->crop[2]];
371 [fCropRightStepper setIntValue: job->crop[3]];
372 [fCropRightField setIntValue: job->crop[3]];
374 [fPreviewController SetTitle:fTitle];
375 /* Sanity Check Here for < 16 px preview to avoid
376 crashing hb_get_preview. In fact, just for kicks
377 lets getting previews at a min limit of 32, since
378 no human can see any meaningful detail below that */
379 if (job->width >= 64 && job->height >= 64)
382 // Purge the existing picture previews so they get recreated the next time
384 [fPreviewController purgeImageCache];
385 /* We actually call displayPreview now from pictureSliderChanged which keeps
386 * our picture preview slider in sync with the previews being shown
389 //[fPreviewController pictureSliderChanged:nil];
390 [self reloadStillPreview];
393 /* we get the sizing info to display from fPreviewController */
394 [fSizeInfoField setStringValue: [fPreviewController pictureSizeInfoString]];
398 [fHBController pictureSettingsDidChange];
403 - (NSString*) getPictureSizeInfoString
405 return [fSizeInfoField stringValue];
408 - (void)reloadStillPreview
410 hb_job_t * job = fTitle->job;
412 [fPreviewController SetTitle:fTitle];
413 /* Sanity Check Here for < 16 px preview to avoid
414 crashing hb_get_preview. In fact, just for kicks
415 lets getting previews at a min limit of 32, since
416 no human can see any meaningful detail below that */
417 if (job->width >= 64 && job->height >= 64)
420 // Purge the existing picture previews so they get recreated the next time
422 [fPreviewController purgeImageCache];
423 /* We actually call displayPreview now from pictureSliderChanged which keeps
424 * our picture preview slider in sync with the previews being shown
427 [fPreviewController pictureSliderChanged:nil];
439 - (void) setAutoCrop: (BOOL) setting
444 - (BOOL) allowLooseAnamorphic
446 return allowLooseAnamorphic;
449 - (void) setAllowLooseAnamorphic: (BOOL) setting
451 allowLooseAnamorphic = setting;
454 - (IBAction)showPreviewPanel: (id)sender forTitle: (hb_title_t *)title
456 [self SetTitle:title];
457 [self showWindow:sender];
463 /* we use this to setup the initial picture filters upon first launch, after that their states
464 are maintained across different sources */
465 - (void) setInitialPictureFilters
467 /* we use a popup to show the detelecine settings */
468 [fDetelecinePopUp removeAllItems];
469 [fDetelecinePopUp addItemWithTitle: @"Off"];
470 [fDetelecinePopUp addItemWithTitle: @"Default"];
471 [fDetelecinePopUp addItemWithTitle: @"Custom"];
472 [fDetelecinePopUp selectItemAtIndex: fPictureFilterSettings.detelecine];
474 [self modeDecombDeinterlaceSliderChanged:nil];
475 /* we use a popup to show the decomb settings */
476 [fDecombPopUp removeAllItems];
477 [fDecombPopUp addItemWithTitle: @"Off"];
478 [fDecombPopUp addItemWithTitle: @"Default"];
479 [fDecombPopUp addItemWithTitle: @"Custom"];
480 [fDecombPopUp selectItemAtIndex: fPictureFilterSettings.decomb];
482 /* we use a popup to show the deinterlace settings */
483 [fDeinterlacePopUp removeAllItems];
484 [fDeinterlacePopUp addItemWithTitle: @"None"];
485 [fDeinterlacePopUp addItemWithTitle: @"Fast"];
486 [fDeinterlacePopUp addItemWithTitle: @"Slow"];
487 [fDeinterlacePopUp addItemWithTitle: @"Slower"];
488 [fDeinterlacePopUp addItemWithTitle: @"Custom"];
490 /* Set deinterlaces level according to the integer in the main window */
491 [fDeinterlacePopUp selectItemAtIndex: fPictureFilterSettings.deinterlace];
493 /* we use a popup to show the denoise settings */
494 [fDenoisePopUp removeAllItems];
495 [fDenoisePopUp addItemWithTitle: @"None"];
496 [fDenoisePopUp addItemWithTitle: @"Weak"];
497 [fDenoisePopUp addItemWithTitle: @"Medium"];
498 [fDenoisePopUp addItemWithTitle: @"Strong"];
499 [fDenoisePopUp addItemWithTitle: @"Custom"];
500 /* Set denoises level according to the integer in the main window */
501 [fDenoisePopUp selectItemAtIndex: fPictureFilterSettings.denoise];
509 - (IBAction) modeDecombDeinterlaceSliderChanged: (id) sender
512 if ([fDecombDeinterlaceSlider floatValue] == 0.0)
514 [fDecombBox setHidden:NO];
515 [fDeinterlaceBox setHidden:YES];
516 fPictureFilterSettings.decomb = [fDecombPopUp indexOfSelectedItem];
517 fPictureFilterSettings.usedecomb = 1;
518 fPictureFilterSettings.deinterlace = 0;
519 [self adjustFilterDisplay:fDecombPopUp];
520 [fDecombPopUp selectItemAtIndex:fPictureFilterSettings.decomb];
524 [fDecombBox setHidden:YES];
525 [fDeinterlaceBox setHidden:NO];
526 fPictureFilterSettings.usedecomb = 0;
527 fPictureFilterSettings.decomb = 0;
528 [self adjustFilterDisplay:fDeinterlacePopUp];
529 [fDeinterlacePopUp selectItemAtIndex: fPictureFilterSettings.deinterlace];
531 [self FilterSettingsChanged: sender];
535 - (IBAction) FilterSettingsChanged: (id) sender
538 fPictureFilterSettings.detelecine = [fDetelecinePopUp indexOfSelectedItem];
539 [self adjustFilterDisplay:fDetelecinePopUp];
541 fPictureFilterSettings.decomb = [fDecombPopUp indexOfSelectedItem];
542 [self adjustFilterDisplay:fDecombPopUp];
544 fPictureFilterSettings.deinterlace = [fDeinterlacePopUp indexOfSelectedItem];
545 [self adjustFilterDisplay:fDeinterlacePopUp];
547 fPictureFilterSettings.denoise = [fDenoisePopUp indexOfSelectedItem];
548 [self adjustFilterDisplay:fDenoisePopUp];
550 if ([fDeblockField stringValue] == @"Off")
552 fPictureFilterSettings.deblock = 0;
556 fPictureFilterSettings.deblock = [fDeblockField intValue];
559 fPictureFilterSettings.grayscale = [fGrayscaleCheck state];
563 [fHBController pictureSettingsDidChange];
569 - (void) adjustFilterDisplay: (id) sender
572 NSBox * filterBox = nil;
573 NSTextField * filterField;
574 if (sender == fDetelecinePopUp)
576 filterBox = fDetelecineBox;
577 filterField = fDetelecineField;
579 if (sender == fDecombPopUp)
581 filterBox = fDecombBox;
582 filterField = fDecombField;
584 if (sender == fDeinterlacePopUp)
586 filterBox = fDeinterlaceBox;
587 filterField = fDeinterlaceField;
590 if (sender == fDenoisePopUp)
592 filterBox = fDenoiseBox;
593 filterField = fDenoiseField;
596 NSSize currentSize = [filterBox frame].size;
597 if ([sender titleOfSelectedItem] == @"Custom")
599 currentSize.height = 60;
603 currentSize.height = 30;
605 /* Check to see if we have changed the size from current */
606 if (currentSize.height != [filterBox frame].size.height)
608 /* We are changing the size of the box, so recalc the origin */
609 NSPoint origin = [filterBox frame].origin;
610 /* See if we are expanding the box downwards */
611 if (currentSize.height > [filterBox frame].size.height)
613 origin.y = origin.y - currentSize.height / 2;
617 origin.y = origin.y + currentSize.height;
619 /* go ahead and resize the box */
620 [filterBox setFrameSize:currentSize];
621 [filterBox setFrameOrigin:origin];
628 - (IBAction) deblockSliderChanged: (id) sender
630 if ([fDeblockSlider floatValue] == 4.0)
632 [fDeblockField setStringValue: [NSString stringWithFormat: @"Off"]];
636 [fDeblockField setStringValue: [NSString stringWithFormat: @"%.0f", [fDeblockSlider floatValue]]];
638 [self FilterSettingsChanged: sender];
644 return fPictureFilterSettings.detelecine;
647 - (NSString*) detelecineCustomString
649 return [fDetelecineField stringValue];
652 - (void) setDetelecine: (int) setting
654 fPictureFilterSettings.detelecine = setting;
657 - (void) setDetelecineCustomString: (NSString*) string
659 [fDetelecineField setStringValue:string];
664 return fPictureFilterSettings.deinterlace;
666 - (NSString*) deinterlaceCustomString
668 return [fDeinterlaceField stringValue];
671 - (void) setDeinterlaceCustomString: (NSString*) string
673 [fDeinterlaceField setStringValue:string];
676 - (void) setDeinterlace: (int) setting
678 fPictureFilterSettings.deinterlace = setting;
682 return fPictureFilterSettings.decomb;
685 - (NSString*) decombCustomString
687 return [fDecombField stringValue];
692 return fPictureFilterSettings.usedecomb;
695 - (void) setUseDecomb: (int) setting
697 fPictureFilterSettings.usedecomb = setting;
698 if (fPictureFilterSettings.usedecomb == 1)
700 [fDecombDeinterlaceSlider setFloatValue:0.0];
704 [fDecombDeinterlaceSlider setFloatValue:1.0];
706 [self modeDecombDeinterlaceSliderChanged:nil];
709 - (void) setDecomb: (int) setting {
710 fPictureFilterSettings.decomb = setting;
713 - (void) setDecombCustomString: (NSString*) string
715 [fDecombField setStringValue:string];
720 return fPictureFilterSettings.denoise;
723 - (NSString*) denoiseCustomString
725 return [fDenoiseField stringValue];
728 - (void) setDenoiseCustomString: (NSString*) string
730 [fDenoiseField setStringValue:string];
733 - (void) setDenoise: (int) setting
735 fPictureFilterSettings.denoise = setting;
740 return fPictureFilterSettings.deblock;
743 - (void) setDeblock: (int) setting
745 fPictureFilterSettings.deblock = setting;
750 return fPictureFilterSettings.grayscale;
753 - (void) setGrayscale: (int) setting
755 fPictureFilterSettings.grayscale = setting;