OSDN Git Service

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