summaryrefslogtreecommitdiffstats
path: root/macosx
diff options
context:
space:
mode:
authorDamiano Galassi <[email protected]>2015-10-06 19:52:42 +0200
committerDamiano Galassi <[email protected]>2015-10-06 19:52:42 +0200
commitb4a0e952b323ce54616f5c1610454195b7b2445a (patch)
treee0c33961ff2b12f40f2a577a7f9b6ca9374ad1eb /macosx
parentde4e62133b9607101db3386bce78c0030ce6f883 (diff)
MacGui: move some code out of HBPreviewController.m. Remember the windows size when going back from the Scale To Screen mode
Diffstat (limited to 'macosx')
-rw-r--r--macosx/English.lproj/PicturePreview.xib32
-rw-r--r--macosx/HBPreviewController.m510
-rw-r--r--macosx/HBPreviewView.h51
-rw-r--r--macosx/HBPreviewView.m272
-rw-r--r--macosx/HandBrake.xcodeproj/project.pbxproj12
-rw-r--r--macosx/QTKit+HBQTMovieExtensions.h22
-rw-r--r--macosx/QTKit+HBQTMovieExtensions.m49
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