OSDN Git Service

LinGui: don't disable subme 10 when psy-rd is 0
[handbrake-jp/handbrake-jp-git.git] / macosx / HBPreviewController.mm
1 /* $Id: HBPreviewController.mm,v 1.11 2005/08/01 15:10:44 titer Exp $
2
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. */
6
7 #import "HBPreviewController.h"
8 #import "Controller.h"
9
10 @interface PreviewController (Private)
11
12 - (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize;
13 - (void)resizeSheetForViewSize: (NSSize)viewSize;
14 - (void)setViewSize: (NSSize)viewSize;
15 - (BOOL)viewNeedsToResizeToSize: (NSSize)newSize;
16
17 @end
18
19 @implementation PreviewController
20
21 - (id)init
22 {
23         if (self = [super initWithWindowNibName:@"PicturePreview"])
24         {
25         // NSWindowController likes to lazily load its window. However since
26         // this controller tries to set all sorts of outlets before the window
27         // is displayed, we need it to load immediately. The correct way to do
28         // this, according to the documentation, is simply to invoke the window
29         // getter once.
30         //
31         // If/when we switch a lot of this stuff to bindings, this can probably
32         // go away.
33         [self window];
34         
35                 fPicturePreviews = [[NSMutableDictionary dictionaryWithCapacity: HB_NUM_HBLIB_PICTURES] retain];
36         /* Init libhb with check for updates libhb style set to "0" so its ignored and lets sparkle take care of it */
37         int loggingLevel = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LoggingLevel"] intValue];
38         fPreviewLibhb = hb_init(loggingLevel, 0);
39         
40         }
41         return self;
42 }
43
44
45
46 //------------------------------------------------------------------------------------
47 // Displays and brings the picture window to the front
48 //------------------------------------------------------------------------------------
49 - (IBAction) showPreviewWindow: (id)sender
50 {
51     [self showWindow:sender];
52     [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PreviewWindowIsOpen"];
53     
54     /* lets set the preview window to accept mouse moved events */
55     [fPreviewWindow setAcceptsMouseMovedEvents:YES];
56     hudTimerSeconds = 0;
57     [self pictureSliderChanged:nil];
58     [self startReceivingLibhbNotifications];
59 }
60
61 - (void)setHBController: (HBController *)controller
62 {
63     fHBController = controller;
64 }
65
66 - (void)awakeFromNib
67 {
68     [fPreviewWindow setDelegate:self];
69     if( ![[self window] setFrameUsingName:@"Preview"] )
70         [[self window] center];
71     [self setWindowFrameAutosaveName:@"Preview"];
72     [[self window] setExcludedFromWindowsMenu:YES];
73     
74     /* lets set the preview window to accept mouse moved events */
75     [fPreviewWindow setAcceptsMouseMovedEvents:YES];
76     //[self pictureSliderChanged:nil];
77     [self startReceivingLibhbNotifications];
78     
79     isFullScreen = NO;
80     hudTimerSeconds = 0;
81     /* we set the progress indicator to not use threaded animation
82      * as it causes a conflict with the qtmovieview's controllerbar
83     */
84     [fMovieCreationProgressIndicator setUsesThreadedAnimation:NO];
85     
86     /* Setup our layers for core animation */
87     [fPictureViewArea setWantsLayer:YES];
88     [fPictureView setWantsLayer:YES];
89     
90     [fMovieView setWantsLayer:YES];
91     
92     [fCancelPreviewMovieButton setWantsLayer:YES];
93     [fMovieCreationProgressIndicator setWantsLayer:YES];
94     
95     [fPictureControlBox setWantsLayer:YES];
96     [fPictureSlider setWantsLayer:YES];
97     [fFullScreenToggleButton setWantsLayer:YES];
98     [fPictureSettingsToggleButton setWantsLayer:YES];
99     [fScaleToScreenToggleButton setWantsLayer:YES];
100     [fCreatePreviewMovieButton setWantsLayer:YES];
101     
102     [fEncodingControlBox setWantsLayer:YES];
103     
104     [fShowPreviewMovieButton setWantsLayer:YES];
105     
106     /* Since the xib has everything off center for easy acess
107      * we align our views and windows here we an align to anything
108      * since it will actually change later upon source load, but
109      * for convenience we will use the fPictureViewArea
110      */
111      
112      /* Align the still preview image view to the picture box */
113      [fPictureView setFrameSize:[fPictureViewArea frame].size];
114      [fMovieView setFrameSize:[fPictureViewArea frame].size];
115      //[fPreviewWindow setFrameSize:[fPictureViewArea frame].size];
116     
117     
118 }
119 - (BOOL)acceptsMouseMovedEvents
120 {
121 return YES;
122 }
123
124 - (void)windowWillClose:(NSNotification *)aNotification
125 {
126     
127     
128     /* Upon Closing the picture window, we make sure we clean up any
129      * preview movie that might be playing
130      */
131     play_movie = NO;
132     hb_stop( fPreviewLibhb );
133     isEncoding = NO;
134     // Show the picture view
135     [fPictureView setHidden:NO];
136     [fMovieView pause:nil];
137     [fMovieView setHidden:YES];
138     
139     isFullScreen = NO;
140     hudTimerSeconds = 0;
141     [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"PreviewWindowIsOpen"];
142 }
143
144 - (BOOL)windowShouldClose:(id)fPictureWindow
145 {
146      
147      return YES;
148 }
149
150 - (void) dealloc
151 {
152     hb_stop(fPreviewLibhb);
153     if (fPreviewMoviePath)
154     {
155         [[NSFileManager defaultManager] removeFileAtPath:fPreviewMoviePath handler:nil];
156         [fPreviewMoviePath release];
157     }    
158     
159     [fLibhbTimer invalidate];
160     [fLibhbTimer release];
161     
162     [fHudTimer invalidate];
163     [fHudTimer release];
164     
165     [fPicturePreviews release];
166     [fFullScreenWindow release];
167
168     [super dealloc];
169 }
170
171 - (void) SetHandle: (hb_handle_t *) handle
172 {
173     fHandle = handle;
174     
175
176     
177     /* we set the preview length popup in seconds */
178     [fPreviewMovieLengthPopUp removeAllItems];
179     [fPreviewMovieLengthPopUp addItemWithTitle: @"5"];
180     [fPreviewMovieLengthPopUp addItemWithTitle: @"10"];
181     [fPreviewMovieLengthPopUp addItemWithTitle: @"15"];
182     [fPreviewMovieLengthPopUp addItemWithTitle: @"20"];
183     [fPreviewMovieLengthPopUp addItemWithTitle: @"25"];
184     [fPreviewMovieLengthPopUp addItemWithTitle: @"30"];
185     [fPreviewMovieLengthPopUp addItemWithTitle: @"35"];
186     [fPreviewMovieLengthPopUp addItemWithTitle: @"40"];
187     [fPreviewMovieLengthPopUp addItemWithTitle: @"45"];
188     [fPreviewMovieLengthPopUp addItemWithTitle: @"50"];
189     [fPreviewMovieLengthPopUp addItemWithTitle: @"55"];
190     [fPreviewMovieLengthPopUp addItemWithTitle: @"60"];
191     
192     /* adjust the preview slider length */
193     /* We use our advance pref to determine how many previews we scanned */
194     int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue];
195     [fPictureSlider setMaxValue: hb_num_previews - 1.0];
196     [fPictureSlider setNumberOfTickMarks: hb_num_previews];
197     
198     if ([[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"])
199     {
200         [fPreviewMovieLengthPopUp selectItemWithTitle:[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"]];
201     }
202     else
203     {
204         /* currently hard set default to 10 seconds */
205         [fPreviewMovieLengthPopUp selectItemAtIndex: 1];
206     }
207 }
208
209 - (void) SetTitle: (hb_title_t *) title
210 {
211     hb_job_t * job = title->job;
212     
213     fTitle = title;
214     fPicture = 0;
215     MaxOutputWidth = title->width - job->crop[2] - job->crop[3];
216     MaxOutputHeight = title->height - job->crop[0] - job->crop[1];
217     [self SettingsChanged: nil];
218 }
219
220
221
222 // Adjusts the window to draw the current picture (fPicture) adjusting its size as
223 // necessary to display as much of the picture as possible.
224 - (void) displayPreview
225 {
226     hb_job_t * job = fTitle->job;
227     /* lets make sure that the still picture view is not hidden and that 
228      * the movie preview is 
229      */
230     [fMovieView pause:nil];
231     [fMovieView setHidden:YES];
232     [fMovieCreationProgressIndicator stopAnimation: nil];
233     [fMovieCreationProgressIndicator setHidden: YES];
234     
235     [fPictureView setHidden:NO];
236     
237     //[fHBController writeToActivityLog: "displayPreview called"];
238     
239     NSImage *fPreviewImage = [self imageForPicture: fPicture];
240     NSSize imageScaledSize = [fPreviewImage size];
241     [fPictureView setImage: fPreviewImage];
242     
243     NSSize displaySize = NSMakeSize( ( CGFloat )fTitle->width, ( CGFloat )fTitle->height );
244     NSString *sizeInfoString;
245     /* Set the picture size display fields below the Preview Picture*/
246     if( fTitle->job->anamorphic.mode == 1 ) // Original PAR Implementation
247     {
248         output_width = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3];
249         output_height = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1];
250         display_width = output_width * fTitle->job->anamorphic.par_width / fTitle->job->anamorphic.par_height;
251         sizeInfoString = [NSString stringWithFormat:
252                           @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Strict",
253                           fTitle->width, fTitle->height, output_width, output_height, display_width, output_height];
254         
255         displaySize.width = display_width;
256         displaySize.height = fTitle->height;
257         imageScaledSize.width = display_width;
258         imageScaledSize.height = output_height;   
259     }
260     else if (fTitle->job->anamorphic.mode == 2) // Loose Anamorphic
261     {
262         hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height);
263         display_width = output_width * output_par_width / output_par_height;
264         sizeInfoString = [NSString stringWithFormat:
265                           @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Loose",
266                           fTitle->width, fTitle->height, output_width, output_height, display_width, output_height];
267         
268         displaySize.width = display_width;
269         displaySize.height = fTitle->height;
270         imageScaledSize.width = display_width;
271         imageScaledSize.height = output_height;
272     }
273     else if (fTitle->job->anamorphic.mode == 3) // Custom Anamorphic
274     {
275         hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height);
276         display_width = output_width * output_par_width / output_par_height;
277         sizeInfoString = [NSString stringWithFormat:
278                           @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Custom",
279                           fTitle->width, fTitle->height, output_width, output_height, fTitle->job->anamorphic.dar_width, fTitle->job->anamorphic.dar_height];
280         
281         displaySize.width = fTitle->job->anamorphic.dar_width + fTitle->job->crop[2] + fTitle->job->crop[3];
282         displaySize.height = fTitle->job->anamorphic.dar_height + fTitle->job->crop[0] + fTitle->job->crop[1];
283         imageScaledSize.width = (int)fTitle->job->anamorphic.dar_width;
284         imageScaledSize.height = (int)fTitle->job->height;   
285     } 
286     else // No Anamorphic
287     {
288         sizeInfoString = [NSString stringWithFormat:
289                           @"Source: %dx%d, Output: %dx%d", fTitle->width, fTitle->height,
290                           fTitle->job->width, fTitle->job->height];
291         
292         displaySize.width = fTitle->width;
293         displaySize.height = fTitle->height;
294         imageScaledSize.width = fTitle->job->width;
295         imageScaledSize.height = fTitle->job->height;
296     }
297     
298     NSSize viewSize = [self optimalViewSizeForImageSize:displaySize];
299     
300     /* Initially set our preview image here */
301     /*
302     if (scaleToScreen == YES)
303     {
304         viewSize.width = viewSize.width - (viewSize.width - imageScaledSize.width);
305         viewSize.height = viewSize.height - (viewSize.height - imageScaledSize.height);
306         [fPreviewImage setSize: viewSize];
307         //[fPictureView setFrameSize: viewSize];
308     }
309     
310     else
311     {
312         [fPreviewImage setSize: imageScaledSize];
313         [fPictureView setFrameSize: imageScaledSize];
314     }
315     [fPictureView setImage: fPreviewImage];
316     // center it vertically and horizontally
317     NSPoint origin = [fPictureViewArea frame].origin;
318     origin.y += ([fPictureViewArea frame].size.height -
319                  [fPictureView frame].size.height) / 2.0;
320     
321     origin.x += ([fPictureViewArea frame].size.width -
322                  [fPictureView frame].size.width) / 2.0;
323     [fPictureView setFrameOrigin:origin]; 
324     */
325     /* we also need to take into account scaling to full screen to activate switching the view size */
326     if( [self viewNeedsToResizeToSize:viewSize])
327     {
328         if (fTitle->job->anamorphic.mode != 2 || (fTitle->job->anamorphic.mode == 2 && fTitle->width == fTitle->job->width))
329         {
330             [self resizeSheetForViewSize:viewSize];
331             //[self setViewSize:viewSize];
332             
333         }
334     }   
335     
336     viewSize.width = viewSize.width - (viewSize.width - imageScaledSize.width);
337     viewSize.height = viewSize.height - (viewSize.height - imageScaledSize.height);
338     [self setViewSize:viewSize];
339     
340     /* special case for scaleToScreen */
341     if (scaleToScreen == YES)
342     {
343         [fPreviewImage setSize: viewSize];
344         [fPictureView setImage: fPreviewImage];
345     }
346     
347     NSString *scaleString;
348     
349     if( imageScaledSize.height > [fPictureView frame].size.height)
350     {
351         CGFloat scale = ( ( CGFloat )[fPictureView frame].size.width) / ( ( CGFloat )imageScaledSize.width);        
352         scaleString = [NSString stringWithFormat:
353                        NSLocalizedString( @" (Scaled to %.0f%% actual size)",
354                                          @"String shown when a preview is scaled" ), scale * 100.0];
355     }
356     else
357     {
358         scaleString = @"";
359     }
360     /* Set the info fields in the hud controller */
361     [fInfoField setStringValue: [NSString stringWithFormat:
362                                  @"%@", sizeInfoString]];
363     
364     [fscaleInfoField setStringValue: [NSString stringWithFormat:
365                                       @"%@", scaleString]];
366     /* Set the info field in the window title bar */
367     [[self window] setTitle:[NSString stringWithFormat: @"Preview - %@ %@",sizeInfoString, scaleString]];
368 }
369
370 - (IBAction) previewDurationPopUpChanged: (id) sender
371 {
372     
373     [[NSUserDefaults standardUserDefaults] setObject:[fPreviewMovieLengthPopUp titleOfSelectedItem] forKey:@"PreviewLength"];
374     
375 }    
376     
377 - (IBAction) SettingsChanged: (id) sender
378 {
379          // Purge the existing picture previews so they get recreated the next time
380         // they are needed.
381         [self purgeImageCache];
382         [self pictureSliderChanged:nil];
383 }
384
385 - (IBAction) pictureSliderChanged: (id) sender
386 {
387     // Show the picture view
388     [fPictureView setHidden:NO];
389     [fMovieView pause:nil];
390     [fMovieView setHidden:YES];
391     [fEncodingControlBox setHidden: YES];
392     
393     int newPicture = [fPictureSlider intValue];
394     if (newPicture != fPicture)
395     {
396         fPicture = newPicture;
397     }
398     [self displayPreview];
399     
400 }
401
402 - (IBAction)showPreviewPanel: (id)sender forTitle: (hb_title_t *)title
403 {
404     //[self SetTitle:title];
405     
406     if ([fPreviewWindow isVisible])
407     {
408         
409         [fPreviewWindow close];
410         
411     }
412     else
413     {
414         [self showWindow:sender];
415         [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PreviewWindowIsOpen"];
416         [fPreviewWindow setAcceptsMouseMovedEvents:YES];
417         isFullScreen = NO;
418         scaleToScreen = NO;
419         hudTimerSeconds = 0;
420         [self pictureSliderChanged:nil];
421         [self startHudTimer];
422     }
423     
424 }
425
426 - (NSString*) pictureSizeInfoString
427 {
428     return [fInfoField stringValue];
429 }
430
431 - (IBAction)showPictureSettings:(id)sender
432 {
433     [fHBController showPicturePanel:self];
434 }
435
436 #pragma mark Hud Control Overlay
437 - (void) mouseMoved:(NSEvent *)theEvent
438 {
439     [super mouseMoved:theEvent];
440     
441     if (isEncoding == NO)
442     {    
443         if (hudTimerSeconds == 0)
444         {
445             hudTimerSeconds ++;
446             [self startHudTimer];
447         }
448         
449         if (hudTimerSeconds > 20)
450         {
451             
452             
453             [self stopHudTimer];
454             [self showHideHudControls];
455         }
456         
457     }
458 }
459
460 - (void) startHudTimer
461 {
462     if (!fHudTimer)
463     {
464         fHudTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(hudTimerFired:) userInfo:nil repeats:YES];
465         [fHudTimer retain];
466     }
467 }
468
469 - (void) stopHudTimer
470 {
471     if (fHudTimer)
472     {
473         [fHudTimer invalidate];
474         [fHudTimer release];
475         fHudTimer = nil;
476         hudTimerSeconds = 0;
477     }
478 }
479
480 - (void) hudTimerFired: (NSTimer*)theTimer
481 {
482     hudTimerSeconds ++;
483     [self showHideHudControls];
484
485 }
486
487 - (void) showHideHudControls
488 {
489     /* Test for mouse location to show/hide hud controls */
490     NSPoint    mouseLoc;
491     NSRect     targetFrame;
492     NSRect     controlBoxFrame;
493     targetFrame = [fPictureViewArea frame];
494     controlBoxFrame = [fPictureControlBox frame];
495     
496     if (isFullScreen)
497     {
498         mouseLoc = [fFullScreenWindow mouseLocationOutsideOfEventStream];
499         [fScaleToScreenToggleButton setHidden:NO];
500     }
501     else
502     {
503         mouseLoc = [fPreviewWindow mouseLocationOutsideOfEventStream];
504         [fScaleToScreenToggleButton setHidden:YES];
505     }
506     
507     /* if the pointer is inside the picture view areas but not
508      * in the controlbox, check the hudTimerSeconds to see if
509      * its in the allowable time span
510      */
511     if ( hudTimerSeconds > 0 && hudTimerSeconds < 20)
512     {
513         
514         if (isEncoding == NO)
515         {
516             if (NSPointInRect (mouseLoc, controlBoxFrame))
517             {
518                 /* Mouse is over the preview area so show hud controls so just
519                  * reset the timer to keep the control box visible
520                 */
521                 [fPictureControlBox setHidden: NO];
522                 hudTimerSeconds = 1;
523                 return;
524             }
525             /* Re-verify we are within the target frame */
526             if (NSPointInRect (mouseLoc, targetFrame))
527             {
528                 /* Mouse is over the preview area so show hud controls */
529                 [[fPictureControlBox animator] setHidden: NO];
530                 /* increment our timer by one */
531                 hudTimerSeconds ++;
532             }
533             else
534             {
535                 [[fPictureControlBox animator] setHidden: YES];
536                 [self stopHudTimer];
537             }
538         }
539         
540     }
541     else
542     {
543         [[fPictureControlBox animator] setHidden: YES];
544         [self stopHudTimer];
545     }
546     
547 }
548
549
550 #pragma mark Fullscreen Mode
551
552 - (IBAction)toggleScreenMode:(id)sender
553 {
554     if (!isFullScreen)
555     {
556         [self goFullScreen:nil];
557     }
558     else
559     {
560         [self goWindowedScreen:nil];
561     }
562 }
563
564 - (IBAction)toggleScaleToScreen:(id)sender
565 {
566     if (scaleToScreen == YES)
567     {
568         scaleToScreen = NO;
569         /* make sure we are set to a still preview */
570         [self pictureSliderChanged:nil];
571         [fScaleToScreenToggleButton setTitle:@"<->"];
572     }
573     else
574     {
575         scaleToScreen = YES;
576         /* make sure we are set to a still preview */
577         [self pictureSliderChanged:nil];
578         [fScaleToScreenToggleButton setTitle:@">-<"];
579     }
580 }
581
582 - (BOOL)fullScreen
583 {
584     return isFullScreen;
585 }
586
587 - (IBAction)goFullScreen:(id)sender 
588
589     // Get the screen information. 
590     NSScreen* mainScreen = [fPreviewWindow screen];
591     NSDictionary* screenInfo = [mainScreen deviceDescription]; 
592     NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"]; 
593     // Capture the screen. 
594     CGDirectDisplayID displayID = (CGDirectDisplayID)[screenID longValue]; 
595     CGDisplayErr err = CGDisplayCapture(displayID); 
596     
597     if (err == CGDisplayNoErr) 
598     { 
599         
600         /* make sure we are set to a still preview and not scaled to screen */
601         scaleToScreen = NO;
602         [self pictureSliderChanged:nil];
603         
604         // Create the full-screen window. 
605         //NSRect winRect = [mainScreen frame];
606         //fPictureViewArea
607         NSRect winRect = [fPictureViewArea frame];
608           
609         fFullScreenWindow = [[NSWindow alloc] initWithContentRect:winRect 
610                                                         styleMask:NSBorderlessWindowMask 
611                                                           backing:NSBackingStoreBuffered 
612                                                             defer:NO 
613                                                            screen:mainScreen]; 
614         
615         // Establish the window attributes. 
616         [fFullScreenWindow setReleasedWhenClosed:NO]; 
617         [fFullScreenWindow setDisplaysWhenScreenProfileChanges:YES]; 
618         [fFullScreenWindow setDelegate:self]; 
619         
620         /* insert a view into the new window */
621         [fFullScreenWindow setContentView:fPictureViewArea]; 
622         [fPictureViewArea setNeedsDisplay:YES];
623         
624         /* Better to center the window using the screen's frame
625          * and the windows origin. Note that we should take into
626          * account the auto sizing and alignment that occurs in 
627          * setViewSize each time the preview changes.
628          * Note: by using [fFullScreenWindow screen] (instead of
629          * [NSScreen mainScreen]) in referencing the screen
630          * coordinates, the full screen window will show up on
631          * whichever display was being used in windowed mode
632          * on multi-display systems
633          */
634         
635         NSSize screenSize = [[fFullScreenWindow screen] frame].size;
636         NSSize windowSize = [fFullScreenWindow frame].size;
637         NSPoint windowOrigin = [fFullScreenWindow frame].origin;
638         
639         /* Adjust our origin y (vertical) based on the screen height */
640         windowOrigin.y += (screenSize.height - windowSize.height) / 2.0;
641         windowOrigin.x += (screenSize.width - windowSize.width) / 2.0;
642         
643         [fFullScreenWindow setFrameOrigin:windowOrigin];
644         
645         /* lets kill the timer for now */
646         [self stopReceivingLibhbNotifications];
647         
648         /* We need to retain the fPreviewWindow */
649         [fPreviewWindow retain];
650         
651         [self setWindow:fFullScreenWindow];
652         
653         // The window has to be above the level of the shield window.
654         int32_t shieldLevel = CGShieldingWindowLevel(); 
655         
656         [fFullScreenWindow setLevel:shieldLevel]; 
657         
658         // Show the window. 
659         [fFullScreenWindow makeKeyAndOrderFront:self];
660         
661         
662         /* Change the name of fFullScreenToggleButton appropriately */
663         [fFullScreenToggleButton setTitle: @"Windowed"];
664         
665         /* Lets fire the timer back up for the hud controls, etc. */
666         [self startReceivingLibhbNotifications];
667         
668         isFullScreen = YES;
669         [fScaleToScreenToggleButton setHidden:NO];
670         
671         /* make sure we are set to a still preview */
672         [self pictureSliderChanged:nil];
673         
674         [fFullScreenWindow setAcceptsMouseMovedEvents:YES];
675         
676         
677         hudTimerSeconds = 0;
678         [self startHudTimer];
679     } 
680
681
682 // Title-less windows normally don't receive key presses, override this
683 - (BOOL)canBecomeKeyWindow
684 {
685     return YES;
686 }
687
688 // Title-less windows normally can't become main which means that another
689 // non-fullscreen window will have the "active" titlebar in expose. Bad, fix it.
690 - (BOOL)canBecomeMainWindow
691 {
692     return YES;
693 }
694
695
696 - (IBAction)goWindowedScreen:(id)sender
697 {
698     
699     /* Get the screen info to release the display but don't actually do
700      * it until the windowed screen is setup.
701      */
702     scaleToScreen = NO;
703     [self pictureSliderChanged:nil];
704     [fScaleToScreenToggleButton setTitle:@"<->"];
705         
706     NSScreen* mainScreen = [NSScreen mainScreen]; 
707     NSDictionary* screenInfo = [mainScreen deviceDescription]; 
708     NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"];
709     CGDirectDisplayID displayID = (CGDirectDisplayID)[screenID longValue]; 
710     
711     [fFullScreenWindow dealloc];
712     [fFullScreenWindow release];
713     
714     
715     [fPreviewWindow setContentView:fPictureViewArea]; 
716     [fPictureViewArea setNeedsDisplay:YES];
717     [self setWindow:fPreviewWindow];
718     
719     // Show the window. 
720     [fPreviewWindow makeKeyAndOrderFront:self];
721     
722     /* Set the window back to regular level */
723     [fPreviewWindow setLevel:NSNormalWindowLevel];
724     
725     /* Set the isFullScreen flag back to NO */
726     isFullScreen = NO;
727     scaleToScreen = NO;
728     /* make sure we are set to a still preview */
729     [self pictureSliderChanged:nil];
730     [self showPreviewWindow:nil];
731     
732     /* Change the name of fFullScreenToggleButton appropriately */
733     [fFullScreenToggleButton setTitle: @"Full Screen"];
734     // [fScaleToScreenToggleButton setHidden:YES];
735     /* set the picture settings pallete back to normal level */
736     [fHBController picturePanelWindowed];
737     
738     /* Release the display now that the we are back in windowed mode */
739     CGDisplayRelease(displayID);
740     
741     [fPreviewWindow setAcceptsMouseMovedEvents:YES];
742     //[fFullScreenWindow setAcceptsMouseMovedEvents:NO];
743     
744     hudTimerSeconds = 0;
745     [self startHudTimer];
746     
747 }
748
749
750 #pragma mark Still Preview Image Processing
751
752
753 // This function converts an image created by libhb (specified via pictureIndex) into
754 // an NSImage suitable for the GUI code to use. If removeBorders is YES,
755 // makeImageForPicture crops the image generated by libhb stripping off the gray
756 // border around the content. This is the low-level method that generates the image.
757 // -imageForPicture calls this function whenever it can't find an image in its cache.
758 + (NSImage *) makeImageForPicture: (int)pictureIndex
759                 libhb:(hb_handle_t*)handle
760                 title:(hb_title_t*)title
761 {
762     static uint8_t * buffer;
763     static int bufferSize;
764
765     // Make sure we have a big enough buffer to receive the image from libhb. libhb
766     int dstWidth = title->job->width;
767     int dstHeight = title->job->height;
768         
769     int newSize;
770     newSize = dstWidth * dstHeight * 4;
771     if( bufferSize < newSize )
772     {
773         bufferSize = newSize;
774         buffer     = (uint8_t *) realloc( buffer, bufferSize );
775     }
776
777     hb_get_preview( handle, title, pictureIndex, buffer );
778
779     // Create an NSBitmapImageRep and copy the libhb image into it, converting it from
780     // libhb's format to one suitable for NSImage. Along the way, we'll strip off the
781     // border around libhb's image.
782         
783     // The image data returned by hb_get_preview is 4 bytes per pixel, BGRA format.
784     // Alpha is ignored.
785         
786     NSBitmapFormat bitmapFormat = (NSBitmapFormat)NSAlphaFirstBitmapFormat;
787     NSBitmapImageRep * imgrep = [[[NSBitmapImageRep alloc]
788             initWithBitmapDataPlanes:nil
789             pixelsWide:dstWidth
790             pixelsHigh:dstHeight
791             bitsPerSample:8
792             samplesPerPixel:3   // ignore alpha
793             hasAlpha:NO
794             isPlanar:NO
795             colorSpaceName:NSCalibratedRGBColorSpace
796             bitmapFormat:bitmapFormat
797             bytesPerRow:dstWidth * 4
798             bitsPerPixel:32] autorelease];
799
800     UInt32 * src = (UInt32 *)buffer;
801     UInt32 * dst = (UInt32 *)[imgrep bitmapData];
802     for (int r = 0; r < dstHeight; r++)
803     {
804         for (int c = 0; c < dstWidth; c++)
805 #if TARGET_RT_LITTLE_ENDIAN
806             *dst++ = Endian32_Swap(*src++);
807 #else
808             *dst++ = *src++;
809 #endif
810     }
811
812     NSImage * img = [[[NSImage alloc] initWithSize: NSMakeSize(dstWidth, dstHeight)] autorelease];
813     [img addRepresentation:imgrep];
814
815     return img;
816 }
817
818 // Returns the preview image for the specified index, retrieving it from its internal
819 // cache or by calling makeImageForPicture if it is not cached. Generally, you should
820 // use imageForPicture so that images are cached. Calling makeImageForPicture will
821 // always generate a new copy of the image.
822 - (NSImage *) imageForPicture: (int) pictureIndex
823 {
824     // The preview for the specified index may not currently exist, so this method
825     // generates it if necessary.
826     NSString * key = [NSString stringWithFormat:@"%d", pictureIndex];
827     NSImage * theImage = [fPicturePreviews objectForKey:key];
828     if (!theImage)
829     {
830         theImage = [PreviewController makeImageForPicture:pictureIndex libhb:fHandle title:fTitle];
831         [fPicturePreviews setObject:theImage forKey:key];
832     }
833     return theImage;
834 }
835
836 // Purges all images from the cache. The next call to imageForPicture will cause a new
837 // image to be generated.
838 - (void) purgeImageCache
839 {
840     [fPicturePreviews removeAllObjects];
841 }
842
843  
844
845 #pragma mark Movie Preview
846 - (IBAction) createMoviePreview: (id) sender
847 {
848     
849     
850     /* Lets make sure the still picture previews are showing in case
851      * there is currently a movie showing */
852     [self pictureSliderChanged:nil];
853     
854     /* Rip or Cancel ? */
855     hb_state_t s;
856     hb_get_state2( fPreviewLibhb, &s );
857     
858     if(sender == fCancelPreviewMovieButton && (s.state == HB_STATE_WORKING || s.state == HB_STATE_PAUSED))
859         {
860         
861         play_movie = NO;
862         hb_stop( fPreviewLibhb );
863         [fPictureView setHidden:NO];
864         [fMovieView pause:nil];
865         [fMovieView setHidden:YES];
866         [fPictureSlider setHidden:NO];
867         isEncoding = NO;
868         
869         return;
870     }
871     
872     
873     /* we use controller.mm's prepareJobForPreview to go ahead and set all of our settings
874      * however, we want to use a temporary destination field of course
875      * so that we do not put our temp preview in the users chosen
876      * directory */
877     
878     hb_job_t * job = fTitle->job;
879     
880     /* We run our current setting through prepeareJob in Controller.mm
881      * just as if it were a regular encode */
882     
883     [fHBController prepareJobForPreview];
884     
885     /* Destination file. We set this to our preview directory
886      * changing the extension appropriately.*/
887     if (fTitle->job->mux == HB_MUX_MP4) // MP4 file
888     {
889         /* we use .m4v for our mp4 files so that ac3 and chapters in mp4 will play properly */
890         fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.m4v";
891     }
892     else if (fTitle->job->mux == HB_MUX_MKV) // MKV file
893     {
894         fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.mkv";
895     }
896     else if (fTitle->job->mux == HB_MUX_AVI) // AVI file
897     {
898         fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.avi";
899     }
900     else if (fTitle->job->mux == HB_MUX_OGM) // OGM file
901     {
902         fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.ogm";
903     }
904     
905     fPreviewMoviePath = [[fPreviewMoviePath stringByExpandingTildeInPath]retain];
906     
907     /* See if there is an existing preview file, if so, delete it */
908     if( ![[NSFileManager defaultManager] fileExistsAtPath:fPreviewMoviePath] )
909     {
910         [[NSFileManager defaultManager] removeFileAtPath:fPreviewMoviePath
911                                                  handler:nil];
912     }
913     
914     /* We now direct our preview encode to fPreviewMoviePath */
915     fTitle->job->file = [fPreviewMoviePath UTF8String];
916     
917     /* We use our advance pref to determine how many previews to scan */
918     int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue];
919     job->start_at_preview = fPicture + 1;
920     job->seek_points = hb_num_previews;
921     
922     /* we use the preview duration popup to get the specified
923      * number of seconds for the preview encode.
924      */
925     
926     job->pts_to_stop = [[fPreviewMovieLengthPopUp titleOfSelectedItem] intValue] * 90000LL;
927     
928     /* lets go ahead and send it off to libhb
929      * Note: unlike a full encode, we only send 1 pass regardless if the final encode calls for 2 passes.
930      * this should suffice for a fairly accurate short preview and cuts our preview generation time in half.
931      * However we also need to take into account the indepth scan for subtitles.
932      */
933     /*
934      * If scanning we need to do some extra setup of the job.
935      */
936     if( job->indepth_scan == 1 )
937     {
938         char *x264opts_tmp;
939         
940         /*
941          * When subtitle scan is enabled do a fast pre-scan job
942          * which will determine which subtitles to enable, if any.
943          */
944         job->pass = -1;
945         x264opts_tmp = job->x264opts;
946         
947         job->x264opts = NULL;
948         job->indepth_scan = 1;  
949         /*
950          * Add the pre-scan job
951          */
952         hb_add( fPreviewLibhb, job );
953         job->x264opts = x264opts_tmp;
954     }                  
955     /* Go ahead and perform the actual encoding preview scan */
956     job->indepth_scan = 0;
957     job->pass = 0;
958     hb_add( fPreviewLibhb, job );
959     
960     [fEncodingControlBox setHidden: NO];
961     [fPictureControlBox setHidden: YES];
962     
963     [fMovieCreationProgressIndicator setHidden: NO];
964     [fPreviewMovieStatusField setHidden: NO];
965     
966     isEncoding = YES;
967     
968     play_movie = YES;
969     
970     /* Let fPreviewLibhb do the job */
971     hb_start( fPreviewLibhb );
972         
973 }
974
975 - (void) startReceivingLibhbNotifications
976 {
977     if (!fLibhbTimer)
978     {
979         fLibhbTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(libhbTimerFired:) userInfo:nil repeats:YES];
980         [fLibhbTimer retain];
981     }
982 }
983
984 - (void) stopReceivingLibhbNotifications
985 {
986     if (fLibhbTimer)
987     {
988         [fLibhbTimer invalidate];
989         [fLibhbTimer release];
990         fLibhbTimer = nil;
991     }
992 }
993 - (void) libhbTimerFired: (NSTimer*)theTimer
994 {
995     hb_state_t s;
996     hb_get_state( fPreviewLibhb, &s );
997     [self libhbStateChanged: s];
998     
999 }
1000
1001 - (void) libhbStateChanged: (hb_state_t &)state
1002 {
1003     switch( state.state )
1004     {
1005         case HB_STATE_IDLE:
1006         case HB_STATE_SCANNING:
1007         case HB_STATE_SCANDONE:
1008             break;
1009             
1010         case HB_STATE_WORKING:
1011         {
1012 #define p state.param.working
1013             
1014             NSMutableString * string;
1015                         /* Update text field */
1016                         string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding preview:  %.2f %%", @"" ), 100.0 * p.progress];
1017             
1018                         if( p.seconds > -1 )
1019             {
1020                 [string appendFormat:
1021                  NSLocalizedString( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", @"" ),
1022                  p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
1023             }
1024             [fPreviewMovieStatusField setStringValue: string];
1025             
1026             [fMovieCreationProgressIndicator setIndeterminate: NO];
1027             /* Update slider */
1028                         [fMovieCreationProgressIndicator setDoubleValue: 100.0 * p.progress];
1029             
1030             [fCreatePreviewMovieButton setTitle: @"Cancel Preview"];
1031             
1032             break;
1033             
1034         }
1035 #undef p
1036             
1037 #define p state.param.muxing            
1038         case HB_STATE_MUXING:
1039         {
1040             // Update fMovieCreationProgressIndicator
1041             [fMovieCreationProgressIndicator setIndeterminate: YES];
1042             [fMovieCreationProgressIndicator startAnimation: nil];
1043             [fPreviewMovieStatusField setStringValue: [NSString stringWithFormat:
1044                                          NSLocalizedString( @"Muxing Preview ...", @"" )]];
1045             break;
1046         }
1047 #undef p                        
1048         case HB_STATE_PAUSED:
1049             [fMovieCreationProgressIndicator stopAnimation: nil];
1050             break;
1051                         
1052         case HB_STATE_WORKDONE:
1053         {
1054             // Delete all remaining jobs since libhb doesn't do this on its own.
1055             hb_job_t * job;
1056             while( ( job = hb_job(fPreviewLibhb, 0) ) )
1057                 hb_rem( fHandle, job );
1058             
1059             [fPreviewMovieStatusField setStringValue: @""];
1060             [fPreviewMovieStatusField setHidden: YES];
1061             
1062             [fMovieCreationProgressIndicator stopAnimation: nil];
1063             [fMovieCreationProgressIndicator setHidden: YES];
1064             [fEncodingControlBox setHidden: YES];
1065             isEncoding = NO;
1066             /* we make sure the picture slider and preview match */
1067             [self pictureSliderChanged:nil];
1068             
1069             
1070             // Show the movie view
1071             if (play_movie)
1072             {
1073             [self showMoviePreview:fPreviewMoviePath];
1074             }
1075             
1076             [fCreatePreviewMovieButton setTitle: @"Live Preview"];
1077             
1078             
1079             break;
1080         }
1081     }
1082         
1083 }
1084
1085 - (IBAction) showMoviePreview: (NSString *) path
1086 {
1087     /* Since the gray background for the still images is part of
1088      * fPictureView, lets leave the picture view visible and postion
1089      * the fMovieView over the image portion of fPictureView so
1090      * we retain the gray cropping border  we have already established
1091      * with the still previews
1092      */
1093     [fMovieView setHidden:NO];
1094     
1095     /* Load the new movie into fMovieView */
1096     QTMovie * aMovie;
1097     NSRect movieBounds;
1098     if (path)
1099     {
1100         [fMovieView setControllerVisible: YES];
1101         /* let's make sure there is no movie currently set */
1102         [fMovieView setMovie:nil];
1103         
1104         aMovie = [QTMovie movieWithFile:path error:nil];
1105
1106         /* we get some size information from the preview movie */
1107         NSSize movieSize= [[aMovie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
1108         movieBounds = [fMovieView movieBounds];
1109         movieBounds.size.height = movieSize.height;
1110
1111         if ([fMovieView isControllerVisible])
1112             movieBounds.size.height += [fMovieView controllerBarHeight];
1113         /* since for whatever the reason I cannot seem to get the [fMovieView controllerBarHeight]
1114          * For now just use 15 for additional height as it seems to line up well
1115          */
1116         movieBounds.size.height += 15;
1117
1118         movieBounds.size.width = movieSize.width;
1119
1120         /* We need to find out if the preview movie needs to be scaled down so
1121          * that it doesn't overflow our available viewing container (just like for image
1122          * in -displayPreview) for HD sources, etc. [fPictureViewArea frame].size.height*/
1123         if( ((int)movieBounds.size.height) > [fPictureViewArea frame].size.height || scaleToScreen == YES)
1124         {
1125             /* The preview movie would be larger than the available viewing area
1126              * in the preview movie, so we go ahead and scale it down to the same size
1127              * as the still preview  or we readjust our window to allow for the added height if need be
1128              */
1129             NSSize displaySize = NSMakeSize( (float)movieBounds.size.width, (float)movieBounds.size.height );
1130             NSSize viewSize = [self optimalViewSizeForImageSize:displaySize];
1131             if( [self viewNeedsToResizeToSize:viewSize] )
1132             {
1133                 
1134                 [self resizeSheetForViewSize:viewSize];
1135                 [self setViewSize:viewSize];
1136                 
1137             }
1138             
1139             [fMovieView setPreservesAspectRatio:YES];
1140             [fMovieView setFrameSize:viewSize];
1141         }
1142         else
1143         {
1144             /* Since the preview movie is smaller than the available viewing area
1145              * we can go ahead and use the preview movies native size */
1146             [fMovieView setFrameSize:movieBounds.size];
1147
1148         }
1149         
1150
1151         
1152
1153         // lets reposition the movie if need be
1154         
1155         NSPoint origin = [fPictureViewArea frame].origin;
1156         origin.x += trunc(([fPictureViewArea frame].size.width -
1157                            [fMovieView frame].size.width) / 2.0);
1158         /* We need to detect whether or not we are currently less than the available height.*/
1159         if (movieBounds.size.height < [fPictureView frame].size.height)
1160         {
1161         /* If we are, we are adding 15 to the height to allow for the controller bar so
1162          * we need to subtract half of that for the origin.y to get the controller bar
1163          * below the movie to it lines up vertically with where our still preview was
1164          */
1165         origin.y += trunc((([fPictureViewArea frame].size.height -
1166                             [fMovieView frame].size.height) / 2.0) - 7.5);
1167         }
1168         else
1169         {
1170         /* if we are >= to the height of the picture view area, the controller bar
1171          * gets taken care of with picture resizing, so we do not want to offset the height
1172          */
1173         origin.y += trunc(([fPictureViewArea frame].size.height -
1174                             [fMovieView frame].size.height) / 2.0);
1175         }
1176         [fMovieView setFrameOrigin:origin]; 
1177         
1178         [fMovieView setMovie:aMovie];
1179         /// to actually play the movie
1180         [fMovieView play:aMovie];
1181     }
1182     else
1183     {
1184         aMovie = nil;
1185     }       
1186     isEncoding = NO;
1187 }
1188
1189
1190 @end
1191
1192 @implementation PreviewController (Private)
1193
1194 //
1195 // -[PictureController(Private) optimalViewSizeForImageSize:]
1196 //
1197 // Given the size of the preview image to be shown, returns the best possible
1198 // size for the view.
1199 //
1200 - (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize
1201 {
1202     // The min size is 320x240
1203     CGFloat minWidth = 480.0;
1204     CGFloat minHeight = 360.0;
1205
1206     NSSize screenSize = [[NSScreen mainScreen] frame].size;
1207     NSSize sheetSize = [[self window] frame].size;
1208     NSSize viewAreaSize = [fPictureViewArea frame].size;
1209     CGFloat paddingX = sheetSize.width - viewAreaSize.width;
1210     CGFloat paddingY = sheetSize.height - viewAreaSize.height;
1211     CGFloat maxWidth;
1212     CGFloat maxHeight;
1213     
1214     if (isFullScreen)
1215     {
1216         /* We are in full screen mode so lets use the full screen if we need to */
1217         maxWidth =  screenSize.width - paddingX;
1218         maxHeight = screenSize.height - paddingY;
1219     }
1220     else
1221     {
1222         // The max size of the view is when the sheet is taking up 85% of the screen.
1223         maxWidth = (0.85 * screenSize.width) - paddingX;
1224         maxHeight = (0.85 * screenSize.height) - paddingY;
1225     }
1226     
1227     NSSize resultSize = imageSize;
1228     
1229     // Its better to have a view that's too small than a view that's too big, so
1230     // apply the maximum constraints last.
1231     if( resultSize.width < minWidth )
1232     {
1233         resultSize.height *= (minWidth / resultSize.width);
1234         resultSize.width = minWidth;
1235     }
1236     if( resultSize.height < minHeight )
1237     {
1238         resultSize.width *= (minHeight / resultSize.height);
1239         resultSize.height = minHeight;
1240     }
1241     if( resultSize.width > maxWidth )
1242     {
1243         resultSize.height *= (maxWidth / resultSize.width);
1244         resultSize.width = maxWidth;
1245     }
1246     if( resultSize.height > maxHeight )
1247     {
1248         resultSize.width *= (maxHeight / resultSize.height);
1249         resultSize.height = maxHeight;
1250     }
1251     
1252     if (scaleToScreen == YES)
1253     {
1254         CGFloat screenAspect;
1255         CGFloat viewAreaAspect; 
1256         //note, a mbp 15" at 1440 x 900 is a 1.6 ar
1257         screenAspect = screenSize.width / screenSize.height;
1258         
1259         // Note, a standard dvd will use 720 x 480 which is a 1.5
1260         viewAreaAspect = viewAreaSize.width / viewAreaSize.height;
1261         
1262         if (screenAspect < viewAreaAspect)
1263         {
1264             resultSize.width = screenSize.width;
1265             resultSize.height = (screenSize.width / viewAreaAspect);
1266         }
1267         else
1268         {
1269             resultSize.height = screenSize.height;
1270             resultSize.width = resultSize.height * viewAreaAspect;
1271         }
1272         
1273     }
1274
1275       return resultSize;
1276
1277     
1278 }
1279
1280 //
1281 // -[PictureController(Private) resizePanelForViewSize:animate:]
1282 //
1283 // Resizes the entire window to accomodate a view of a particular size.
1284 //
1285 - (void)resizeSheetForViewSize: (NSSize)viewSize
1286 {
1287     // Figure out the deltas for the new frame area
1288     NSSize currentSize = [fPictureViewArea frame].size;
1289     CGFloat deltaX = viewSize.width - currentSize.width;
1290     CGFloat deltaY = viewSize.height - currentSize.height;
1291     
1292     // Now resize the whole panel by those same deltas, but don't exceed the min
1293     NSRect frame = [[self window] frame];
1294     NSSize maxSize = [[self window] maxSize];
1295     NSSize minSize = [[self window] minSize];
1296     frame.size.width += deltaX;
1297     frame.size.height += deltaY;
1298     if( frame.size.width < minSize.width )
1299     {
1300         frame.size.width = minSize.width;
1301     }
1302     
1303     if( frame.size.height < minSize.height )
1304     {
1305         frame.size.height = minSize.height;
1306     }
1307     
1308     
1309     // But now the sheet is off-center, so also shift the origin to center it and
1310     // keep the top aligned.
1311     if( frame.size.width != [[self window] frame].size.width )
1312         frame.origin.x -= (deltaX / 2.0);
1313     
1314     if (isFullScreen)
1315     {
1316         if( frame.size.height != [[self window] frame].size.height )
1317         {
1318             frame.origin.y -= (deltaY / 2.0);
1319         }
1320         else
1321         {
1322             if( frame.size.height != [[self window] frame].size.height )
1323                 frame.origin.y -= deltaY;
1324         }
1325         
1326         [[self window] setFrame:frame display:YES animate:NO];
1327     }
1328     else
1329     {
1330         /* Since upon launch we can open up the preview window if it was open
1331          * the last time we quit (and at the size it was) we want to make
1332          * sure that upon resize we do not have the window off the screen
1333          * So check the origin against the screen origin and adjust if
1334          * necessary.
1335          */
1336         NSSize screenSize = [[[self window] screen] frame].size;
1337         NSPoint screenOrigin = [[[self window] screen] frame].origin;
1338         /* our origin is off the screen to the left*/
1339         if (frame.origin.x < screenOrigin.x)
1340         {
1341             /* so shift our origin to the right */
1342             frame.origin.x = screenOrigin.x;
1343         }
1344         else if ((frame.origin.x + frame.size.width) > (screenOrigin.x + screenSize.width))
1345         {
1346             /* the right side of the preview is off the screen, so shift to the left */
1347             frame.origin.x = (screenOrigin.x + screenSize.width) - frame.size.width;
1348         }
1349         
1350         [[self window] setFrame:frame display:YES animate:YES];
1351     }
1352     
1353 }
1354
1355 //
1356 // -[PictureController(Private) setViewSize:]
1357 //
1358 // Changes the view's size and centers it vertically inside of its area.
1359 // Assumes resizeSheetForViewSize: has already been called.
1360 //
1361 - (void)setViewSize: (NSSize)viewSize
1362 {   
1363     /* special case for scaleToScreen */
1364     if (scaleToScreen == YES)
1365     {
1366         /* for scaleToScreen, we expand the fPictureView to fit the entire screen */
1367         NSSize areaSize = [fPictureViewArea frame].size;
1368         CGFloat viewSizeAspect = viewSize.width / viewSize.height;
1369         if (viewSizeAspect > 1.0) // we are wider than taller, so expand the width to fill the area and scale the height
1370         {
1371             viewSize.width = areaSize.width;
1372             viewSize.height = viewSize.width / viewSizeAspect;
1373         }
1374         else
1375         {
1376             viewSize.height = areaSize.height;
1377             viewSize.width = viewSize.height * viewSizeAspect;
1378         }
1379         
1380     }
1381     
1382     [fPictureView setFrameSize:viewSize];
1383     
1384         // center it vertically and horizontally
1385     NSPoint origin = [fPictureViewArea frame].origin;
1386     origin.y += ([fPictureViewArea frame].size.height -
1387                  [fPictureView frame].size.height) / 2.0;
1388     
1389     origin.x += ([fPictureViewArea frame].size.width -
1390                  [fPictureView frame].size.width) / 2.0; 
1391     
1392     [fPictureView setFrameOrigin:origin];
1393     
1394     NSPoint controlboxorigin = [fPictureView frame].origin;
1395     
1396     /* for now, put the origin.y 100 above the bottom of the fPictureView */
1397     controlboxorigin.y += 100;
1398     
1399     controlboxorigin.x += ([fPictureViewArea frame].size.width -
1400                            [fPictureControlBox frame].size.width) / 2.0;
1401     
1402     
1403     /* origin should be rounded to integer otherwise font/antialiasing
1404      * may be blurry.
1405      */
1406     controlboxorigin.x = floor( controlboxorigin.x );
1407     controlboxorigin.y = floor( controlboxorigin.y );
1408     
1409     /* requires that thefPictureControlBox and the fEncodingControlBox
1410      * are the same width to line up.
1411      */
1412     [fPictureControlBox setFrameOrigin:controlboxorigin];
1413     [fEncodingControlBox setFrameOrigin:controlboxorigin];
1414     
1415 }
1416
1417
1418 - (BOOL)viewNeedsToResizeToSize: (NSSize)newSize
1419 {
1420     NSSize viewSize = [fPictureViewArea frame].size;
1421     return (newSize.width != viewSize.width || newSize.height != viewSize.height);
1422 }
1423
1424 @end