diff options
author | Damiano Galassi <[email protected]> | 2015-10-06 19:52:42 +0200 |
---|---|---|
committer | Damiano Galassi <[email protected]> | 2015-10-06 19:52:42 +0200 |
commit | b4a0e952b323ce54616f5c1610454195b7b2445a (patch) | |
tree | e0c33961ff2b12f40f2a577a7f9b6ca9374ad1eb | |
parent | de4e62133b9607101db3386bce78c0030ce6f883 (diff) |
MacGui: move some code out of HBPreviewController.m. Remember the windows size when going back from the Scale To Screen mode
-rw-r--r-- | macosx/English.lproj/PicturePreview.xib | 32 | ||||
-rw-r--r-- | macosx/HBPreviewController.m | 510 | ||||
-rw-r--r-- | macosx/HBPreviewView.h | 51 | ||||
-rw-r--r-- | macosx/HBPreviewView.m | 272 | ||||
-rw-r--r-- | macosx/HandBrake.xcodeproj/project.pbxproj | 12 | ||||
-rw-r--r-- | macosx/QTKit+HBQTMovieExtensions.h | 22 | ||||
-rw-r--r-- | macosx/QTKit+HBQTMovieExtensions.m | 49 |
7 files changed, 587 insertions, 361 deletions
diff --git a/macosx/English.lproj/PicturePreview.xib b/macosx/English.lproj/PicturePreview.xib index 708b0d8b7..afb3b3dcb 100644 --- a/macosx/English.lproj/PicturePreview.xib +++ b/macosx/English.lproj/PicturePreview.xib @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="8164.2" systemVersion="15A225f" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9052" systemVersion="15B22c" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> <dependencies> <deployment identifier="macosx"/> <development version="6300" identifier="xcode"/> - <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="8164.2"/> - <plugIn identifier="com.apple.QTKitIBPlugin" version="8164.2"/> + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9052"/> + <plugIn identifier="com.apple.QTKitIBPlugin" version="9052"/> </dependencies> <objects> <customObject id="-2" userLabel="File's Owner" customClass="HBPreviewController"> @@ -23,28 +23,34 @@ <outlet property="fPreviewMovieStatusField" destination="223" id="225"/> <outlet property="fScaleToScreenToggleButton" destination="275" id="yX0-fL-6J9"/> <outlet property="fscaleInfoField" destination="280" id="282"/> + <outlet property="previewView" destination="ooo-9X-9Al" id="als-Lt-aVz"/> <outlet property="window" destination="5" id="184"/> </connections> </customObject> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/> - <window title="Preview" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="5" userLabel="PreviewPanel"> + <window title="Preview" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" frameAutosaveName="Preview" animationBehavior="default" id="5" userLabel="PreviewPanel"> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/> - <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> - <rect key="contentRect" x="221" y="837" width="490" height="360"/> + <rect key="contentRect" x="221" y="837" width="500" height="360"/> <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1418"/> + <value key="minSize" type="size" width="480" height="360"/> <view key="contentView" id="6"> - <rect key="frame" x="0.0" y="0.0" width="490" height="360"/> + <rect key="frame" x="0.0" y="0.0" width="500" height="360"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> + <customView id="ooo-9X-9Al" customClass="HBPreviewView"> + <rect key="frame" x="0.0" y="0.0" width="500" height="360"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <animations/> + </customView> <qtMovieView preservesAspectRatio="YES" id="207"> - <rect key="frame" x="0.0" y="0.0" width="490" height="360"/> + <rect key="frame" x="0.0" y="0.0" width="500" height="360"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <animations/> <color key="fillColor" red="0.80000000999999998" green="0.80000000999999998" blue="0.80000000999999998" alpha="1" colorSpace="calibratedRGB"/> </qtMovieView> <customView id="2me-4k-EDi" userLabel="Picture Controls" customClass="HBHUDView"> - <rect key="frame" x="15" y="136" width="460" height="100"/> + <rect key="frame" x="20" y="136" width="460" height="100"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <subviews> <button toolTip="Encode And Play Back A Live Preview At Your Current Settings" verticalHuggingPriority="750" id="215"> @@ -155,7 +161,7 @@ <animations/> </customView> <customView hidden="YES" id="COi-Ia-2yt" userLabel="Playback Controls" customClass="HBHUDView"> - <rect key="frame" x="15" y="32" width="460" height="100"/> + <rect key="frame" x="20" y="32" width="460" height="100"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <subviews> <slider verticalHuggingPriority="750" id="341"> @@ -229,7 +235,7 @@ <animations/> </customView> <customView hidden="YES" id="F8A-dU-Y1l" userLabel="Encoding Controls" customClass="HBHUDView"> - <rect key="frame" x="15" y="240" width="460" height="100"/> + <rect key="frame" x="20" y="240" width="460" height="100"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> <subviews> <textField verticalHuggingPriority="750" id="223"> @@ -265,6 +271,10 @@ </subviews> <animations/> </view> + <connections> + <outlet property="delegate" destination="-2" id="7iq-HC-WuX"/> + </connections> + <point key="canvasLocation" x="-182" y="-40"/> </window> </objects> <resources> diff --git a/macosx/HBPreviewController.m b/macosx/HBPreviewController.m index 9be3bae5b..642661750 100644 --- a/macosx/HBPreviewController.m +++ b/macosx/HBPreviewController.m @@ -8,53 +8,17 @@ #import "HBPreviewGenerator.h" #import "HBPictureController.h" -#import <QTKit/QTKit.h> - -@implementation QTMovieView (HBQTMovieViewExtensions) - -- (void) mouseMoved: (NSEvent *) theEvent -{ - [super mouseMoved:theEvent]; -} - -@end - -@implementation QTMovie (HBQTMovieExtensions) +#import "HBPreviewView.h" -- (BOOL) isPlaying -{ - if ([self rate] > 0) - return YES; - else - return NO; -} - -- (NSString *) timecode -{ - QTTime time = [self currentTime]; - double timeInSeconds = (double)time.timeValue / time.timeScale; - UInt16 seconds = (UInt16)fmod(timeInSeconds, 60.0); - UInt16 minutes = (UInt16)fmod(timeInSeconds / 60.0, 60.0); - UInt16 hours = (UInt16)(timeInSeconds / (60.0 * 60.0)); - UInt16 milliseconds = (UInt16)(timeInSeconds - (int) timeInSeconds) * 1000; - return [NSString stringWithFormat:@"%02d:%02d:%02d.%03d", hours, minutes, seconds, milliseconds]; -} - -- (void) setCurrentTimeDouble: (double) value -{ - long timeScale = [[self attributeForKey:QTMovieTimeScaleAttribute] longValue]; - [self setCurrentTime:QTMakeTime((long long)value * timeScale, timeScale)]; -} +#import <QTKit/QTKit.h> +#import "QTKit+HBQTMovieExtensions.h" -@end +#define ANIMATION_DUR 0.15 -#define BORDER_SIZE 2.0 // make min width and height of preview window large enough for hud #define MIN_WIDTH 480.0 #define MIN_HEIGHT 360.0 -#define ANIMATION_DUR 0.15 - typedef enum ViewMode : NSUInteger { ViewModePicturePreview, ViewModeEncoding, @@ -91,13 +55,8 @@ typedef enum ViewMode : NSUInteger { @property (nonatomic, readwrite) HBPictureController *pictureSettingsWindow; -@property (nonatomic, strong) CALayer *backLayer; -@property (nonatomic, strong) CALayer *pictureLayer; - -@property (nonatomic) CGFloat backingScaleFactor; - @property (nonatomic) ViewMode currentViewMode; -@property (nonatomic) BOOL scaleToScreen; +@property (nonatomic) NSPoint windowCenterPoint; @property (nonatomic, strong) NSTimer *hudTimer; @@ -106,21 +65,7 @@ typedef enum ViewMode : NSUInteger { @property (nonatomic, strong) QTMovie *movie; @property (nonatomic, strong) NSTimer *movieTimer; -/* Pictures HUD actions */ -- (IBAction) previewDurationPopUpChanged: (id) sender; -- (IBAction) pictureSliderChanged: (id) sender; -- (IBAction) showPictureSettings:(id)sender; -- (IBAction) toggleScaleToScreen:(id)sender; - -- (IBAction) cancelCreateMoviePreview: (id) sender; -- (IBAction) createMoviePreview: (id) sender; - -/* Movie HUD actions */ -- (IBAction) showPicturesPreview: (id) sender; -- (IBAction) toggleMoviePreviewPlayPause: (id) sender; -- (IBAction) moviePlaybackGoToBeginning: (id) sender; -- (IBAction) moviePlaybackGoToEnd: (id) sender; -- (IBAction) previewScrubberChanged: (id) sender; +@property (weak) IBOutlet HBPreviewView *previewView; @end @@ -134,83 +79,49 @@ typedef enum ViewMode : NSUInteger { - (void)windowDidLoad { - [[self window] setDelegate:self]; - - if( ![[self window] setFrameUsingName:@"Preview"] ) - [[self window] center]; - - [self setWindowFrameAutosaveName:@"Preview"]; - [[self window] setExcludedFromWindowsMenu:YES]; - - /* lets set the preview window to accept mouse moved events */ - [[self window] setAcceptsMouseMovedEvents:YES]; + self.window.contentView.wantsLayer = YES; - /* we set the progress indicator to not use threaded animation - * as it causes a conflict with the qtmovieview's controllerbar - */ - [fMovieCreationProgressIndicator setUsesThreadedAnimation:NO]; + self.windowCenterPoint = [self centerPoint]; - [fMovieView setHidden:YES]; - [fMovieView setDelegate:self]; - [fMovieView setControllerVisible:NO]; + self.window.excludedFromWindowsMenu = YES; + self.window.acceptsMouseMovedEvents = YES; - /* we set the preview length popup in seconds */ + // we set the preview length popup in seconds [fPreviewMovieLengthPopUp removeAllItems]; [fPreviewMovieLengthPopUp addItemsWithTitles:@[@"15", @"30", @"45", @"60", @"90", @"120", @"150", @"180", @"210", @"240"]]; if ([[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"]) + { [fPreviewMovieLengthPopUp selectItemWithTitle:[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"]]; - if (![fPreviewMovieLengthPopUp selectedItem]) - /* currently hard set default to 15 seconds */ + } + if (!fPreviewMovieLengthPopUp.selectedItem) + { + // currently hard set default to 15 seconds [fPreviewMovieLengthPopUp selectItemAtIndex: 0]; + } - /* Setup our layers for core animation */ - [[[self window] contentView] setWantsLayer:YES]; - - self.backLayer = [CALayer layer]; - [self.backLayer setBounds:CGRectMake(0.0, 0.0, MIN_WIDTH, MIN_HEIGHT)]; - [self.backLayer setPosition:CGPointMake([[[self window] contentView] frame].size.width /2, - [[[self window] contentView] frame].size.height /2)]; - - [self.backLayer setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; - CGColorRef white = CGColorCreateGenericRGB(1.0, 1.0, 1.0, 1.0); - [self.backLayer setBackgroundColor: white]; - CFRelease(white); - [self.backLayer setShadowOpacity:0.5f]; - [self.backLayer setShadowOffset:CGSizeMake(0, 0)]; - - self.pictureLayer = [CALayer layer]; - [self.pictureLayer setBounds:CGRectMake(0.0, 0.0, MIN_WIDTH - (BORDER_SIZE * 2), MIN_HEIGHT - (BORDER_SIZE * 2))]; - [self.pictureLayer setPosition:CGPointMake([[[self window] contentView] frame].size.width /2, - [[[self window] contentView] frame].size.height /2)]; - - [self.pictureLayer setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; - - // Disable fade on contents change - NSMutableDictionary *actions = [NSMutableDictionary - dictionaryWithDictionary:[self.pictureLayer actions]]; - - actions[@"contents"] = [NSNull null]; - [self.pictureLayer setActions:actions]; + // Relocate our hud origins. + NSPoint hudControlBoxOrigin = fMoviePlaybackControlBox.frame.origin; + fPictureControlBox.frameOrigin = hudControlBoxOrigin; + fEncodingControlBox.frameOrigin = hudControlBoxOrigin; + fMoviePlaybackControlBox.frameOrigin = hudControlBoxOrigin; - [[[[self window] contentView] layer] insertSublayer:self.backLayer below: [fMovieView layer]]; - [[[[self window] contentView] layer] insertSublayer:self.pictureLayer below: [fMovieView layer]]; + [self hideHud]; - /* relocate our hud origins */ - NSPoint hudControlBoxOrigin = [fMoviePlaybackControlBox frame].origin; - [fPictureControlBox setFrameOrigin:hudControlBoxOrigin]; - [fEncodingControlBox setFrameOrigin:hudControlBoxOrigin]; - [fMoviePlaybackControlBox setFrameOrigin:hudControlBoxOrigin]; + fMovieView.hidden = YES; + fMovieView.delegate = self; + [fMovieView setControllerVisible:NO]; +} - [self hideHud]; +- (void)dealloc +{ + [self removeMovieObservers]; - /* set the current scale factor */ - if( [[self window] respondsToSelector:@selector( backingScaleFactor )] ) - self.backingScaleFactor = [[self window] backingScaleFactor]; - else - self.backingScaleFactor = 1.0; + [_hudTimer invalidate]; + [_movieTimer invalidate]; + [_generator cancel]; } - (void)setGenerator:(HBPreviewGenerator *)generator @@ -237,25 +148,25 @@ typedef enum ViewMode : NSUInteger { } [self switchViewToMode:ViewModePicturePreview]; - [self displayPreview]; + [self displayPreviewAtIndex:self.pictureIndex]; } else { - [self.pictureLayer setContents:nil]; + [self.previewView setImage:nil]; self.window.title = NSLocalizedString(@"Preview", nil); } } -- (void) reloadPreviews +- (void)reloadPreviews { if (self.generator) { [self switchViewToMode:ViewModePicturePreview]; - [self displayPreview]; + [self displayPreviewAtIndex:self.pictureIndex]; } } -- (void) showWindow: (id) sender +- (void)showWindow:(id)sender { [super showWindow:sender]; @@ -269,7 +180,7 @@ typedef enum ViewMode : NSUInteger { } } -- (void) windowWillClose: (NSNotification *) aNotification +- (void)windowWillClose:(NSNotification *)aNotification { if (self.currentViewMode == ViewModeEncoding) { @@ -285,7 +196,7 @@ typedef enum ViewMode : NSUInteger { [self.generator purgeImageCache]; } -- (void) windowDidChangeBackingProperties: (NSNotification *) notification +- (void)windowDidChangeBackingProperties:(NSNotification *)notification { NSWindow *theWindow = (NSWindow *)[notification object]; @@ -297,55 +208,35 @@ typedef enum ViewMode : NSUInteger { { // Scale factor changed, update the preview window // to the new situation - self.backingScaleFactor = newBackingScaleFactor; if (self.generator) + { [self reloadPreviews]; + } } } +#pragma mark - Window sizing + /** - * Given the size of the preview image to be shown, returns the best possible - * size for the view. + * Calculates and returns the center point of the window */ -- (NSSize) optimalViewSizeForImageSize: (NSSize) imageSize -{ - CGFloat minWidth = MIN_WIDTH; - CGFloat minHeight = MIN_HEIGHT; - - NSSize screenSize = [[[self window] screen] visibleFrame].size; - CGFloat maxWidth = screenSize.width; - CGFloat maxHeight = screenSize.height; - - 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; +- (NSPoint)centerPoint { + NSPoint center = NSMakePoint(floor(self.window.frame.origin.x + self.window.frame.size.width / 2), + floor(self.window.frame.origin.y + self.window.frame.size.height / 2)); + return center; +} - if ( resultSize.width > maxWidth || resultSize.height > maxHeight ) +- (void)windowDidMove:(NSNotification *)notification +{ + if (self.previewView.fitToView == NO) { - // 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); - } + self.windowCenterPoint = [self centerPoint]; } +} - // 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; +- (void)windowDidResize:(NSNotification *)notification +{ + [self updateSizeLabels]; } /** @@ -353,22 +244,20 @@ typedef enum ViewMode : NSUInteger { */ - (void)resizeWindowForViewSize:(NSSize)viewSize animate:(BOOL)performAnimation { - NSSize currentSize = [[[self window] contentView] frame].size; - NSRect frame = [[self window] frame]; + NSWindow *window = self.window; + NSSize currentSize = window.contentView.frame.size; + NSRect frame = window.frame; // Calculate border around content region of the frame int borderX = (int)(frame.size.width - currentSize.width); int borderY = (int)(frame.size.height - currentSize.height); // Make sure the frame is smaller than the screen - NSSize maxSize = [[[self window] screen] visibleFrame].size; + NSSize maxSize = window.screen.visibleFrame.size; - /* if we are not Scale To Screen, put an 10% of visible screen on the window */ - if (self.scaleToScreen == NO) - { - maxSize.width = maxSize.width * 0.90; - maxSize.height = maxSize.height * 0.90; - } + // if we are not Scale To Screen, put an 10% of visible screen on the window + maxSize.width = maxSize.width * 0.90; + maxSize.height = maxSize.height * 0.90; // Set the new frame size // Add the border to the new frame size so that the content region @@ -376,55 +265,75 @@ typedef enum ViewMode : NSUInteger { frame.size.width = viewSize.width + borderX; frame.size.height = viewSize.height + borderY; - /* compare frame to max size of screen */ - if( frame.size.width > maxSize.width ) + // compare frame to max size of screen + if (frame.size.width > maxSize.width) { frame.size.width = maxSize.width; } - if( frame.size.height > maxSize.height ) + if (frame.size.height > maxSize.height) { frame.size.height = maxSize.height; } - /* 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] visibleFrame].size; - NSPoint screenOrigin = [[[self window] screen] visibleFrame].origin; + // 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 = window.screen.visibleFrame.size; + NSPoint screenOrigin = window.screen.visibleFrame.origin; + + frame.origin.x = self.windowCenterPoint.x - floor(frame.size.width / 2); + frame.origin.y = self.windowCenterPoint.y - floor(frame.size.height / 2); - /* our origin is off the screen to the left*/ + // our origin is off the screen to the left if (frame.origin.x < screenOrigin.x) { - /* so shift our origin to the right */ + // so shift our origin to the right frame.origin.x = screenOrigin.x; } else if ((frame.origin.x + frame.size.width) > (screenOrigin.x + screenSize.width)) { - /* the right side of the preview is off the screen, so shift to the left */ + // the right side of the preview is off the screen, so shift to the left frame.origin.x = (screenOrigin.x + screenSize.width) - frame.size.width; } - if (self.scaleToScreen == YES) + [window setFrame:frame display:YES animate:performAnimation]; +} + +- (void)updateSizeLabels +{ + if (self.generator) { - /* our origin is off the screen to the top*/ - if (frame.origin.y < screenOrigin.y) + CGFloat scale = self.previewView.scale; + + NSMutableString *scaleString = [NSMutableString string]; + if (scale * 100.0 != 100) { - /* so shift our origin to the bottom */ - frame.origin.y = screenOrigin.y; + [scaleString appendFormat:NSLocalizedString(@"(%.0f%% actual size)", nil), scale * 100.0]; } - else if ((frame.origin.y + frame.size.height) > (screenOrigin.y + screenSize.height)) + else { - /* the top side of the preview is off the screen, so shift to the bottom */ - frame.origin.y = (screenOrigin.y + screenSize.height) - frame.size.height; + [scaleString appendString:NSLocalizedString(@"(Actual size)", nil)]; + } + + if (self.previewView.fitToView == YES) + { + [scaleString appendString:NSLocalizedString(@" Scaled To Screen", nil)]; } - } - [[self window] setFrame:frame display:YES animate:performAnimation]; + // Set the info fields in the hud controller + fInfoField.stringValue = self.generator.info; + fscaleInfoField.stringValue = scaleString; + + // Set the info field in the window title bar + self.window.title = [NSString stringWithFormat:NSLocalizedString(@"Preview - %@ %@", nil), + self.generator.info, scaleString]; + } } +#pragma mark - Hud mode + /** * Enable/Disable an arbitrary number of UI elements. * @param boxes an array of UI elements @@ -469,7 +378,7 @@ typedef enum ViewMode : NSUInteger { } else if (self.currentViewMode == ViewModeMoviePreview) { - /* Stop playback and remove the observers */ + // Stop playback and remove the observers [fMovieView pause:self]; [self stopMovieTimer]; [self removeMovieObservers]; @@ -504,7 +413,7 @@ typedef enum ViewMode : NSUInteger { [self initPreviewScrubberForMovie]; [self startMovieTimer]; - /* Install movie notifications */ + // Install movie notifications [self addMovieObservers]; } break; @@ -516,19 +425,10 @@ typedef enum ViewMode : NSUInteger { self.currentViewMode = mode; } -- (void) dealloc -{ - [self removeMovieObservers]; - - [_hudTimer invalidate]; - [_movieTimer invalidate]; - [_generator cancel]; -} - #pragma mark - #pragma mark Hud Control Overlay -- (void) mouseMoved: (NSEvent *) theEvent +- (void)mouseMoved:(NSEvent *)theEvent { [super mouseMoved:theEvent]; NSPoint mouseLoc = [theEvent locationInWindow]; @@ -621,7 +521,7 @@ typedef enum ViewMode : NSUInteger { [fEncodingControlBox setHidden:YES]; } -- (void) startHudTimer +- (void)startHudTimer { if (self.hudTimer) { @@ -634,17 +534,16 @@ typedef enum ViewMode : NSUInteger { } } -- (void) stopHudTimer +- (void)stopHudTimer { [self.hudTimer invalidate]; self.hudTimer = nil; } -- (void) hudTimerFired: (NSTimer *)theTimer +- (void)hudTimerFired: (NSTimer *)theTimer { - /* Regardless which control box is active, after the timer - * period we want either one to fade to hidden. - */ + // Regardless which control box is active, after the timer + // period we want either one to fade to hidden. [self hideHudWithAnimation:fPictureControlBox]; [self hideHudWithAnimation:fMoviePlaybackControlBox]; @@ -658,146 +557,58 @@ typedef enum ViewMode : NSUInteger { * 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)displayPreviewAtIndex:(NSUInteger)idx { if (self.window.isVisible) { - CGImageRef fPreviewImage = [self.generator copyImageAtIndex:self.pictureIndex shouldCache:YES]; - [self.pictureLayer setContents:(__bridge id)(fPreviewImage)]; + CGImageRef fPreviewImage = [self.generator copyImageAtIndex:idx shouldCache:YES]; + [self.previewView setImage:fPreviewImage]; CFRelease(fPreviewImage); } - // Set the picture size display fields below the Preview Picture - NSSize imageScaledSize = [self.generator imageSize]; - - if (self.backingScaleFactor != 1.0) + if (self.previewView.fitToView == NO && !(self.window.styleMask & NSFullScreenWindowMask)) { - // HiDPI mode usually display everything - // with douple pixel count, but we don't - // want to double the size of the video - imageScaledSize.height /= self.backingScaleFactor; - imageScaledSize.width /= self.backingScaleFactor; - } + // Get the optimal view size for the image + NSSize imageScaledSize = [self.generator imageSize]; - // Get the optimal view size for the image - NSSize viewSize = [self optimalViewSizeForImageSize:imageScaledSize]; - viewSize.width += BORDER_SIZE * 2; - viewSize.height += BORDER_SIZE * 2; - - NSSize windowSize; - if (self.scaleToScreen == YES) - { - // Scale the window to the max possible size - windowSize = [[[self window] screen] visibleFrame].size; - } - else - { // Scale the window to the image size - windowSize = viewSize; + NSSize windowSize = [self.previewView optimalViewSizeForImageSize:imageScaledSize minSize:NSMakeSize(MIN_WIDTH, MIN_HEIGHT)]; + [self resizeWindowForViewSize:windowSize animate:self.window.isVisible]; } - [self resizeWindowForViewSize:windowSize animate:self.window.isVisible]; - NSSize areaSize = [[[self window] contentView] frame].size; - areaSize.width -= BORDER_SIZE * 2; - areaSize.height -= BORDER_SIZE * 2; - - if (self.scaleToScreen == YES) - { - // 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 pictureAspectRatio = imageScaledSize.width / imageScaledSize.height; - CGFloat areaAspectRatio = areaSize.width / areaSize.height; - - if (pictureAspectRatio > areaAspectRatio) - { - viewSize.width = areaSize.width; - viewSize.height = viewSize.width / pictureAspectRatio; - } - else - { - viewSize.height = areaSize.height; - viewSize.width = viewSize.height * pictureAspectRatio; - } - } - else - { - // If the image is larger then the window, scale the image - viewSize = imageScaledSize; - - if (imageScaledSize.width > areaSize.width || imageScaledSize.height > areaSize.height) - { - CGFloat pictureAspectRatio = imageScaledSize.width / imageScaledSize.height; - CGFloat areaAspectRatio = areaSize.width / areaSize.height; - - if (pictureAspectRatio > areaAspectRatio) - { - viewSize.width = areaSize.width; - viewSize.height = viewSize.width / pictureAspectRatio; - } - else - { - viewSize.height = areaSize.height; - viewSize.width = viewSize.height * pictureAspectRatio; - } - } - } - - // Resize the CALayers - [self.backLayer setBounds:CGRectMake(0, 0, viewSize.width + (BORDER_SIZE * 2), viewSize.height + (BORDER_SIZE * 2))]; - [self.pictureLayer setBounds:CGRectMake(0, 0, viewSize.width, viewSize.height)]; - - CGFloat scale = self.pictureLayer.frame.size.width / imageScaledSize.width; - NSString *scaleString; - if (scale * 100.0 != 100) - { - scaleString = [NSString stringWithFormat:@" (%.0f%% actual size)", scale * 100.0]; - } - else - { - scaleString = @"(Actual size)"; - } - - if (_scaleToScreen == YES) - { - scaleString = [scaleString stringByAppendingString:@" Scaled To Screen"]; - } - - // Set the info fields in the hud controller - [fInfoField setStringValue:self.generator.info]; - [fscaleInfoField setStringValue:scaleString]; - - // Set the info field in the window title bar - [self.window setTitle:[NSString stringWithFormat:@"Preview - %@ %@", self.generator.info, scaleString]]; + [self updateSizeLabels]; } -- (IBAction) previewDurationPopUpChanged: (id) sender +- (IBAction)previewDurationPopUpChanged:(id)sender { [[NSUserDefaults standardUserDefaults] setObject:[fPreviewMovieLengthPopUp titleOfSelectedItem] forKey:@"PreviewLength"]; } -- (IBAction) pictureSliderChanged: (id) sender +- (IBAction)pictureSliderChanged:(id)sender { if ((self.pictureIndex != [fPictureSlider intValue] || !sender) && self.generator) { self.pictureIndex = [fPictureSlider intValue]; - [self displayPreview]; + [self displayPreviewAtIndex:self.pictureIndex]; } } -- (IBAction) toggleScaleToScreen: (id) sender +- (IBAction)toggleScaleToScreen:(id)sender { - if (self.scaleToScreen == YES) + if (self.previewView.fitToView == YES) { - self.scaleToScreen = NO; - /* make sure we are set to a still preview */ - [self displayPreview]; - [fScaleToScreenToggleButton setTitle:@"Scale To Screen"]; + self.previewView.fitToView = NO; + fScaleToScreenToggleButton.title = NSLocalizedString(@"Scale To Screen", nil); + + [self displayPreviewAtIndex:self.pictureIndex]; } else { - self.scaleToScreen = YES; - /* make sure we are set to a still preview */ - [self displayPreview]; - [fScaleToScreenToggleButton setTitle:@"Actual Scale"]; + self.previewView.fitToView = YES; + if (!(self.window.styleMask & NSFullScreenWindowMask)) + { + [self.window setFrame:self.window.screen.visibleFrame display:YES animate:YES]; + } + fScaleToScreenToggleButton.title = NSLocalizedString(@"Actual Scale", nil); } } @@ -834,11 +645,11 @@ typedef enum ViewMode : NSUInteger { { NSError *outError; NSDictionary *movieAttributes = @{QTMovieURLAttribute: fileURL, - QTMovieAskUnresolvedDataRefsAttribute: @(NO), - @"QTMovieOpenForPlaybackAttribute": @(YES), - @"QTMovieOpenAsyncRequiredAttribute": @(NO), - @"QTMovieOpenAsyncOKAttribute": @(NO), - @"QTMovieIsSteppableAttribute": @(YES), + QTMovieAskUnresolvedDataRefsAttribute: @NO, + @"QTMovieOpenForPlaybackAttribute": @YES, + @"QTMovieOpenAsyncRequiredAttribute": @NO, + @"QTMovieOpenAsyncOKAttribute": @NO, + @"QTMovieIsSteppableAttribute": @YES, QTMovieApertureModeAttribute: QTMovieApertureModeClean}; QTMovie *movie = [[QTMovie alloc] initWithAttributes:movieAttributes error:&outError]; @@ -860,29 +671,28 @@ typedef enum ViewMode : NSUInteger { } else { - /* Scale the fMovieView to the picture player size */ - [fMovieView setFrameSize:[self.pictureLayer frame].size]; - [fMovieView setFrameOrigin:[self.pictureLayer frame].origin]; + // Scale the fMovieView to the picture player size + [fMovieView setFrame:self.previewView.pictureFrame]; [fMovieView setMovie:movie]; [movie setDelegate:self]; // get and enable subtitles - NSArray *subtitlesArray = [movie tracksOfMediaType: @"sbtl"]; - if (subtitlesArray && [subtitlesArray count]) + NSArray *subtitlesArray = [movie tracksOfMediaType:QTMediaTypeSubtitle]; + if (subtitlesArray.count) { // enable the first tx3g subtitle track - [subtitlesArray[0] setEnabled: YES]; + [subtitlesArray[0] setEnabled:YES]; } else { // Perian subtitles subtitlesArray = [movie tracksOfMediaType: QTMediaTypeVideo]; - if (subtitlesArray && ([subtitlesArray count] >= 2)) + if (subtitlesArray.count >= 2) { // track 0 should be video, other video tracks should // be subtitles; force-enable the first subs track - [subtitlesArray[1] setEnabled: YES]; + [subtitlesArray[1] setEnabled:YES]; } } @@ -915,7 +725,7 @@ typedef enum ViewMode : NSUInteger { - (IBAction) toggleMoviePreviewPlayPause: (id) sender { - /* make sure a movie is even loaded up */ + // make sure a movie is even loaded up if (self.movie) { if ([self.movie isPlaying]) // we are playing @@ -1005,7 +815,7 @@ typedef enum ViewMode : NSUInteger { - (void) addMovieObservers { - /* Notification for any time the movie rate changes */ + // Notification for any time the movie rate changes [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(movieRateDidChange:) name:@"QTMovieRateDidChangeNotification" @@ -1014,7 +824,7 @@ typedef enum ViewMode : NSUInteger { - (void) removeMovieObservers { - /*Notification for any time the movie rate changes */ + // Notification for any time the movie rate changes [[NSNotificationCenter defaultCenter] removeObserver:self name:@"QTMovieRateDidChangeNotification" object:self.movie]; @@ -1022,7 +832,7 @@ typedef enum ViewMode : NSUInteger { - (void) movieRateDidChange: (NSNotification *) notification { - if ([self.movie isPlaying]) + if (self.movie.isPlaying) [fPlayPauseButton setState: NSOnState]; else [fPlayPauseButton setState: NSOffState]; @@ -1092,16 +902,16 @@ typedef enum ViewMode : NSUInteger { [super keyDown:event]; } -- (void) scrollWheel: (NSEvent *) theEvent +- (void)scrollWheel:(NSEvent *)theEvent { if (self.currentViewMode != ViewModeEncoding) { - if ([theEvent deltaY] < 0) + if (theEvent.deltaY < 0) { [fPictureSlider setIntegerValue:self.pictureIndex < [fPictureSlider maxValue] ? self.pictureIndex + 1 : self.pictureIndex]; [self pictureSliderChanged:self]; } - else if ([theEvent deltaY] > 0) + else if (theEvent.deltaY > 0) { [fPictureSlider setIntegerValue:self.pictureIndex > [fPictureSlider minValue] ? self.pictureIndex - 1 : self.pictureIndex]; [self pictureSliderChanged:self]; diff --git a/macosx/HBPreviewView.h b/macosx/HBPreviewView.h new file mode 100644 index 000000000..b590b7e8d --- /dev/null +++ b/macosx/HBPreviewView.h @@ -0,0 +1,51 @@ +/* HBPreviewView.h + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ + +#import <Cocoa/Cocoa.h> + +NS_ASSUME_NONNULL_BEGIN + +/** + * A HBPreviewView is a sublcass of NSView that can be used to display an image + * plus a border. + */ +@interface HBPreviewView : NSView + +/** + * The image displayed by the view. + */ +@property (nonatomic, readwrite, nullable) CGImageRef image; + +/** + * The scale at which the image is shown. + */ +@property (nonatomic, readonly) CGFloat scale; + +/** + * The actual frame of the displayed image. + */ +@property (nonatomic, readonly) CGRect pictureFrame; + +/** + * Wheters the image will be scaled to fill the view + * or not. + */ +@property (nonatomic, readwrite) BOOL fitToView; + +/** + * If enabled, the view will show a white border around the image. + */ +@property (nonatomic, readwrite) BOOL showBorder; + +/** + * Given the size of the preview image to be shown, returns the best possible + * size for the view. + */ +- (NSSize)optimalViewSizeForImageSize:(NSSize)imageSize minSize:(NSSize)minSize; + +@end + +NS_ASSUME_NONNULL_END diff --git a/macosx/HBPreviewView.m b/macosx/HBPreviewView.m new file mode 100644 index 000000000..5ea95b3dd --- /dev/null +++ b/macosx/HBPreviewView.m @@ -0,0 +1,272 @@ +/* HBPreviewView.m + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ + +#import "HBPreviewView.h" + +// the white border around the preview image +#define BORDER_SIZE 2.0 + +@interface HBPreviewView () + +@property (nonatomic) CALayer *backLayer; +@property (nonatomic) CALayer *pictureLayer; + +@property (nonatomic, readwrite) CGFloat scale; +@property (nonatomic, readwrite) NSRect pictureFrame; + + +@end + +@implementation HBPreviewView + +- (instancetype)initWithFrame:(NSRect)frameRect +{ + self = [super initWithFrame:frameRect]; + + if (self) + { + [self setUp]; + } + + return self; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) + { + [self setUp]; + } + + return self; +} + +/** + * Setups the sublayers, + * called by every initializer. + */ +- (void)setUp +{ + // Make it a layer hosting view + self.layer = [CALayer new]; + self.wantsLayer = YES; + + _backLayer = [CALayer layer]; + [_backLayer setBounds:CGRectMake(0.0, 0.0, self.frame.size.width, self.frame.size.height)]; + CGColorRef white = CGColorCreateGenericRGB(1.0, 1.0, 1.0, 1.0); + [_backLayer setBackgroundColor: white]; + CFRelease(white); + [_backLayer setShadowOpacity:0.5f]; + [_backLayer setShadowOffset:CGSizeMake(0, 0)]; + [_backLayer setAnchorPoint:CGPointMake(0, 0)]; + + _pictureLayer = [CALayer layer]; + [_pictureLayer setBounds:CGRectMake(0.0, 0.0, self.frame.size.width - (BORDER_SIZE * 2), self.frame.size.height - (BORDER_SIZE * 2))]; + [_pictureLayer setAnchorPoint:CGPointMake(0, 0)]; + + // Disable fade on contents change. + NSMutableDictionary *actions = [NSMutableDictionary dictionary]; + if (_pictureLayer.actions) + { + [actions addEntriesFromDictionary:_pictureLayer.actions]; + } + + actions[@"contents"] = [NSNull null]; + _pictureLayer.actions = actions; + + [self.layer addSublayer:_backLayer]; + [self.layer addSublayer:_pictureLayer]; + + _pictureLayer.hidden = YES; + _backLayer.hidden = YES; + + _showBorder = YES; + + _scale = 1; + _pictureFrame = _pictureLayer.frame; +} + +- (void)setImage:(CGImageRef)image +{ + _image = image; + self.pictureLayer.contents = (__bridge id _Nullable)(image); + + // Hide the layers if there is no image + BOOL hidden = _image == nil ? YES : NO; + self.pictureLayer.hidden = hidden ; + self.backLayer.hidden = hidden || !self.showBorder; + + [self layout]; +} + +- (void)setFitToView:(BOOL)fitToView +{ + _fitToView = fitToView; + [self layout]; +} + +- (void)setShowBorder:(BOOL)showBorder +{ + _showBorder = showBorder; + self.backLayer.hidden = !showBorder; + [self layout]; +} + +- (void)setFrame:(NSRect)newRect { + // A change in size has required the view to be invalidated. + if ([self inLiveResize]) { + [super setFrame:newRect]; + } + else { + [super setFrame:newRect]; + } + + [self layout]; +} + +- (NSSize)scaledSize:(NSSize)source toFit:(NSSize)destination +{ + NSSize result; + CGFloat sourceAspectRatio = source.width / source.height; + CGFloat destinationAspectRatio = destination.width / destination.height; + + // Source is larger than screen in one or more dimensions + if (sourceAspectRatio > destinationAspectRatio) + { + // Source aspect wider than screen aspect, snap to max width and vary height + result.width = destination.width; + result.height = result.width / sourceAspectRatio; + } + else + { + // Source aspect narrower than screen aspect, snap to max height vary width + result.height = destination.height; + result.width = result.height * sourceAspectRatio; + } + + return result; +} + +/** + * Updates the sublayers layout. + */ +- (void)layout +{ + // Set the picture size display fields below the Preview Picture + NSSize imageSize = NSMakeSize(CGImageGetWidth(self.image), CGImageGetHeight(self.image)); + NSSize imageScaledSize = imageSize; + + if (self.window.backingScaleFactor != 1.0) + { + // HiDPI mode usually display everything + // with douple pixel count, but we don't + // want to double the size of the video + imageScaledSize.height /= self.window.backingScaleFactor; + imageScaledSize.width /= self.window.backingScaleFactor; + } + + NSSize frameSize = self.frame.size; + + if (self.showBorder == YES) + { + frameSize.width -= BORDER_SIZE * 2; + frameSize.height -= BORDER_SIZE * 2; + } + + if (self.fitToView == YES) + { + // We are in Fit to View mode so, we have to get the ratio for height and width against the window + // size so we can scale from there. + imageScaledSize = [self scaledSize:imageScaledSize toFit:frameSize]; + } + else + { + // If the image is larger then the view, scale the image + if (imageScaledSize.width > frameSize.width || imageScaledSize.height > frameSize.height) + { + imageScaledSize = [self scaledSize:imageScaledSize toFit:frameSize]; + } + } + + [NSAnimationContext beginGrouping]; + [[NSAnimationContext currentContext] setDuration:0]; + + // Resize the CALayers + CGRect backRect = CGRectMake(0, 0, imageScaledSize.width + (BORDER_SIZE * 2), imageScaledSize.height + (BORDER_SIZE * 2)); + CGRect pictureRect = CGRectMake(0, 0, imageScaledSize.width, imageScaledSize.height); + + backRect = CGRectIntegral(backRect); + pictureRect = CGRectIntegral(pictureRect); + + self.backLayer.bounds = backRect; + self.pictureLayer.bounds = pictureRect; + + // Position the CALayers + CGPoint anchor = CGPointMake(floor((self.frame.size.width - pictureRect.size.width) / 2), + floor((self.frame.size.height - pictureRect.size.height) / 2)); + [self.pictureLayer setPosition:anchor]; + + CGPoint backAchor = CGPointMake(anchor.x - BORDER_SIZE, anchor.y - BORDER_SIZE); + [self.backLayer setPosition:backAchor]; + + [NSAnimationContext endGrouping]; + + // Update the proprierties + self.scale = self.pictureLayer.frame.size.width / imageSize.width; + self.pictureFrame = self.pictureLayer.frame; +} + +/** + * Given the size of the preview image to be shown, returns the best possible + * size for the view. + */ +- (NSSize)optimalViewSizeForImageSize:(NSSize)imageSize minSize:(NSSize)minSize +{ + if (self.window.backingScaleFactor != 1.0) + { + // HiDPI mode usually display everything + // with douple pixel count, but we don't + // want to double the size of the video + imageSize.height /= self.window.backingScaleFactor; + imageSize.width /= self.window.backingScaleFactor; + } + + NSSize screenSize = self.window.screen.visibleFrame.size; + CGFloat maxWidth = screenSize.width; + CGFloat maxHeight = screenSize.height; + + NSSize resultSize = imageSize; + + if (resultSize.width > maxWidth || resultSize.height > maxHeight) + { + resultSize = [self scaledSize:resultSize toFit:screenSize]; + } + + // If necessary, grow to minimum dimensions to ensure controls overlay is not obstructed + if (resultSize.width < minSize.width) + { + resultSize.width = minSize.width; + } + if (resultSize.height < minSize.height) + { + resultSize.height = minSize.height; + } + + // Add the border + if (self.showBorder) + { + resultSize.width += BORDER_SIZE * 2; + resultSize.height += BORDER_SIZE * 2; + } + + resultSize.width = floor(resultSize.width); + resultSize.height = floor(resultSize.height); + + return resultSize; +} + +@end diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index 477b69b06..e4780d22b 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -113,6 +113,8 @@ 6F0D69A91AD0683100A39DCA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 273F204014ADBC210021BE6D /* Foundation.framework */; }; A90A0CAF1988D57200DA65CE /* HBAudioTrackPreset.m in Sources */ = {isa = PBXBuildFile; fileRef = A90A0CAE1988D57200DA65CE /* HBAudioTrackPreset.m */; }; A91017B41A64440A00039BFB /* HBSubtitles.m in Sources */ = {isa = PBXBuildFile; fileRef = A91017B31A64440A00039BFB /* HBSubtitles.m */; }; + A914BCB31BC441C700157917 /* HBPreviewView.m in Sources */ = {isa = PBXBuildFile; fileRef = A914BCB21BC441C700157917 /* HBPreviewView.m */; }; + A914BCB61BC441D100157917 /* QTKit+HBQTMovieExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = A914BCB51BC441D100157917 /* QTKit+HBQTMovieExtensions.m */; }; A9160A351AE7A165009A7818 /* HBCodingUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = A9160A341AE7A165009A7818 /* HBCodingUtilities.m */; }; A91726E7197291BC00D1AFEF /* HBChapterTitlesController.m in Sources */ = {isa = PBXBuildFile; fileRef = A91726E6197291BC00D1AFEF /* HBChapterTitlesController.m */; }; A91806711A4807B000FC9BED /* HBRange.m in Sources */ = {isa = PBXBuildFile; fileRef = A91806701A4807B000FC9BED /* HBRange.m */; }; @@ -384,6 +386,10 @@ A90A0CAE1988D57200DA65CE /* HBAudioTrackPreset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBAudioTrackPreset.m; sourceTree = "<group>"; }; A91017B21A64440A00039BFB /* HBSubtitles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBSubtitles.h; sourceTree = "<group>"; }; A91017B31A64440A00039BFB /* HBSubtitles.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBSubtitles.m; sourceTree = "<group>"; }; + A914BCB11BC441C700157917 /* HBPreviewView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPreviewView.h; sourceTree = "<group>"; }; + A914BCB21BC441C700157917 /* HBPreviewView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPreviewView.m; sourceTree = "<group>"; }; + A914BCB41BC441D100157917 /* QTKit+HBQTMovieExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "QTKit+HBQTMovieExtensions.h"; sourceTree = "<group>"; }; + A914BCB51BC441D100157917 /* QTKit+HBQTMovieExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "QTKit+HBQTMovieExtensions.m"; sourceTree = "<group>"; }; A9160A331AE7A165009A7818 /* HBCodingUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBCodingUtilities.h; sourceTree = "<group>"; }; A9160A341AE7A165009A7818 /* HBCodingUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBCodingUtilities.m; sourceTree = "<group>"; }; A91726E5197291BC00D1AFEF /* HBChapterTitlesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBChapterTitlesController.h; sourceTree = "<group>"; }; @@ -761,6 +767,8 @@ A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */, A95121E41B5F7BE700FD773D /* NSArray+HBAdditions.h */, A95121E51B5F7BE700FD773D /* NSArray+HBAdditions.m */, + A914BCB41BC441D100157917 /* QTKit+HBQTMovieExtensions.h */, + A914BCB51BC441D100157917 /* QTKit+HBQTMovieExtensions.m */, A9B34D711976844500871B7D /* UI Views */, 273F20BD14ADC09F0021BE6D /* main.mm */, ); @@ -1137,6 +1145,8 @@ A9BB0F2619A0ECE40079F1C1 /* HBHUDButtonCell.m */, A9C9F88719A733FE00DC8923 /* HBHUDView.h */, A9C9F88819A733FE00DC8923 /* HBHUDView.m */, + A914BCB11BC441C700157917 /* HBPreviewView.h */, + A914BCB21BC441C700157917 /* HBPreviewView.m */, ); name = "UI Views"; sourceTree = "<group>"; @@ -1391,6 +1401,7 @@ A9AA447A1970664A00D7DEFC /* HBUtilities.m in Sources */, A9BC24C91A69293E007DC41A /* HBAttributedStringAdditions.m in Sources */, 273F20AC14ADBE670021BE6D /* HBController.m in Sources */, + A914BCB61BC441D100157917 /* QTKit+HBQTMovieExtensions.m in Sources */, 273F20AD14ADBE670021BE6D /* HBAdvancedController.m in Sources */, 273F20AE14ADBE670021BE6D /* HBAudioTrack.m in Sources */, A9DEC87A1A23C89E00C79B48 /* HBPicture.m in Sources */, @@ -1410,6 +1421,7 @@ A9F472891976B7F30009EC65 /* HBSubtitlesDefaultsController.m in Sources */, A91AFD0C1A948827009BECED /* HBOutputFileWriter.m in Sources */, A9906B2C1A710920001D82D5 /* HBQueueController.m in Sources */, + A914BCB31BC441C700157917 /* HBPreviewView.m in Sources */, A9CF25F41990D64E0023F727 /* HBPreset.m in Sources */, A95121E61B5F7BE700FD773D /* NSArray+HBAdditions.m in Sources */, A9DEC8741A23C87500C79B48 /* HBCore.m in Sources */, diff --git a/macosx/QTKit+HBQTMovieExtensions.h b/macosx/QTKit+HBQTMovieExtensions.h new file mode 100644 index 000000000..dadea3d1d --- /dev/null +++ b/macosx/QTKit+HBQTMovieExtensions.h @@ -0,0 +1,22 @@ +/* QTKit+HBQTMovieExtensions.h + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ + +#import <Cocoa/Cocoa.h> +#import <QTKit/QTKit.h> + +@interface QTMovieView (HBQTMovieViewExtensions) + +- (void)mouseMoved:(NSEvent *)theEvent; + +@end + +@interface QTMovie (HBQTMovieExtensions) + +- (BOOL)isPlaying; +- (NSString *)timecode; +- (void)setCurrentTimeDouble:(double)value; + +@end diff --git a/macosx/QTKit+HBQTMovieExtensions.m b/macosx/QTKit+HBQTMovieExtensions.m new file mode 100644 index 000000000..903659ec9 --- /dev/null +++ b/macosx/QTKit+HBQTMovieExtensions.m @@ -0,0 +1,49 @@ +/* QTKit+HBQTMovieExtensions.m + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ + +#import "QTKit+HBQTMovieExtensions.h" + +@implementation QTMovieView (HBQTMovieViewExtensions) + +- (void)mouseMoved:(NSEvent *)theEvent +{ + [super mouseMoved:theEvent]; +} + +@end + +@implementation QTMovie (HBQTMovieExtensions) + +- (BOOL)isPlaying +{ + if (self.rate > 0) + { + return YES; + } + else + { + return NO; + } +} + +- (NSString *)timecode +{ + QTTime time = [self currentTime]; + double timeInSeconds = (double)time.timeValue / time.timeScale; + UInt16 seconds = (UInt16)fmod(timeInSeconds, 60.0); + UInt16 minutes = (UInt16)fmod(timeInSeconds / 60.0, 60.0); + UInt16 hours = (UInt16)(timeInSeconds / (60.0 * 60.0)); + UInt16 milliseconds = (UInt16)(timeInSeconds - (int) timeInSeconds) * 1000; + return [NSString stringWithFormat:@"%02d:%02d:%02d.%03d", hours, minutes, seconds, milliseconds]; +} + +- (void)setCurrentTimeDouble:(double)value +{ + long timeScale = [[self attributeForKey:QTMovieTimeScaleAttribute] longValue]; + [self setCurrentTime:QTMakeTime((long long)value * timeScale, timeScale)]; +} + +@end
\ No newline at end of file |