diff options
author | Damiano Galassi <[email protected]> | 2019-10-05 19:00:30 +0200 |
---|---|---|
committer | Damiano Galassi <[email protected]> | 2019-10-05 19:00:30 +0200 |
commit | 4238775818207edef7f303dabf99684f5542bc53 (patch) | |
tree | 0fc0b4a659abd329f394a92c31adcfcf6085cefe | |
parent | b8fc24a311d3f0163fd39d758d54096f37dbb8b3 (diff) |
Improve preview window sizing.
-rw-r--r-- | macosx/Base.lproj/PicturePreview.xib | 12 | ||||
-rw-r--r-- | macosx/HBPreviewController.m | 114 | ||||
-rw-r--r-- | macosx/HBPreviewView.h | 2 | ||||
-rw-r--r-- | macosx/HBPreviewView.m | 163 | ||||
-rw-r--r-- | macosx/NSWindow+HBAdditions.h | 2 | ||||
-rw-r--r-- | macosx/NSWindow+HBAdditions.m | 46 |
6 files changed, 168 insertions, 171 deletions
diff --git a/macosx/Base.lproj/PicturePreview.xib b/macosx/Base.lproj/PicturePreview.xib index 5a5562ffd..183f39eb0 100644 --- a/macosx/Base.lproj/PicturePreview.xib +++ b/macosx/Base.lproj/PicturePreview.xib @@ -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> @@ -14,16 +14,16 @@ </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> diff --git a/macosx/HBPreviewController.m b/macosx/HBPreviewController.m index e3d9c72af..4d8e5ed11 100644 --- a/macosx/HBPreviewController.m +++ b/macosx/HBPreviewController.m @@ -63,12 +63,12 @@ // 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 { @@ -167,7 +167,13 @@ self.window.title = NSLocalizedString(@"Preview", @"Preview -> window title"); self.pictureHUD.generator = nil; } + [self switchStateToHUD:self.pictureHUD]; + + if (generator) + { + [self resizeToOptimalSize]; + } } - (void)reloadPreviews @@ -176,6 +182,7 @@ { [self.generator cancel]; [self switchStateToHUD:self.pictureHUD]; + [self resizeToOptimalSize]; } } @@ -204,20 +211,43 @@ [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]; } } } @@ -229,13 +259,20 @@ 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 @@ -247,7 +284,7 @@ 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 { @@ -269,6 +306,12 @@ } } +- (void)toggleScaleToScreen +{ + self.previewView.fitToView = !self.previewView.fitToView; + [self resizeToOptimalSize]; +} + #pragma mark - Hud State /** @@ -299,14 +342,16 @@ // 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]; @@ -431,51 +476,13 @@ [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); } } @@ -593,8 +600,7 @@ 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; } diff --git a/macosx/HBPreviewView.h b/macosx/HBPreviewView.h index e521aa9f9..29d0ae867 100644 --- a/macosx/HBPreviewView.h +++ b/macosx/HBPreviewView.h @@ -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 diff --git a/macosx/HBPreviewView.m b/macosx/HBPreviewView.m index 7f5b81e30..753fd09f4 100644 --- a/macosx/HBPreviewView.m +++ b/macosx/HBPreviewView.m @@ -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 @@ -14,11 +15,6 @@ @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 @@ -85,17 +81,14 @@ _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; } } @@ -109,20 +102,20 @@ 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 @@ -130,16 +123,27 @@ _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 @@ -165,91 +169,68 @@ 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) @@ -261,20 +242,10 @@ 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 diff --git a/macosx/NSWindow+HBAdditions.h b/macosx/NSWindow+HBAdditions.h index 4f4116013..7adb69d5d 100644 --- a/macosx/NSWindow+HBAdditions.h +++ b/macosx/NSWindow+HBAdditions.h @@ -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 diff --git a/macosx/NSWindow+HBAdditions.m b/macosx/NSWindow+HBAdditions.m index daf572bfa..d783ee8bc 100644 --- a/macosx/NSWindow+HBAdditions.m +++ b/macosx/NSWindow+HBAdditions.m @@ -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; @@ -45,22 +45,42 @@ // 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]; |