]> granicus.if.org Git - handbrake/commitdiff
Improve preview window sizing.
authorDamiano Galassi <damiog@gmail.com>
Sat, 5 Oct 2019 17:00:30 +0000 (19:00 +0200)
committerDamiano Galassi <damiog@gmail.com>
Sat, 5 Oct 2019 17:00:30 +0000 (19:00 +0200)
macosx/Base.lproj/PicturePreview.xib
macosx/HBPreviewController.m
macosx/HBPreviewView.h
macosx/HBPreviewView.m
macosx/NSWindow+HBAdditions.h
macosx/NSWindow+HBAdditions.m

index 5a5562ffdb76288421bfa7d7b16db33f7ae0aaa1..183f39eb084d8c08bfa882569ba77c1e0b1607d9 100644 (file)
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
     <dependencies>
         <deployment identifier="macosx"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15504"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
         </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" frameAutosaveName="" animationBehavior="default" id="5" userLabel="PreviewPanel">
-            <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
+        <window title="Preview" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="5" userLabel="PreviewPanel">
+            <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
             <rect key="contentRect" x="221" y="837" width="500" height="360"/>
-            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1418"/>
+            <rect key="screenRect" x="0.0" y="0.0" width="1920" height="1177"/>
             <value key="minSize" type="size" width="480" height="360"/>
             <view key="contentView" id="6">
                 <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">
+                    <customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" 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"/>
                     </customView>
index e3d9c72aff1004c4181d54ffbaee02534cb07012..4d8e5ed11255ef0a040aa5bebd84f446dceacbda 100644 (file)
     // We need the center and we can't use the
     // standard NSWindow autosave because we change
     // the window size at startup.
-    NSString *centerString = [[NSUserDefaults standardUserDefaults] objectForKey:@"HBPreviewWindowCenter"];
+    NSString *centerString = [NSUserDefaults.standardUserDefaults stringForKey:@"HBPreviewWindowCenter"];
     if (centerString.length)
     {
         NSPoint center = NSPointFromString(centerString);
         self.windowCenterPoint = center;
-        [self.window HB_resizeToBestSizeForViewSize:NSMakeSize(MIN_WIDTH, MIN_HEIGHT) center:self.windowCenterPoint animate:NO];
+        [self.window HB_resizeToBestSizeForViewSize:NSMakeSize(MIN_WIDTH, MIN_HEIGHT) keepInScreenRect:YES centerPoint:center animate:NO];
     }
     else
     {
         self.window.title = NSLocalizedString(@"Preview", @"Preview -> window title");
         self.pictureHUD.generator = nil;
     }
+
     [self switchStateToHUD:self.pictureHUD];
+    
+    if (generator)
+    {
+        [self resizeToOptimalSize];
+    }
 }
 
 - (void)reloadPreviews
     {
         [self.generator cancel];
         [self switchStateToHUD:self.pictureHUD];
+        [self resizeToOptimalSize];
     }
 }
 
     [self.generator purgeImageCache];
 }
 
+#pragma mark - Window sizing
+
+- (void)resizeToOptimalSize
+{
+    if (!(self.window.styleMask & NSWindowStyleMaskFullScreen))
+    {
+        if (self.previewView.fitToView)
+        {
+            [self.window setFrame:self.window.screen.visibleFrame display:YES animate:YES];
+        }
+        else
+        {
+            // Get the optimal view size for the image
+            NSSize windowSize = [self.previewView optimalViewSizeForImageSize:self.generator.imageSize
+                                                                      minSize:NSMakeSize(MIN_WIDTH, MIN_HEIGHT)
+                                                                  scaleFactor:self.window.backingScaleFactor];
+            // Scale the window to the image size
+            [self.window HB_resizeToBestSizeForViewSize:windowSize keepInScreenRect:YES centerPoint:NSZeroPoint animate:self.window.isVisible];
+        }
+    }
+
+    [self updateSizeLabels];
+}
+
 - (void)windowDidChangeBackingProperties:(NSNotification *)notification
 {
     NSWindow *theWindow = (NSWindow *)notification.object;
 
     CGFloat newBackingScaleFactor = theWindow.backingScaleFactor;
-    CGFloat oldBackingScaleFactor = [notification.userInfo[@"NSBackingPropertyOldScaleFactorKey"] doubleValue];
+    CGFloat oldBackingScaleFactor = [notification.userInfo[NSBackingPropertyOldScaleFactorKey] doubleValue];
 
     if (newBackingScaleFactor != oldBackingScaleFactor)
     {
-        // Scale factor changed, update the preview window
-        // to the new situation
+        // Scale factor changed, resize the preview window
         if (self.generator)
         {
-            [self reloadPreviews];
+            [self resizeToOptimalSize];
         }
     }
 }
     if (self.previewView.fitToView == NO)
     {
         self.windowCenterPoint = [self.window HB_centerPoint];
-        [[NSUserDefaults standardUserDefaults] setObject:NSStringFromPoint(self.windowCenterPoint) forKey:@"HBPreviewWindowCenter"];
+        [NSUserDefaults.standardUserDefaults setObject:NSStringFromPoint(self.windowCenterPoint) forKey:@"HBPreviewWindowCenter"];
     }
 }
 
 - (void)windowDidResize:(NSNotification *)notification
 {
     [self updateSizeLabels];
+    if (self.currentHUD == self.playerHUD)
+    {
+        [CATransaction begin];
+        CATransaction.disableActions = YES;
+        self.player.layer.frame = self.previewView.pictureFrame;
+        [CATransaction commit];
+    }
 }
 
 - (void)updateSizeLabels
         NSMutableString *scaleString = [NSMutableString string];
         if (scale * 100.0 != 100)
         {
-            [scaleString appendFormat:NSLocalizedString(@"(%.0f%% actual size)", @"Preview -> size info label"), scale * 100.0];
+            [scaleString appendFormat:NSLocalizedString(@"(%.0f%% actual size)", @"Preview -> size info label"), floor(scale * 100.0)];
         }
         else
         {
     }
 }
 
+- (void)toggleScaleToScreen
+{
+    self.previewView.fitToView = !self.previewView.fitToView;
+    [self resizeToOptimalSize];
+}
+
 #pragma mark - Hud State
 
 /**
     // Show the current hud
     NSMutableArray<NSViewController<HBHUD> *> *huds = [@[self.pictureHUD, self.encodingHUD, self.playerHUD] mutableCopy];
     [huds removeObject:hud];
-    for (NSViewController *controller in huds) {
+    for (NSViewController *controller in huds)
+    {
         controller.view.hidden = YES;
     }
+    
     if (self.generator)
     {
         hud.view.hidden = NO;
         hud.view.layer.opacity = 1.0;
-    };
+    }
 
     [self.window makeFirstResponder:hud.view];
     [self startHudTimer];
     [self displayPreviewAtIndex:self.pictureHUD.selectedIndex];
 }
 
-/**
- * Adjusts the window to draw the current picture (fPicture) adjusting its size as
- * necessary to display as much of the picture as possible.
- */
 - (void)displayPreviewAtIndex:(NSUInteger)idx
 {
-    if (!self.generator)
-    {
-        return;
-    }
-
-    if (self.window.isVisible)
+    if (self.generator && self.window.isVisible)
     {
-        CGImageRef fPreviewImage = [self.generator copyImageAtIndex:idx shouldCache:YES];
-        [self.previewView setImage:fPreviewImage];
-        CFRelease(fPreviewImage);
-    }
-
-    if (self.previewView.fitToView == NO && !(self.window.styleMask & NSWindowStyleMaskFullScreen))
-    {
-        // Get the optimal view size for the image
-        NSSize imageScaledSize = [self.generator imageSize];
-
-        // Scale the window to the image size
-        NSSize windowSize = [self.previewView optimalViewSizeForImageSize:imageScaledSize minSize:NSMakeSize(MIN_WIDTH, MIN_HEIGHT)];
-        [self.window HB_resizeToBestSizeForViewSize:windowSize center:self.windowCenterPoint animate:self.window.isVisible];
-    }
-
-    [self updateSizeLabels];
-}
-
-- (void)toggleScaleToScreen
-{
-    if (self.previewView.fitToView == YES)
-    {
-        self.previewView.fitToView = NO;
-        [self displayPreviewAtIndex:self.pictureHUD.selectedIndex];
-    }
-    else
-    {
-        self.previewView.fitToView = YES;
-        if (!(self.window.styleMask & NSWindowStyleMaskFullScreen))
-        {
-            [self.window setFrame:self.window.screen.visibleFrame display:YES animate:YES];
-        }
+        CGImageRef image = [self.generator copyImageAtIndex:idx shouldCache:YES];
+        self.previewView.image = image;
+        CFRelease(image);
     }
 }
 
     CALayer *playerLayer = self.player.layer;
     playerLayer.frame = self.previewView.pictureFrame;
 
-    [self.window.contentView.layer insertSublayer:playerLayer atIndex:1];
-
+    [self.previewView.layer insertSublayer:playerLayer atIndex:10];
     self.playerHUD.player = self.player;
 }
 
index e521aa9f9dfdf3858ba9293b5453d5ad212b8414..29d0ae8672cc1a5d6eaf0f95d1ea76cf8fa4b189 100644 (file)
@@ -49,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
  * 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;
+- (NSSize)optimalViewSizeForImageSize:(NSSize)imageSize minSize:(NSSize)minSize scaleFactor:(CGFloat)scaleFactor;
 
 @end
 
index 7f5b81e30325b432e6cb03f6bb523d336a76e401..753fd09f41c4af4dfa2c526b4dbe83bb157e42d5 100644 (file)
@@ -5,6 +5,7 @@
  It may be used under the terms of the GNU General Public License. */
 
 #import "HBPreviewView.h"
+#import <QuartzCore/QuartzCore.h>
 
 // the white border around the preview image
 #define BORDER_SIZE 2.0
 @property (nonatomic) CALayer *backLayer;
 @property (nonatomic) CALayer *pictureLayer;
 
-@property (nonatomic, readwrite) CGFloat scale;
-@property (nonatomic, readwrite) NSRect pictureFrame;
-
-@property (nonatomic, readwrite) CGFloat scaleFactor;
-
 @end
 
 @implementation HBPreviewView
 
     _pictureLayer.hidden = YES;
     _backLayer.hidden = YES;
-
     _showBorder = YES;
-    _scale = 1;
-    _pictureFrame = _pictureLayer.frame;
 }
 
 - (void)viewDidChangeBackingProperties
 {
     if (self.window)
     {
-        self.scaleFactor = self.window.backingScaleFactor;
+        self.needsLayout = YES;
     }
 }
 
     self.pictureLayer.hidden = hidden ;
     self.backLayer.hidden = hidden || !self.showBorder;
 
-    [self _updatePreviewLayout];
+    self.needsLayout = YES;
 }
 
 - (void)setFitToView:(BOOL)fitToView
 {
     _fitToView = fitToView;
-    [self _updatePreviewLayout];
+    self.needsLayout = YES;
 }
 
 - (void)setShowBorder:(BOOL)showBorder
 {
     _showBorder = showBorder;
     self.backLayer.hidden = !showBorder;
-    [self _updatePreviewLayout];
+    self.needsLayout = YES;
 }
 
 - (void)setShowShadow:(BOOL)showShadow
     _backLayer.shadowOpacity = showShadow ? 0.5f : 0;
 }
 
-- (void)setFrame:(NSRect)newRect {
-    // A change in size has required the view to be invalidated.
-    if ([self inLiveResize]) {
-        [super setFrame:newRect];
+- (CGFloat)scale
+{
+    if (self.image)
+    {
+        NSSize imageSize = NSMakeSize(CGImageGetWidth(self.image), CGImageGetHeight(self.image));
+        CGFloat backingScaleFactor = self.window.backingScaleFactor;
+        CGFloat borderSize = self.showBorder ? BORDER_SIZE : 0;
+        
+        NSSize imageScaledSize = [self imageScaledSize:imageSize toFit:self.frame.size borderSize:borderSize scaleFactor:self.window.backingScaleFactor];
+
+        return (imageScaledSize.width - borderSize * 2) / imageSize.width * backingScaleFactor;
     }
-    else {
-        [super setFrame:newRect];
+    else
+    {
+        return 1;
     }
+}
 
-    [self _updatePreviewLayout];
+- (CGRect)pictureFrame
+{
+    return self.pictureLayer.frame;
 }
 
 - (NSSize)scaledSize:(NSSize)source toFit:(NSSize)destination
     return result;
 }
 
-/**
- *  Updates the sublayers layout.
- */
-- (void)_updatePreviewLayout
+- (NSSize)imageScaledSize:(NSSize)source toFit:(NSSize)destination borderSize:(CGFloat)borderSize scaleFactor:(CGFloat)scaleFactor
+{
+    // HiDPI mode usually display everything
+    // with double pixel count, but we don't
+    // want to double the size of the video
+    NSSize scaledSource = NSMakeSize(source.width / scaleFactor, source.height / scaleFactor);
+    
+    scaledSource.width += borderSize * 2;
+    scaledSource.height += borderSize * 2;
+        
+    if (self.fitToView == YES || scaledSource.width > destination.width || scaledSource.height > destination.height)
+    {
+        // If the image is larger then the view or if we are in Fit to View mode, scale the image
+        scaledSource = [self scaledSize:source toFit:destination];
+    }
+    
+    return scaledSource;
+}
+
+- (void)layout
 {
     // Set the picture size display fields below the Preview Picture
     NSSize imageSize = NSMakeSize(CGImageGetWidth(self.image), CGImageGetHeight(self.image));
-    CGFloat backingScaleFactor = 1.0;
 
     if (imageSize.width > 0 && imageSize.height > 0)
     {
-        backingScaleFactor = self.scaleFactor;
-
-        // HiDPI mode usually display everything
-        // with double pixel count, but we don't
-        // want to double the size of the video
-        NSSize imageScaledSize = NSMakeSize(imageSize.width / backingScaleFactor, imageSize.height / backingScaleFactor);
+        CGFloat borderSize = self.showBorder ? BORDER_SIZE : 0;
         NSSize frameSize = self.frame.size;
+        
+        NSSize imageScaledSize = [self imageScaledSize:imageSize
+                                                 toFit:frameSize
+                                            borderSize:borderSize
+                                           scaleFactor:self.window.backingScaleFactor];
+        
+        [CATransaction begin];
+        CATransaction.disableActions = YES;
 
-        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 (imageScaledSize.width > frameSize.width || imageScaledSize.height > frameSize.height)
-        {
-            // If the image is larger then the view, scale the image
-            imageScaledSize = [self scaledSize:imageScaledSize toFit:frameSize];
-        }
-
-        [NSAnimationContext beginGrouping];
-        [NSAnimationContext.currentContext setDuration:0];
-
-        // Resize and position the CALayers
-        CGFloat width = imageScaledSize.width + (BORDER_SIZE * 2);
-        CGFloat height = imageScaledSize.height + (BORDER_SIZE * 2);
-
-        CGFloat offsetX = (self.frame.size.width - width) / 2;
-        CGFloat offsetY = (self.frame.size.height - height) / 2;
+        CGFloat width = imageScaledSize.width;
+        CGFloat height = imageScaledSize.height;
+
+        CGFloat offsetX = (frameSize.width - width) / 2;
+        CGFloat offsetY = (frameSize.height - height) / 2;
 
         NSRect alignedRect = [self backingAlignedRect:NSMakeRect(offsetX, offsetY, width, height) options:NSAlignAllEdgesNearest];
 
         self.backLayer.frame = alignedRect;
-        self.pictureLayer.frame = NSInsetRect(alignedRect, 2, 2);
-
-        [NSAnimationContext endGrouping];
+        self.pictureLayer.frame = NSInsetRect(alignedRect, borderSize, borderSize);
         
-        // Update the properties
-        self.scale = self.pictureLayer.frame.size.width / imageSize.width * backingScaleFactor;
-        self.pictureFrame = self.pictureLayer.frame;
+        [CATransaction commit];
     }
 }
 
 /**
- * Given the size of the preview image to be shown, returns the best possible
- * size for the view.
+ * 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
+- (NSSize)optimalViewSizeForImageSize:(NSSize)imageSize minSize:(NSSize)minSize scaleFactor:(CGFloat)scaleFactor
 {
-    if (self.scaleFactor != 1.0)
-    {
-        // HiDPI mode usually display everything
-        // with double pixel count, but we don't
-        // want to double the size of the video
-        imageSize.height /= self.scaleFactor;
-        imageSize.width /= self.scaleFactor;
-    }
-
-    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];
-    }
+    NSSize resultSize = [self imageScaledSize:imageSize
+                                        toFit:self.window.screen.visibleFrame.size
+                                   borderSize:self.showBorder ? BORDER_SIZE : 0
+                                  scaleFactor:scaleFactor];
 
     // If necessary, grow to minimum dimensions to ensure controls overlay is not obstructed
     if (resultSize.width < minSize.width)
         resultSize.height = minSize.height;
     }
 
-    // Add the border
-    if (self.showBorder)
-    {
-        resultSize.width += BORDER_SIZE * 2;
-        resultSize.height += BORDER_SIZE * 2;
-    }
-
     NSRect alignedRect = [self backingAlignedRect:NSMakeRect(0, 0, resultSize.width, resultSize.height)
                                           options:NSAlignAllEdgesNearest];
 
-    resultSize.width = alignedRect.size.width;
-    resultSize.height = alignedRect.size.height;
-
-    return resultSize;
+    return alignedRect.size;
 }
 
 #pragma mark - Accessibility
index 4f411601329fc7aa888ff6f9f33630c3a5006002..7adb69d5d14ffa127f2d1a1f39b5e145c80faff3 100644 (file)
@@ -11,7 +11,7 @@
 /**
  *  Resizes the entire window to accommodate a view of a particular size.
  */
-- (void)HB_resizeToBestSizeForViewSize:(NSSize)viewSize center:(NSPoint)center animate:(BOOL)performAnimation;
+- (void)HB_resizeToBestSizeForViewSize:(NSSize)viewSize keepInScreenRect:(BOOL)keepInScreenRect centerPoint:(NSPoint)center animate:(BOOL)animateFlag;
 
 /**
  *  Calculates and returns the center point of the window
index daf572bfaf30cc84376cac4822e0de3755fe869d..d783ee8bca597c20b1e98c127bd0910ae08500d4 100644 (file)
@@ -8,7 +8,7 @@
 
 @implementation NSWindow (HBAdditions)
 
-- (void)HB_resizeToBestSizeForViewSize:(NSSize)viewSize center:(NSPoint)center animate:(BOOL)animateFlag
+- (void)HB_resizeToBestSizeForViewSize:(NSSize)viewSize keepInScreenRect:(BOOL)keepInScreenRect centerPoint:(NSPoint)center animate:(BOOL)animateFlag
 {
     NSSize currentSize = self.contentView.frame.size;
     NSRect frame = self.frame;
     // 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.screen.visibleFrame.size;
-    NSPoint screenOrigin = self.screen.visibleFrame.origin;
-
+    
+    if (center.x == 0 && center.y == 0)
+    {
+        center = [self HB_centerPoint];
+    }
     frame.origin.x = center.x - floor(frame.size.width / 2);
     frame.origin.y = center.y - floor(frame.size.height / 2);
 
-    // our origin is off the screen to the left
-    if (frame.origin.x < screenOrigin.x)
+    if (keepInScreenRect)
     {
-        // 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
-        frame.origin.x = (screenOrigin.x + screenSize.width) - frame.size.width;
+        NSSize screenSize = self.screen.visibleFrame.size;
+        NSPoint screenOrigin = self.screen.visibleFrame.origin;
+
+        // our origin is off the screen to the left
+        if (frame.origin.x < screenOrigin.x)
+        {
+            // 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
+            frame.origin.x = (screenOrigin.x + screenSize.width) - frame.size.width;
+        }
+        
+        // our origin is off the screen to the bottom
+        if (frame.origin.y < screenOrigin.y)
+        {
+            // so shift our origin to the top
+            frame.origin.y = screenOrigin.y;
+        }
+        else if ((frame.origin.y + frame.size.height) > (screenOrigin.y + screenSize.height))
+        {
+            // 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;
+        }
     }
 
     [self setFrame:frame display:YES animate:animateFlag];