OSDN Git Service

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