OSDN Git Service

import original 0.9.5 release
[handbrake-jp/handbrake-jp.git] / macosx / HBPreviewController.m
index 5397fe5..a4d8b84 100644 (file)
@@ -14,6 +14,8 @@
 }
 @end
 
+
+
 @interface PreviewController (Private)
 
 - (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize;
         int loggingLevel = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LoggingLevel"] intValue];
         fPreviewLibhb = hb_init(loggingLevel, 0);
         
+        
+
        }
        return self;
 }
 
 
-
 //------------------------------------------------------------------------------------
 // Displays and brings the picture window to the front
 //------------------------------------------------------------------------------------
@@ -83,7 +86,6 @@
     //[self pictureSliderChanged:nil];
     [self startReceivingLibhbNotifications];
     
-    isFullScreen = NO;
     hudTimerSeconds = 0;
     /* we set the progress indicator to not use threaded animation
      * as it causes a conflict with the qtmovieview's controllerbar
     // Show the picture view
     [fPictureView setHidden:NO];
     [fMovieView pause:nil];
+    [fMovieTimer invalidate];
+    [fMovieTimer release];
     [fMovieView setHidden:YES];
        [fMovieView setMovie:nil];
 
-    isFullScreen = NO;
     hudTimerSeconds = 0;
     [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"PreviewWindowIsOpen"];
 }
     hb_stop(fPreviewLibhb);
     if (fPreviewMoviePath)
     {
-        [[NSFileManager defaultManager] removeFileAtPath:fPreviewMoviePath handler:nil];
+        [[NSFileManager defaultManager] removeItemAtPath:fPreviewMoviePath error:nil];
         [fPreviewMoviePath release];
     }    
     
     [fHudTimer invalidate];
     [fHudTimer release];
     
+    [fMovieTimer invalidate];
+    [fMovieTimer release];
+    
     [fPicturePreviews release];
     [fFullScreenWindow release];
-
+    
+    hb_close(&fPreviewLibhb);
+    
+    [self removeMovieCallbacks];
+    
     [super dealloc];
 }
 
     fPicture = 0;
     MaxOutputWidth = title->width - job->crop[2] - job->crop[3];
     MaxOutputHeight = title->height - job->crop[0] - job->crop[1];
+    
     [self SettingsChanged: nil];
+
 }
 
 
 
 // Adjusts the window to draw the current picture (fPicture) adjusting its size as
 // necessary to display as much of the picture as possible.
-- (void) displayPreview
+- (void) displayPreview 
 {
     hb_job_t * job = fTitle->job;
     /* lets make sure that the still picture view is not hidden and that 
      * the movie preview is 
      */
+     aMovie = nil;
     [fMovieView pause:nil];
     [fMovieView setHidden:YES];
        [fMovieView setMovie:nil];
     [fMovieCreationProgressIndicator stopAnimation: nil];
     [fMovieCreationProgressIndicator setHidden: YES];
+    [fMoviePlaybackControlBox setHidden: YES];
+    if( fMovieTimer )
+    {
+        [self stopMovieTimer];
+    }
+    [fPictureControlBox setHidden: NO];
     
     [fPictureView setHidden:NO];
     
-    //[fHBController writeToActivityLog: "displayPreview called"];
-    
     NSImage *fPreviewImage = [self imageForPicture: fPicture];
     NSSize imageScaledSize = [fPreviewImage size];
     [fPictureView setImage: fPreviewImage];
                           @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Custom",
                           fTitle->width, fTitle->height, output_width, output_height, fTitle->job->anamorphic.dar_width, fTitle->job->anamorphic.dar_height];
         
-        displaySize.width = fTitle->job->anamorphic.dar_width + fTitle->job->crop[2] + fTitle->job->crop[3];
+        displaySize.width = fTitle->job->anamorphic.dar_width + fTitle->job->crop[2] + fTitle->job->crop[3] ;
         displaySize.height = fTitle->job->anamorphic.dar_height + fTitle->job->crop[0] + fTitle->job->crop[1];
         imageScaledSize.width = (int)fTitle->job->anamorphic.dar_width;
         imageScaledSize.height = (int)fTitle->job->height;   
         sizeInfoString = [NSString stringWithFormat:
                           @"Source: %dx%d, Output: %dx%d", fTitle->width, fTitle->height,
                           fTitle->job->width, fTitle->job->height];
-        
+       
         displaySize.width = fTitle->width;
         displaySize.height = fTitle->height;
         imageScaledSize.width = fTitle->job->width;
         imageScaledSize.height = fTitle->job->height;
     }
     
+    
+    
     NSSize viewSize = [self optimalViewSizeForImageSize:displaySize];
+    [self resizeSheetForViewSize:viewSize];
+
+    NSSize windowSize = [[self window] frame].size;    
     
-    /* Initially set our preview image here */
-    /*
     if (scaleToScreen == YES)
     {
-        viewSize.width = viewSize.width - (viewSize.width - imageScaledSize.width);
-        viewSize.height = viewSize.height - (viewSize.height - imageScaledSize.height);
-        [fPreviewImage setSize: viewSize];
-        //[fPictureView setFrameSize: viewSize];
+        /* Note: this should probably become a utility function */
+        /* We are in Scale To Screen mode so, we have to get the ratio for height and width against the window
+         *size so we can scale from there.
+         */
+        CGFloat deltaWidth = imageScaledSize.width / displaySize.width;
+        CGFloat deltaHeight = imageScaledSize.height /displaySize.height;
+        NSSize windowSize = [[self window] frame].size;  
+        CGFloat pictureAspectRatio = imageScaledSize.width / imageScaledSize.height;
+        
+        /* Set our min size to the storage size */
+        NSSize minSize;
+        minSize.width = fTitle->width;
+        minSize.height = fTitle->height;
+
+        /* Set delta's based on minimum size */
+        if (imageScaledSize.width <  minSize.width)
+        {
+            deltaWidth = imageScaledSize.width / minSize.width;
+        }
+        else
+        {
+            deltaWidth = 1.0;
+        }
+        
+        if (imageScaledSize.height <  minSize.height)
+        {
+            deltaHeight =  imageScaledSize.height / minSize.height;
+        }
+        else
+        {
+            deltaHeight = 1.0;
+        }
+        
+        /* Now apply our deltas to the full screen view */
+        if (pictureAspectRatio > 1.0) // we are wider than taller, so expand the width to fill the area and scale the height
+        {
+            viewSize.width = windowSize.width * deltaWidth;
+            viewSize.height = viewSize.width / pictureAspectRatio;
+            
+        }
+        else
+        {
+            viewSize.height = windowSize.height * deltaHeight; 
+            viewSize.width = viewSize.height * pictureAspectRatio;
+        }
+        
     }
-    
     else
     {
-        [fPreviewImage setSize: imageScaledSize];
-        [fPictureView setFrameSize: imageScaledSize];
-    }
-    [fPictureView setImage: fPreviewImage];
-    // center it vertically and horizontally
-    NSPoint origin = [fPictureViewArea frame].origin;
-    origin.y += ([fPictureViewArea frame].size.height -
-                 [fPictureView frame].size.height) / 2.0;
-    
-    origin.x += ([fPictureViewArea frame].size.width -
-                 [fPictureView frame].size.width) / 2.0;
-    [fPictureView setFrameOrigin:origin]; 
-    */
-    /* we also need to take into account scaling to full screen to activate switching the view size */
-    if( [self viewNeedsToResizeToSize:viewSize])
-    {
-        if (fTitle->job->anamorphic.mode != 2 || (fTitle->job->anamorphic.mode == 2 && fTitle->width == fTitle->job->width))
+        viewSize.width = viewSize.width - (viewSize.width - imageScaledSize.width);
+        viewSize.height = viewSize.height - (viewSize.height - imageScaledSize.height);
+        
+        if (fTitle->width > windowSize.width || fTitle->height > windowSize.height)
         {
-            [self resizeSheetForViewSize:viewSize];
-            //[self setViewSize:viewSize];
-            
+            CGFloat viewSizeAspect = viewSize.width / viewSize.height;
+            if (viewSizeAspect > 1.0) // we are wider than taller, so expand the width to fill the area and scale the height
+            {
+                viewSize.width = viewSize.width * (windowSize.width / fTitle->width) ;
+                viewSize.height = viewSize.width / viewSizeAspect;
+            }
+            else
+            {
+                viewSize.height = viewSize.height * (windowSize.height / fTitle->height);
+                viewSize.width = viewSize.height * viewSizeAspect;
+            }
         }
-    }   
+        
+    }
     
-    viewSize.width = viewSize.width - (viewSize.width - imageScaledSize.width);
-    viewSize.height = viewSize.height - (viewSize.height - imageScaledSize.height);
     [self setViewSize:viewSize];
     
-    /* special case for scaleToScreen */
-    if (scaleToScreen == YES)
-    {
-        [fPreviewImage setSize: viewSize];
-        [fPictureView setImage: fPreviewImage];
-    }
-    
+    /* relocate our hud origins as per setViewSize */
+    NSPoint hudControlBoxOrigin = [fPictureControlBox frame].origin;
+    hudControlBoxOrigin.y = ([[self window] frame].size.height / 2) - (viewSize.height / 2);
+    hudControlBoxOrigin.x = ([[self window] frame].size.width / 2) - ([fPictureControlBox frame].size.width / 2);
+    [fPictureControlBox setFrameOrigin:hudControlBoxOrigin];
+    [fEncodingControlBox setFrameOrigin:hudControlBoxOrigin];
+    [fMoviePlaybackControlBox setFrameOrigin:hudControlBoxOrigin];
+
+
     NSString *scaleString;
-    
-    if( imageScaledSize.height > [fPictureView frame].size.height)
+    CGFloat scale = ( ( CGFloat )[fPictureView frame].size.width) / ( ( CGFloat )imageScaledSize.width);
+    if (scale * 100.0 != 100)
     {
-        CGFloat scale = ( ( CGFloat )[fPictureView frame].size.width) / ( ( CGFloat )imageScaledSize.width);        
         scaleString = [NSString stringWithFormat:
-                       NSLocalizedString( @" (Scaled to %.0f%% actual size)",
+                       NSLocalizedString( @" (%.0f%% actual size)",
                                          @"String shown when a preview is scaled" ), scale * 100.0];
     }
     else
     {
-        scaleString = @"";
+        scaleString = @"(Actual size)";
+    }
+    
+    if (scaleToScreen == YES)
+    {
+        scaleString = [scaleString stringByAppendingString:@" Scaled To Screen"];
     }
     /* Set the info fields in the hud controller */
     [fInfoField setStringValue: [NSString stringWithFormat:
         [self showWindow:sender];
         [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PreviewWindowIsOpen"];
         [fPreviewWindow setAcceptsMouseMovedEvents:YES];
-        isFullScreen = NO;
         scaleToScreen = NO;
         [self pictureSliderChanged:nil];
     }
 }
 
 #pragma mark Hud Control Overlay
+/* enableHudControls and disableHudControls are used to sync enableUI
+ * in HBController so that during a scan we do not attempt to access source
+ * images, etc. which can cause a crash. In general this ui behavior will mirror
+ * the main window ui's enableUI method and in fact is called from there */
+- (void) enableHudControls
+{
+    [fPictureSlider setEnabled:YES];
+    [fScaleToScreenToggleButton setEnabled:YES];
+    [fCreatePreviewMovieButton setEnabled:YES];
+    [fGoToStillPreviewButton setEnabled:YES];
+    [fHBController writeToActivityLog: "Preview: Enabling HUD Controls"];
+}
+
+- (void) disableHudControls
+{
+    [fPictureSlider setEnabled:NO];
+    [fScaleToScreenToggleButton setEnabled:NO];
+    [fCreatePreviewMovieButton setEnabled:NO];
+    [fGoToStillPreviewButton setEnabled:NO];
+    [fHBController writeToActivityLog: "Preview: Disabling HUD Controls"];
+}
+
 - (void) mouseMoved:(NSEvent *)theEvent
 {
     [super mouseMoved:theEvent];
     NSPoint mouseLoc = [theEvent locationInWindow];
     
     /* Test for mouse location to show/hide hud controls */
-    if( isEncoding == NO ) {
+    if( isEncoding == NO ) 
+    {
+        /* Since we are not encoding, verify which control hud to show
+         * or hide based on aMovie ( aMovie indicates we need movie controls )
+         */
+        NSBox           * hudBoxToShow;
+        if ( aMovie == nil ) // No movie loaded up
+        {
+            hudBoxToShow = fPictureControlBox;
+        }
+        else // We have a movie
+        {
+            hudBoxToShow = fMoviePlaybackControlBox;
+        }
+        
         if( NSPointInRect( mouseLoc, [fPictureControlBox frame] ) )
         {
-            [[fPictureControlBox animator] setHidden: NO];
+            [[hudBoxToShow animator] setHidden: NO];
             [self stopHudTimer];
         }
                else if( NSPointInRect( mouseLoc, [fPictureViewArea frame] ) )
         {
-            [[fPictureControlBox animator] setHidden: NO];
+            [[hudBoxToShow animator] setHidden: NO];
             [self startHudTimer];
         }
         else
-            [[fPictureControlBox animator] setHidden: YES];
+        {
+            [[hudBoxToShow animator] setHidden: YES];
+        }
        }
 }
 
 - (void) hudTimerFired: (NSTimer*)theTimer
 {
     hudTimerSeconds++;
-    if( hudTimerSeconds >= 10 ) {
+    if( hudTimerSeconds >= 10 ) 
+    {
+        /* Regardless which control box is active, after the timer
+         * period we want either one to fade to hidden.
+         */
         [[fPictureControlBox animator] setHidden: YES];
+        [[fMoviePlaybackControlBox animator] setHidden: YES];
         [self stopHudTimer];
     }
 }
 
-#pragma mark Fullscreen Mode
 
-- (IBAction)toggleScreenMode:(id)sender
-{
-    if (!isFullScreen)
-    {
-        [self goFullScreen:nil];
-    }
-    else
-    {
-        [self goWindowedScreen:nil];
-    }
-}
 
 - (IBAction)toggleScaleToScreen:(id)sender
 {
         scaleToScreen = NO;
         /* make sure we are set to a still preview */
         [self pictureSliderChanged:nil];
-        [fScaleToScreenToggleButton setTitle:@"<->"];
+        [fScaleToScreenToggleButton setTitle:@"Scale To Screen"];
     }
     else
     {
         scaleToScreen = YES;
         /* make sure we are set to a still preview */
         [self pictureSliderChanged:nil];
-        [fScaleToScreenToggleButton setTitle:@">-<"];
+        [fScaleToScreenToggleButton setTitle:@"Actual Scale"];
     }
+    
 }
 
-- (BOOL)fullScreen
-{
-    return isFullScreen;
-}
 
-- (IBAction)goFullScreen:(id)sender 
-{ 
-    // Get the screen information. 
-    NSScreen* mainScreen = [fPreviewWindow screen];
-    NSDictionary* screenInfo = [mainScreen deviceDescription]; 
-    NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"]; 
-    // Capture the screen. 
-    CGDirectDisplayID displayID = (CGDirectDisplayID)[screenID longValue]; 
-    CGDisplayErr err = CGDisplayCapture(displayID); 
-    
-    if (err == CGDisplayNoErr) 
-    { 
-        
-        /* make sure we are set to a still preview and not scaled to screen */
-        scaleToScreen = NO;
-        [self pictureSliderChanged:nil];
-        
-        // Create the full-screen window. 
-        //NSRect winRect = [mainScreen frame];
-        //fPictureViewArea
-        NSRect winRect = [fPictureViewArea frame];
-          
-        fFullScreenWindow = [[NSWindow alloc] initWithContentRect:winRect 
-                                                        styleMask:NSBorderlessWindowMask 
-                                                          backing:NSBackingStoreBuffered 
-                                                            defer:NO 
-                                                           screen:mainScreen]; 
-        
-        // Establish the window attributes. 
-        [fFullScreenWindow setReleasedWhenClosed:NO]; 
-        [fFullScreenWindow setDisplaysWhenScreenProfileChanges:YES]; 
-        [fFullScreenWindow setDelegate:self]; 
-        
-        /* insert a view into the new window */
-        [fFullScreenWindow setContentView:fPictureViewArea]; 
-        [fPictureViewArea setNeedsDisplay:YES];
-        
-        /* Better to center the window using the screen's frame
-         * and the windows origin. Note that we should take into
-         * account the auto sizing and alignment that occurs in 
-         * setViewSize each time the preview changes.
-         * Note: by using [fFullScreenWindow screen] (instead of
-         * [NSScreen mainScreen]) in referencing the screen
-         * coordinates, the full screen window will show up on
-         * whichever display was being used in windowed mode
-         * on multi-display systems
-         */
-        
-        NSSize screenSize = [[fFullScreenWindow screen] frame].size;
-        NSSize windowSize = [fFullScreenWindow frame].size;
-        NSPoint windowOrigin = [fFullScreenWindow frame].origin;
-        
-        /* Adjust our origin y (vertical) based on the screen height */
-        windowOrigin.y += (screenSize.height - windowSize.height) / 2.0;
-        windowOrigin.x += (screenSize.width - windowSize.width) / 2.0;
-        
-        [fFullScreenWindow setFrameOrigin:windowOrigin];
-        
-        /* lets kill the timer for now */
-        [self stopReceivingLibhbNotifications];
-        
-        /* We need to retain the fPreviewWindow */
-        [fPreviewWindow retain];
-        
-        [self setWindow:fFullScreenWindow];
-        
-        // The window has to be above the level of the shield window.
-        int32_t shieldLevel = CGShieldingWindowLevel(); 
-        
-        [fFullScreenWindow setLevel:shieldLevel]; 
-        
-        // Show the window. 
-        [fFullScreenWindow makeKeyAndOrderFront:self];
-        
-        
-        /* Change the name of fFullScreenToggleButton appropriately */
-        [fFullScreenToggleButton setTitle: @"Windowed"];
-        
-        /* Lets fire the timer back up for the hud controls, etc. */
-        [self startReceivingLibhbNotifications];
-        
-        isFullScreen = YES;
-        [fScaleToScreenToggleButton setHidden:NO];
-        
-        /* make sure we are set to a still preview */
-        [self pictureSliderChanged:nil];
-        
-        [fFullScreenWindow setAcceptsMouseMovedEvents:YES];
-        
-        
-        hudTimerSeconds = 0;
-        [self startHudTimer];
-    } 
-} 
 
 // Title-less windows normally don't receive key presses, override this
 - (BOOL)canBecomeKeyWindow
     [fPreviewWindow setLevel:NSNormalWindowLevel];
     
     /* Set the isFullScreen flag back to NO */
-    isFullScreen = NO;
+    //isFullScreen = NO;
     scaleToScreen = NO;
     /* make sure we are set to a still preview */
     [self pictureSliderChanged:nil];
     [self showPreviewWindow:nil];
     
     /* Change the name of fFullScreenToggleButton appropriately */
-    [fFullScreenToggleButton setTitle: @"Full Screen"];
+    //[fFullScreenToggleButton setTitle: @"Full Screen"];
     // [fScaleToScreenToggleButton setHidden:YES];
     /* set the picture settings pallete back to normal level */
     [fHBController picturePanelWindowed];
  
 
 #pragma mark Movie Preview
+
+- (IBAction) cancelCreateMoviePreview: (id) sender
+{
+    
+    hb_state_t s;
+    hb_get_state2( fPreviewLibhb, &s );
+    
+    if(isEncoding && (s.state == HB_STATE_WORKING || s.state == HB_STATE_PAUSED))
+    {
+        hb_stop( fPreviewLibhb );
+        [fPictureView setHidden:NO];
+        [fMovieView pause:nil];
+        [fMovieView setHidden:YES];
+               [fMovieView setMovie:nil];
+        [fPictureSlider setHidden:NO];
+        isEncoding = NO;
+        
+        [self pictureSliderChanged:nil];
+        
+        return;
+    }
+    
+}
+
 - (IBAction) createMoviePreview: (id) sender
 {
     
     hb_get_state2( fPreviewLibhb, &s );
     
     if(sender == fCancelPreviewMovieButton && (s.state == HB_STATE_WORKING || s.state == HB_STATE_PAUSED))
-       {
+    {
         hb_stop( fPreviewLibhb );
         [fPictureView setHidden:NO];
         [fMovieView pause:nil];
     
     [fHBController prepareJobForPreview];
     
+    /* Make sure we have a Preview sub directory with our pidnum attached */
+    NSString *PreviewDirectory = [NSString stringWithFormat:@"~/Library/Application Support/HandBrake/Previews/%d", [fHBController getPidnum]];
+    PreviewDirectory = [PreviewDirectory stringByExpandingTildeInPath];
+    if( ![[NSFileManager defaultManager] fileExistsAtPath:PreviewDirectory] )
+    {
+        [[NSFileManager defaultManager] createDirectoryAtPath:PreviewDirectory 
+                                  withIntermediateDirectories:NO 
+                                                   attributes:nil 
+                                                        error:nil];
+    }
     /* Destination file. We set this to our preview directory
      * changing the extension appropriately.*/
     if (fTitle->job->mux == HB_MUX_MP4) // MP4 file
     {
         /* we use .m4v for our mp4 files so that ac3 and chapters in mp4 will play properly */
-        fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.m4v";
+        fPreviewMoviePath = [PreviewDirectory stringByAppendingString:@"/preview_temp.m4v"];
     }
     else if (fTitle->job->mux == HB_MUX_MKV) // MKV file
     {
-        fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.mkv";
-    }
-    else if (fTitle->job->mux == HB_MUX_AVI) // AVI file
-    {
-        fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.avi";
-    }
-    else if (fTitle->job->mux == HB_MUX_OGM) // OGM file
-    {
-        fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.ogm";
+        fPreviewMoviePath = [PreviewDirectory stringByAppendingString:@"/preview_temp.mkv"];
     }
     
     fPreviewMoviePath = [[fPreviewMoviePath stringByExpandingTildeInPath]retain];
     /* See if there is an existing preview file, if so, delete it */
     if( ![[NSFileManager defaultManager] fileExistsAtPath:fPreviewMoviePath] )
     {
-        [[NSFileManager defaultManager] removeFileAtPath:fPreviewMoviePath
-                                                 handler:nil];
+        [[NSFileManager defaultManager] removeItemAtPath:fPreviewMoviePath error:nil];
     }
     
     /* We now direct our preview encode to fPreviewMoviePath */
             [fMovieCreationProgressIndicator stopAnimation: nil];
             [fMovieCreationProgressIndicator setHidden: YES];
             [fEncodingControlBox setHidden: YES];
+            [fPictureControlBox setHidden: YES];
             isEncoding = NO;
-            /* we make sure the picture slider and preview match */
-            [self pictureSliderChanged:nil];
 
             // Show the movie view
             [self showMoviePreview:fPreviewMoviePath];
     }
 }
 
+- (IBAction) toggleMoviePreviewPlayPause: (id) sender
+{
+    /* make sure a movie is even loaded up */
+    if (aMovie != nil)
+    {
+        /* For some stupid reason there is no "isPlaying" method for a QTMovie
+         * object, given that, we detect the rate to determine whether the movie
+         * is playing or not.
+         */
+        if ([aMovie rate] != 0) // we are playing 
+        {
+            [fMovieView pause:aMovie];
+            [fPlayPauseButton setTitle: @">"];
+        }
+        else // we are paused or stopped
+        {
+            [fMovieView play:aMovie];
+            [fPlayPauseButton setTitle: @"||"];   
+        }
+    }
+    
+}
+
+- (IBAction) moviePlaybackGoToBeginning: (id) sender
+{
+    /* make sure a movie is even loaded up */
+    if (aMovie != nil)
+    {
+        [fMovieView gotoBeginning:aMovie];
+     }
+    
+}
+
+- (IBAction) moviePlaybackGoToEnd: (id) sender
+{
+    /* make sure a movie is even loaded up */
+    if (aMovie != nil)
+    {
+        [fMovieView gotoEnd:aMovie];
+     }
+    
+}
+
+- (IBAction) moviePlaybackGoBackwardOneFrame: (id) sender
+{
+    /* make sure a movie is even loaded up */
+    if (aMovie != nil)
+    {
+        [fMovieView pause:aMovie]; // Pause the movie
+        [fMovieView stepBackward:aMovie];
+     }
+    
+}
+
+- (IBAction) moviePlaybackGoForwardOneFrame: (id) sender
+{
+    /* make sure a movie is even loaded up */
+    if (aMovie != nil)
+    {
+        [fMovieView pause:aMovie]; // Pause the movie
+        [fMovieView stepForward:aMovie];
+     }
+    
+}
+
+
+- (void) startMovieTimer
+{
+       if( fMovieTimer ) {
+               [fMovieTimer invalidate];
+               [fMovieTimer release];
+       }
+    fMovieTimer = [NSTimer scheduledTimerWithTimeInterval:0.10 target:self selector:@selector(movieTimerFired:) userInfo:nil repeats:YES];
+    [fMovieTimer retain];
+}
+
+- (void) stopMovieTimer
+{
+    if( fMovieTimer )
+    {
+        [fMovieTimer invalidate];
+        [fMovieTimer release];
+        fMovieTimer = nil;
+    }
+}
+
+- (void) movieTimerFired: (NSTimer*)theTimer
+{
+     if (aMovie != nil)
+    {
+        [self adjustPreviewScrubberForCurrentMovieTime];
+        [fMovieInfoField setStringValue: [NSString stringWithFormat:NSLocalizedString( @"%@", @"" ),[self calculatePlaybackSMTPETimecodeForDisplay]]];    
+    }
+}
+
+
+
 - (IBAction) showMoviePreview: (NSString *) path
 {
     /* Since the gray background for the still images is part of
      * we retain the gray cropping border  we have already established
      * with the still previews
      */
-
+    
     /* Load the new movie into fMovieView */
-    if (path) {
-               QTMovie * aMovie;
+    if (path) 
+    {
+               //QTMovie * aMovie;
                NSError  *outError;
                NSURL *movieUrl = [NSURL fileURLWithPath:path];
                NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                                                                 [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute",
                                                                                 [NSNumber numberWithBool:NO], @"QTMovieOpenAsyncRequiredAttribute",                                                            
                                                                                 [NSNumber numberWithBool:NO], @"QTMovieOpenAsyncOKAttribute",
+                                         [NSNumber numberWithBool:YES], @"QTMovieIsSteppableAttribute",
                                                                                 QTMovieApertureModeClean, QTMovieApertureModeAttribute,
                                                                                 nil];
-
+        
         aMovie = [[[QTMovie alloc] initWithAttributes:movieAttributes error:&outError] autorelease];
-
-               if (!aMovie) {
+        
+        
+               if (!aMovie) 
+        {
                        NSLog(@"Unable to open movie");
                }
-        else {
+        else 
+        {
             NSRect movieBounds;
             /* we get some size information from the preview movie */
             NSSize movieSize= [[aMovie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
             movieBounds = [fMovieView movieBounds];
             movieBounds.size.height = movieSize.height;
-            
-            if ([fMovieView isControllerVisible]) {
+            /* We also get our view size to use for scaling fMovieView's size */
+            NSSize scaledMovieViewSize = [fPictureView frame].size;
+            [fMovieView setControllerVisible:FALSE];
+            if ([fMovieView isControllerVisible]) 
+            {
                 CGFloat controllerBarHeight = [fMovieView controllerBarHeight];
                 if ( controllerBarHeight != 0 ) //Check if QTKit return a real value or not.
+                {
                     movieBounds.size.height += controllerBarHeight;
+                    scaledMovieViewSize.height += controllerBarHeight;
+                }
                 else
+                {
                     movieBounds.size.height += 15;
+                    scaledMovieViewSize.height += 15;
+                }
             }
             
             movieBounds.size.width = movieSize.width;
             
-            /* We need to find out if the preview movie needs to be scaled down so
-             * that it doesn't overflow our available viewing container (just like for image
-             * in -displayPreview) for HD sources, etc. [fPictureViewArea frame].size.height*/
-            if( (movieBounds.size.height) > [fPictureViewArea frame].size.height || scaleToScreen == YES )
-            {
-                /* The preview movie would be larger than the available viewing area
-                 * in the preview movie, so we go ahead and scale it down to the same size
-                 * as the still preview  or we readjust our window to allow for the added height if need be
-                 */
-                NSSize displaySize = NSMakeSize( ( CGFloat ) movieBounds.size.width, ( CGFloat ) movieBounds.size.height );
-                NSSize viewSize = [self optimalViewSizeForImageSize:displaySize];
-                if( [self viewNeedsToResizeToSize:viewSize] ) {
-                    [self resizeSheetForViewSize:viewSize];
-                    [self setViewSize:viewSize];
-                }
-                [fMovieView setFrameSize:viewSize];
-            }
-            else
+            /* we need to account for an issue where the scaledMovieViewSize > the window size */
+            if (scaledMovieViewSize.height > [[self window] frame].size.height)
             {
-                /* Since the preview movie is smaller than the available viewing area
-                 * we can go ahead and use the preview movies native size */
-                [fMovieView setFrameSize:movieBounds.size];
+                [fHBController writeToActivityLog: "showMoviePreview: Our window is not tall enough to show the controller bar ..."];
             }
             
-            //lets reposition the movie if need be
             
-            NSPoint origin = [fPictureViewArea frame].origin;
-            origin.x += trunc( ( [fPictureViewArea frame].size.width -
+            
+            /* Scale the fMovieView to scaledMovieViewSize */
+            [fMovieView setFrameSize:scaledMovieViewSize];
+            
+            /*set our origin try using fPictureViewArea or fPictureView */
+            NSPoint origin = [fPictureView frame].origin;
+            origin.x += trunc( ( [fPictureView frame].size.width -
                                 [fMovieView frame].size.width ) / 2.0 );
-            /* We need to detect whether or not we are currently less than the available height.*/
-            if( movieBounds.size.height < [fPictureView frame].size.height )
-            {
-                /* If we are, we are adding 15 to the height to allow for the controller bar so
-                 * we need to subtract half of that for the origin.y to get the controller bar
-                 * below the movie to it lines up vertically with where our still preview was
-                 */
-                origin.y += trunc( ( ( [fPictureViewArea frame].size.height -
+            origin.y += trunc( ( ( [fPictureView frame].size.height -
                                       [fMovieView frame].size.height ) / 2.0 ) - 7.5 );
-            }
-            else
-            {
-                /* if we are >= to the height of the picture view area, the controller bar
-                 * gets taken care of with picture resizing, so we do not want to offset the height
-                 */
-                origin.y += trunc( ( [fPictureViewArea frame].size.height -
-                                    [fMovieView frame].size.height ) / 2.0 );
-            }
+
             [fMovieView setFrameOrigin:origin];
             [fMovieView setMovie:aMovie];
             [fMovieView setHidden:NO];
+            [fMoviePlaybackControlBox setHidden: NO];
+            [fPictureControlBox setHidden: YES];
+            
             // to actually play the movie
+            
+            [self initPreviewScrubberForMovie];
+            [self startMovieTimer];
+            /* Install amovie notifications */
+            [aMovie setDelegate:self];
+            [self installMovieCallbacks];
             [fMovieView play:aMovie];
+
         }
     }
     isEncoding = NO;
 }
+#pragma mark *** Movie Playback Scrubber and time code methods ***
+
+/* Since MacOSX Leopard QTKit has taken over some responsibility for assessing movie playback
+ * information from the old QuickTime carbon api ( time code information as well as fps, etc.).
+ * However, the QTKit devs at apple were not really big on documentation and further ...
+ * QuickTimes ability to playback HB's largely variable framerate output makes perfectly frame
+ * accurate information at best convoluted. Still, for the purpose of a custom hud based custom
+ * playback scrubber slider this has so far proven to be as accurate as I have found. To say it
+ * could use some better accuracy is not understating it enough probably.
+ * Most of this was gleaned from this obscure Apple Mail list thread:
+ * http://www.mailinglistarchive.com/quicktime-api@lists.apple.com/msg05642.html
+ * Now as we currently do not show a QTKit control bar with scrubber for display sizes > container
+ * size, this seems to facilitate playback control from the HB custom HUD controller fairly close
+ * to the built in controller bar.
+ * Further work needs to be done to try to get accurate frame by frame playback display if we want it.
+ * Note that the keyboard commands for frame by frame step through etc. work as always.
+ */ 
+
+// Returns a human readable string from the currentTime of movie playback
+- (NSString*) calculatePlaybackSMTPETimecodeForDisplay
+{
+    QTTime time = [aMovie currentTime];
+    
+    NSString *smtpeTimeCodeString;
+    int days, hour, minute, second, frame;
+    long long result;
+    
+    result = time.timeValue / time.timeScale; // second
+    frame = (time.timeValue % time.timeScale) / 100;
+    
+    second = result % 60;
+    
+    result = result / 60; // minute
+    minute = result % 60;
+    
+    result = result / 60; // hour
+    hour = result % 24;         
+    days = result;
+    
+    smtpeTimeCodeString = [NSString stringWithFormat:@"Time: %02d:%02d:%02d", hour, minute, second]; // hh:mm:ss
+    return smtpeTimeCodeString;
+    
+}
+
+
+// Initialize the preview scrubber min/max to appropriate values for the current movie
+-(void) initPreviewScrubberForMovie
+{
+    if (aMovie)
+    {
+        
+        QTTime duration = [aMovie duration];
+        float result = duration.timeValue / duration.timeScale;
+        
+        [fMovieScrubberSlider setMinValue:0.0];
+        [fMovieScrubberSlider setMaxValue: (float)result];
+        [fMovieScrubberSlider setFloatValue: 0.0];
+    }
+}
+
+
+-(void) adjustPreviewScrubberForCurrentMovieTime
+{
+    if (aMovie)
+    {
+        QTTime time = [aMovie currentTime];
+        
+        float result = (float)time.timeValue / (float)time.timeScale;;
+        [fMovieScrubberSlider setFloatValue:result];
+    }
+}
+
+- (IBAction) previewScrubberChanged: (id) sender
+{
+    if (aMovie)
+    {
+        [fMovieView pause:aMovie]; // Pause the movie
+        QTTime time = [aMovie currentTime];
+        [self setTime: time.timeScale * [fMovieScrubberSlider floatValue]];
+        [self calculatePlaybackSMTPETimecodeForDisplay];
+    }
+}
+#pragma mark *** Movie Notifications ***
+
+- (void) installMovieCallbacks
+{
+
+
+/*Notification for any time the movie rate changes */
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(movieRateDidChange:)
+                                                     name:@"QTMovieRateDidChangeNotification"
+                                                   object:aMovie];
+        /*Notification for when the movie ends */
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(movieDidEnd:)
+                                                     name:@"QTMovieDidEndNotification"
+                                                   object:aMovie];
+}
+
+- (void)removeMovieCallbacks
+{
+    if (aMovie)
+    {
+        /*Notification for any time the movie rate changes */
+        [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                        name:@"QTMovieRateDidChangeNotification"
+                                                      object:aMovie];
+        /*Notification for when the movie ends */
+        [[NSNotificationCenter defaultCenter] removeObserver:self
+                                                        name:@"QTMovieDidEndNotification"
+                                                      object:aMovie];
+    }
+}
+
+- (void)movieRateDidChange:(NSNotification *)notification
+{
+    if (aMovie != nil)
+    {
+        /* For some stupid reason there is no "isPlaying" method for a QTMovie
+         * object, given that, we detect the rate to determine whether the movie
+         * is playing or not.
+         */
+        //[self adjustPreviewScrubberForCurrentMovieTime];
+        if ([aMovie rate] != 0) // we are playing 
+        {
+            [fPlayPauseButton setTitle: @"||"];
+        }
+        else // we are paused or stopped
+        {
+            [fPlayPauseButton setTitle: @">"];
+        }
+    }
+}
+/* This notification is not currently used. However we should keep it "just in case" as
+ * live preview playback is enhanced.
+ */
+- (void)movieDidEnd:(NSNotification *)notification
+{
+
+    //[fHBController writeToActivityLog: "Movie DidEnd Notification Received"];
+}
+
+
+#pragma mark *** QTTime Utilities ***
+
+       // convert a time value (long) to a QTTime structure
+-(void)timeToQTTime:(long)timeValue resultTime:(QTTime *)aQTTime
+{
+       NSNumber *timeScaleObj;
+       long timeScaleValue;
+
+       timeScaleObj = [aMovie attributeForKey:QTMovieTimeScaleAttribute];
+       timeScaleValue = [timeScaleObj longValue];
+
+       *aQTTime = QTMakeTime(timeValue, timeScaleValue);
+}
+
+       // set the movie's current time
+-(void)setTime:(int)timeValue
+{
+       QTTime movieQTTime;
+       NSValue *valueForQTTime;
+       
+       [self timeToQTTime:timeValue resultTime:&movieQTTime];
+
+       valueForQTTime = [NSValue valueWithQTTime:movieQTTime];
+
+       [aMovie setAttribute:valueForQTTime forKey:QTMovieCurrentTimeAttribute];
+}
+
 
 @end
 
 //
 - (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize
 {
-    // The min size is 320x240
+    // The min size is 480x360
     CGFloat minWidth = 480.0;
     CGFloat minHeight = 360.0;
 
-    NSSize screenSize = [[NSScreen mainScreen] frame].size;
+    NSSize screenSize = [[[self window] screen] visibleFrame].size;
     NSSize sheetSize = [[self window] frame].size;
     NSSize viewAreaSize = [fPictureViewArea frame].size;
-    CGFloat paddingX = sheetSize.width - viewAreaSize.width;
-    CGFloat paddingY = sheetSize.height - viewAreaSize.height;
-    CGFloat maxWidth;
-    CGFloat maxHeight;
+    CGFloat paddingX = 0.00;
+    CGFloat paddingY = 0.00;
     
-    if (isFullScreen)
-    {
-        /* We are in full screen mode so lets use the full screen if we need to */
-        maxWidth =  screenSize.width - paddingX;
-        maxHeight = screenSize.height - paddingY;
-    }
-    else
+    if (fTitle->width > screenSize.width || fTitle->height > screenSize.height)
     {
-        // The max size of the view is when the sheet is taking up 85% of the screen.
-        maxWidth = (0.85 * screenSize.width) - paddingX;
-        maxHeight = (0.85 * screenSize.height) - paddingY;
+        if (scaleToScreen == YES)
+        {
+            paddingX = screenSize.width - imageSize.width;
+            paddingY = screenSize.height - imageSize.height;
+        }
+        
+        else
+        {
+            paddingX = sheetSize.width - viewAreaSize.width;
+            paddingY = sheetSize.height - viewAreaSize.height;  
+        }
+
     }
     
-    NSSize resultSize = imageSize;
+    CGFloat maxWidth;
+    CGFloat maxHeight;
+    maxWidth =  screenSize.width - paddingX;
+    maxHeight = screenSize.height - paddingY;
     
-    // Its better to have a view that's too small than a view that's too big, so
-    // apply the maximum constraints last.
-    if( resultSize.width < minWidth )
-    {
-        resultSize.height *= (minWidth / resultSize.width);
-        resultSize.width = minWidth;
-    }
-    if( resultSize.height < minHeight )
-    {
-        resultSize.width *= (minHeight / resultSize.height);
-        resultSize.height = minHeight;
-    }
-    if( resultSize.width > maxWidth )
-    {
-        resultSize.height *= (maxWidth / resultSize.width);
-        resultSize.width = maxWidth;
-    }
-    if( resultSize.height > maxHeight )
-    {
-        resultSize.width *= (maxHeight / resultSize.height);
-        resultSize.height = maxHeight;
-    }
+    NSSize resultSize = imageSize;
+    CGFloat resultPar = resultSize.width / resultSize.height;
+
+    //note, a mbp 15" at 1440 x 900 is a 1.6 ar
+    CGFloat screenAspect = screenSize.width / screenSize.height;
+    // Note, a standard dvd will use 720 x 480 which is a 1.5
+    CGFloat viewAreaAspect = viewAreaSize.width / viewAreaSize.height;
     
     if (scaleToScreen == YES)
     {
-        CGFloat screenAspect;
-        CGFloat viewAreaAspect; 
-        //note, a mbp 15" at 1440 x 900 is a 1.6 ar
-        screenAspect = screenSize.width / screenSize.height;
-        
-        // Note, a standard dvd will use 720 x 480 which is a 1.5
-        viewAreaAspect = viewAreaSize.width / viewAreaSize.height;
         
         if (screenAspect < viewAreaAspect)
         {
         }
         
     }
+    else if ( resultSize.width > maxWidth || resultSize.height > maxHeight )
+    {
+       // Source is larger than screen in one or more dimensions
+        if ( resultPar > screenAspect )
+        {
+            // Source aspect wider than screen aspect, snap to max width and vary height
+            resultSize.width = maxWidth;
+            resultSize.height = (maxWidth / resultPar);
+        }
+        else
+        {
+            // Source aspect narrower than screen aspect, snap to max height vary width
+            resultSize.height = maxHeight;
+            resultSize.width = (maxHeight * resultPar);
+        }
+    }
 
-      return resultSize;
+    // If necessary, grow to minimum dimensions to ensure controls overlay is not obstructed
+    if ( resultSize.width < minWidth )
+    {
+        resultSize.width = minWidth;
+    }
+    if ( resultSize.height < minHeight )
+    {
+        resultSize.height = minHeight;
+    }
+    
+    return resultSize;
 
     
 }
     
     // Now resize the whole panel by those same deltas, but don't exceed the min
     NSRect frame = [[self window] frame];
-    NSSize maxSize = [[self window] maxSize];
-    NSSize minSize = [[self window] minSize];
+    NSSize maxSize = [[[self window] screen] visibleFrame].size;
+    /* if we are not Scale To Screen, put an 85% of visible screen on the window */
+    if (scaleToScreen == NO )
+    {
+        maxSize.width = maxSize.width * 0.85;
+        maxSize.height = maxSize.height * 0.85;
+    }
+    
+    /* Set our min size to the storage size */
+    NSSize minSize;
+    minSize.width = fTitle->width;
+    minSize.height = fTitle->height;
+    
     frame.size.width += deltaX;
     frame.size.height += deltaY;
     if( frame.size.width < minSize.width )
     {
         frame.size.height = minSize.height;
     }
+    /* compare frame to max size of screen */
+    
+    if( frame.size.width > maxSize.width )
+    {
+        frame.size.width = maxSize.width;
+    }
+    
+    if( frame.size.height > maxSize.height )
+    {
+        frame.size.height = maxSize.height;
+    }
     
     
+    
+
+    
     // But now the sheet is off-center, so also shift the origin to center it and
     // keep the top aligned.
     if( frame.size.width != [[self window] frame].size.width )
         frame.origin.x -= (deltaX / 2.0);
     
-    if (isFullScreen)
-    {
-        if( frame.size.height != [[self window] frame].size.height )
-        {
-            frame.origin.y -= (deltaY / 2.0);
-        }
-        else
-        {
-            if( frame.size.height != [[self window] frame].size.height )
-                frame.origin.y -= deltaY;
-        }
         
-        [[self window] setFrame:frame display:YES animate:NO];
-    }
-    else
-    {
         /* Since upon launch we can open up the preview window if it was open
          * the last time we quit (and at the size it was) we want to make
          * sure that upon resize we do not have the window off the screen
          * So check the origin against the screen origin and adjust if
          * necessary.
          */
-        NSSize screenSize = [[[self window] screen] frame].size;
+        NSSize screenSize = [[[self window] screen] visibleFrame].size;
         NSPoint screenOrigin = [[[self window] screen] frame].origin;
+        if (screenSize.height < frame.size.height)
+        {
+            frame.size.height = screenSize.height;
+        }
+        if (screenSize.width < frame.size.width)
+        {
+            frame.size.width = screenSize.width;
+        }
+        
+        
         /* our origin is off the screen to the left*/
         if (frame.origin.x < screenOrigin.x)
         {
         }
         
         [[self window] setFrame:frame display:YES animate:YES];
-    }
+    
     
 }
 
 //
 - (void)setViewSize: (NSSize)viewSize
 {   
+    
     /* special case for scaleToScreen */
-    if (scaleToScreen == YES)
+    NSSize screenSize = [[[self window] screen] visibleFrame].size;
+    NSSize areaSize = [fPictureViewArea frame].size;
+    NSSize pictureSize = [fPictureView frame].size;
+    CGFloat viewSizeAspect = viewSize.width / viewSize.height;
+    
+    if (viewSize.width > areaSize.width || viewSize.height > areaSize.height)
     {
-        /* for scaleToScreen, we expand the fPictureView to fit the entire screen */
-        NSSize areaSize = [fPictureViewArea frame].size;
-        CGFloat viewSizeAspect = viewSize.width / viewSize.height;
+        
         if (viewSizeAspect > 1.0) // we are wider than taller, so expand the width to fill the area and scale the height
         {
             viewSize.width = areaSize.width;
         }
         
     }
-
+    
     [fPictureView setFrameSize:viewSize];
-
+    NSSize newAreaSize = [fPictureViewArea frame].size;
+    
+    
     // center it vertically and horizontally
     NSPoint origin = [fPictureViewArea frame].origin;
     origin.y += ([fPictureViewArea frame].size.height -
     origin.y = floor( origin.y );
     
     [fPictureView setFrameOrigin:origin];
+    
 }