From 1ca7c1194b2ac3a81b9fa611a5f63932fb9d6ee9 Mon Sep 17 00:00:00 2001 From: Aleh Dzenisiuk Date: Fri, 14 Apr 2023 16:28:02 +0200 Subject: [PATCH] Work around build issues when this is used as a dev pod Unfortunately I am still not quite sure what's the root cause: for some reason MMMContainerView and MMMLayoutUtils.inverseGolden could not be found when this pod was included as a development one. Separating them into their own sources seems to fix the problem for now but I guess it's just a symptom of another issue. --- ...MMMLayoutUtils.swift => LayoutUtils.swift} | 0 Sources/MMMCommonUIObjC/MMMCommonUI.h | 23 +-- Sources/MMMCommonUIObjC/MMMCommonUIMisc.h | 4 +- Sources/MMMCommonUIObjC/MMMContainerView.h | 21 +++ Sources/MMMCommonUIObjC/MMMContainerView.m | 30 ++++ Sources/MMMCommonUIObjC/MMMLayout.h | 133 +----------------- Sources/MMMCommonUIObjC/MMMLayout.m | 130 +---------------- Sources/MMMCommonUIObjC/MMMLayoutUtils.h | 122 ++++++++++++++++ Sources/MMMCommonUIObjC/MMMLayoutUtils.m | 115 +++++++++++++++ Sources/MMMCommonUIObjC/MMMStubView.m | 2 +- 10 files changed, 297 insertions(+), 283 deletions(-) rename Sources/MMMCommonUI/{MMMLayoutUtils.swift => LayoutUtils.swift} (100%) create mode 100644 Sources/MMMCommonUIObjC/MMMContainerView.h create mode 100644 Sources/MMMCommonUIObjC/MMMContainerView.m create mode 100644 Sources/MMMCommonUIObjC/MMMLayoutUtils.h create mode 100644 Sources/MMMCommonUIObjC/MMMLayoutUtils.m diff --git a/Sources/MMMCommonUI/MMMLayoutUtils.swift b/Sources/MMMCommonUI/LayoutUtils.swift similarity index 100% rename from Sources/MMMCommonUI/MMMLayoutUtils.swift rename to Sources/MMMCommonUI/LayoutUtils.swift diff --git a/Sources/MMMCommonUIObjC/MMMCommonUI.h b/Sources/MMMCommonUIObjC/MMMCommonUI.h index b26a706..ff5270b 100644 --- a/Sources/MMMCommonUIObjC/MMMCommonUI.h +++ b/Sources/MMMCommonUIObjC/MMMCommonUI.h @@ -3,25 +3,4 @@ // Copyright (C) 2016-2020 MediaMonks. All rights reserved. // -#import "MMMAnimations.h" -#import "MMMAutoLayoutScrollView.h" -#import "MMMCollectionView.h" -#import "MMMCommonUIMisc.h" -#import "MMMImageView.h" -#import "MMMKeyboard.h" -#import "MMMLayout.h" -#import "MMMNavigation.h" -#import "MMMNavigationStack.h" -#import "MMMPhoto.h" -#import "MMMPhotoLibraryLoadableImage.h" -#import "MMMPreferredSizeChanges.h" -#import "MMMScrollViewShadows.h" -#import "MMMShadowView.h" -#import "MMMStubView.h" -#import "MMMStubViewController.h" -#import "MMMStylesheet.h" -#import "MMMTableView.h" -#import "MMMTableViewCell.h" -#import "MMMVerticalGradientView.h" -#import "MMMViewWrappingCell.h" -#import "MMMWebView.h" +// This file is needed because Swift compatibility headers always contain `#import ` line. diff --git a/Sources/MMMCommonUIObjC/MMMCommonUIMisc.h b/Sources/MMMCommonUIObjC/MMMCommonUIMisc.h index 253fe62..44747e5 100644 --- a/Sources/MMMCommonUIObjC/MMMCommonUIMisc.h +++ b/Sources/MMMCommonUIObjC/MMMCommonUIMisc.h @@ -3,11 +3,11 @@ // Copyright (C) 2016-2020 MediaMonks. All rights reserved. // +@import UIKit; + #if SWIFT_PACKAGE -#import "UIKit/UIKit.h" @import MMMCommonCoreObjC; #else -@import UIKit; @import MMMCommonCore; #endif diff --git a/Sources/MMMCommonUIObjC/MMMContainerView.h b/Sources/MMMCommonUIObjC/MMMContainerView.h new file mode 100644 index 0000000..c709bba --- /dev/null +++ b/Sources/MMMCommonUIObjC/MMMContainerView.h @@ -0,0 +1,21 @@ +// +// Starbucks App. +// Copyright (c) 2023 MediaMonks. All rights reserved. +// + +@import UIKit; + +/** + * Auto Layout does not support constraints against groups of items, so this is for the cases a normal UIView is + * typically used as a container for such a group. + * Unlike UIView we have translatesAutoresizingMaskIntoConstraints set to NO already. + * Also `MMMContainerView` does not intercept touches but subviews still do. + */ +@interface MMMContainerView : UIView + +- (nonnull id)init NS_DESIGNATED_INITIALIZER; + +- (id)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE; +- (id)initWithFrame:(CGRect)frame NS_UNAVAILABLE; + +@end diff --git a/Sources/MMMCommonUIObjC/MMMContainerView.m b/Sources/MMMCommonUIObjC/MMMContainerView.m new file mode 100644 index 0000000..9322e36 --- /dev/null +++ b/Sources/MMMCommonUIObjC/MMMContainerView.m @@ -0,0 +1,30 @@ +// +// Starbucks App. +// Copyright (c) 2023 MediaMonks. All rights reserved. +// + +#import "MMMContainerView.h" + +@implementation MMMContainerView + +- (id)init { + + if (self = [super initWithFrame:CGRectZero]) { + self.translatesAutoresizingMaskIntoConstraints = NO; + } + + return self; +} + +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { + + UIView *view = [super hitTest:point withEvent:event]; + + if (view == self) { + return nil; + } else { + return view; + } +} + +@end diff --git a/Sources/MMMCommonUIObjC/MMMLayout.h b/Sources/MMMCommonUIObjC/MMMLayout.h index f8ecbb3..ae8ccde 100644 --- a/Sources/MMMCommonUIObjC/MMMLayout.h +++ b/Sources/MMMCommonUIObjC/MMMLayout.h @@ -3,113 +3,10 @@ // Copyright (C) 2016-2020 MediaMonks. All rights reserved. // -#import +@import UIKit; NS_ASSUME_NONNULL_BEGIN -/** - * This is to group a few simple layout helpers. - */ -@interface MMMLayoutUtils : NSObject - -/** - * A rect with the given size positioned inside of the target rect in such a way that anchor points of both rects align. - * - * Anchor points are given relative to the sizes of the corresponding rects, similar to CALayer's `anchorPoint` - * property. For example, `CGPointMake(0.5, 0.5)` represents a center of any rect; `CGPointMake(1, 0.5)` means - * the center point of the right vertical edge. - * - * Note that the origin of the rect returned is rounded to the nearest pixels (not points!). - * - * See `rectWithSize:inRect:contentMode:` for a shortcut supporting UIViewContentMode. - */ -+ (CGRect)rectWithSize:(CGSize)size anchor:(CGPoint)anchor withinRect:(CGRect)targetRect anchor:(CGPoint)targetAnchor - NS_SWIFT_NAME(rect(withSize:anchor:withinRect:anchor:)); - -/** - * A shortcut for the above method with anchors being the same for both source and target rect. - * (This way the resulting rect will be always inside of the target one, assuming anchors are within [0; 1] range.) - */ -+ (CGRect)rectWithSize:(CGSize)size withinRect:(CGRect)targetRect anchor:(CGPoint)anchor - NS_SWIFT_NAME(rect(withSize:withinRect:anchor:)); - -/** - * A frame for the `sourceRect` positioned within the `targetRect` according to standard `UIViewContentMode` flags - * related to the layout (i.e. all except `UIViewContentModeRedraw`). - * - * Note that the origin of the resulting rectangle is always rounded to the nearest pixel. - */ -+ (CGRect)rectWithSize:(CGSize)size withinRect:(CGRect)targetRect contentMode:(UIViewContentMode)contentMode - NS_SWIFT_NAME(rect(withSize:withinRect:contentMode:)); - -/** - * A frame of the given size with its center at the specified point (assuming the center is defined by the given anchor - * point). - * - * Note that the origin of the resulting rectangle is rounded to the nearest pixel boundary. - */ -+ (CGRect)rectWithSize:(CGSize)size atPoint:(CGPoint)center anchor:(CGPoint)anchor - NS_SWIFT_NAME(rect(withSize:atPoint:anchor:)); - -/** Same as rectWithSize:center:anchor: with anchor set to (0.5, 0.5). */ -+ (CGRect)rectWithSize:(CGSize)size center:(CGPoint)center - NS_SWIFT_NAME(rect(withSize:center:)); - -@end - -/** - * Suppose you need to contrain a view so its center divides its container in certain ratio different from 1:1 - * (e.g. golden section): - * - * ┌─────────┐ ◆ - * │ │ │ - * │ │ │ a - * │┌───────┐│ │ - * ─│┼ ─ ─ ─ ┼│─◆ ratio = a / b - * │└───────┘│ │ - * │ │ │ - * │ │ │ - * │ │ │ b - * │ │ │ - * │ │ │ - * │ │ │ - * └─────────┘ ◆ - * - * You cannot put this ratio directly into the `multiplier` parameter of the corresponding NSLayoutConstraints relating - * the centers of the views, because the `multiplier` would be the ratio between the distance to the center - * of the view (`h`) and the distance to the center of the container (`H`) instead: - * - * ◆ ┌─────────┐ ◆ - * │ │ │ │ - * │ │ │ │ a = h - * H │ │┌───────┐│ │ - * │ │├ ─ ─ ─ ┼│─◆ multiplier = h / H - * │ │└───────┘│ │ ratio = a / b = h / (2 * H - h) - * ◆─│─ ─ ─ ─ ─│ │ - * │ │ │ - * │ │ │ b = 2 * H - h - * │ │ │ - * │ │ │ - * │ │ │ - * └─────────┘ ◆ - * - * I.e. the `multiplier` is h / H (assuming the view is the first in the definition of the constraint), - * but the ratio we are interested would be h / (2 * H - h) if expressed in the distances to centers. - * - * If you have a desired ratio and want to get a `multiplier`, which when applied, results in the layout dividing - * the container in this ratio, then you can use this function as shortcut. - * - * Detailed calculations: - * ratio = h / (2 * H - h) ==> 2 * H * ratio - h * ratio = h ==> 2 * H * ratio / h - ratio = 1 - * ==> 1 + ratio = 2 * H * ratio / h ==> (1 + ratio) / (2 * ratio) = H / h - * where H / h is the inverse of our `multiplier`, so the actual multiplier is (2 * ratio) / (1 + ratio). - */ -static -NS_SWIFT_NAME(MMMLayoutUtils.centerMultiplier(forRatio:)) -inline CGFloat MMMCenterMultiplierForRatio(CGFloat ratio) { - return (2 * ratio) / (1 + ratio); -} - /** * Auto Layout does not support relationships between empty spaces, so we need to use spacer views and set such * constraints between them. This one is a transparent and by default hidden view which can be used as such a spacer. @@ -125,30 +22,6 @@ inline CGFloat MMMCenterMultiplierForRatio(CGFloat ratio) { @end -/** - * Auto Layout does not support constraints against groups of items, so this is for the cases a normal UIView is - * typically used as a container for such a group. - * Unlike UIView we have translatesAutoresizingMaskIntoConstraints set to NO already. - * Also `MMMContainerView` does not intercept touches but subviews still do. - */ -@interface MMMContainerView : UIView - -- (nonnull id)init NS_DESIGNATED_INITIALIZER; - -- (id)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE; -- (id)initWithFrame:(CGRect)frame NS_UNAVAILABLE; - -@end - -/** Golden ratio constant. */ -extern CGFloat const MMMGolden NS_SWIFT_NAME(MMMLayoutUtils.golden); - -/** 1 divided by golden ratio. */ -extern CGFloat const MMMInverseGolden NS_SWIFT_NAME(MMMLayoutUtils.inverseGolden); - -#define MMM_GOLDEN (MMMGolden) -#define MMM_INVERSE_GOLDEN (MMMInverseGolden) - /** General alignment flags used when it's not important which direction (vertical or horizontal) the alignment is for. */ typedef NS_ENUM(NSInteger, MMMLayoutAlignment) { MMMLayoutAlignmentNone, @@ -303,7 +176,7 @@ static inline MMMLayoutAlignment MMMLayoutAlignmentFromVerticalAlignment(MMMLayo - (void)mmm_addConstraintsHorizontallyCenteringView:(UIView *)view minPadding:(CGFloat)minPadding NS_SWIFT_UNAVAILABLE(""); -#pragma mark - To be depcreated soon +#pragma mark - To be deprecated soon /** * Adds constraints anchoring the given subview within the receiver according to horizontal and vertical alignment flags. @@ -465,7 +338,7 @@ extern NSDictionary *MMMDictionaryFromUIEdgeInsets(NSStr /** * A container which lays out its subviews in certain direction one after another using fixed spacing between them. - * It also aligns all the items along the layout line acccoring to the given alignment settings. + * It also aligns all the items along the layout line according to the given alignment settings. * Note that you must use setSubviews: method instead of feeding them one by one via `addSubview:`. * This is kind of a `UIStackView` that we understand the internals of. */ diff --git a/Sources/MMMCommonUIObjC/MMMLayout.m b/Sources/MMMCommonUIObjC/MMMLayout.m index 39cc747..6e2a0d8 100644 --- a/Sources/MMMCommonUIObjC/MMMLayout.m +++ b/Sources/MMMCommonUIObjC/MMMLayout.m @@ -12,107 +12,9 @@ #endif #import "MMMCommonUIMisc.h" -#import - -// -// -// -@implementation MMMLayoutUtils - -+ (CGRect)rectWithSize:(CGSize)size anchor:(CGPoint)anchor withinRect:(CGRect)targetRect anchor:(CGPoint)targetAnchor { - return MMMPixelIntegralRect(CGRectMake( - targetRect.origin.x + targetRect.size.width * targetAnchor.x - size.width * anchor.x, - targetRect.origin.y + targetRect.size.height * targetAnchor.y - size.height * anchor.y, - size.width, - size.height - )); -} - -+ (CGRect)rectWithSize:(CGSize)size withinRect:(CGRect)targetRect anchor:(CGPoint)anchor { - return MMMPixelIntegralRect(CGRectMake( - targetRect.origin.x + (targetRect.size.width - size.width) * anchor.x, - targetRect.origin.y + (targetRect.size.height - size.height) * anchor.y, - size.width, - size.height - )); -} - -+ (CGRect)rectWithSize:(CGSize)size withinRect:(CGRect)targetRect contentMode:(UIViewContentMode)contentMode { - - switch (contentMode) { - - case UIViewContentModeScaleToFill: - // Not much sense using this routine with this mode, but well, maybe it's coming from the corresponding property of UIView here - return targetRect; - - case UIViewContentModeScaleAspectFit: - case UIViewContentModeScaleAspectFill: - { - double scaleX = targetRect.size.width / size.width; - double scaleY = targetRect.size.height / size.height; - double scale = (contentMode == UIViewContentModeScaleAspectFit) ? MIN(scaleX, scaleY) : MAX(scaleX, scaleY); - CGFloat resultWidth = size.width * scale; - CGFloat resultHeight = size.height * scale; - return MMMPixelIntegralRect( - CGRectMake( - targetRect.origin.x + (targetRect.size.width - resultWidth) * 0.5f, - targetRect.origin.y + (targetRect.size.height - resultHeight) * 0.5f, - resultWidth, - resultHeight - ) - ); - } - - case UIViewContentModeRedraw: - NSAssert(NO, @"UIViewContentModeRedraw does not make any sense for %s", sel_getName(_cmd)); - return targetRect; - - case UIViewContentModeCenter: - return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0.5, 0.5)]; - - case UIViewContentModeTop: - return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0.5, 0)]; - - case UIViewContentModeBottom: - return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0.5, 1)]; - - case UIViewContentModeLeft: - return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0, 0.5)]; - - case UIViewContentModeRight: - return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(1, 0.5)]; - - case UIViewContentModeTopLeft: - return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0, 0)]; - - case UIViewContentModeTopRight: - return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(1, 0)]; - - case UIViewContentModeBottomLeft: - return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0, 1)]; - - case UIViewContentModeBottomRight: - return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(1, 1)]; - } -} +#import "MMMLayoutUtils.h" -+ (CGRect)rectWithSize:(CGSize)size atPoint:(CGPoint)point anchor:(CGPoint)anchor { - return MMMPixelIntegralRect(CGRectMake( - point.x - size.width * anchor.x, - point.y - size.height * anchor.y, - size.width, - size.height - )); -} - -+ (CGRect)rectWithSize:(CGSize)size center:(CGPoint)center { - return [self rectWithSize:size atPoint:center anchor:CGPointMake(.5f, .5f)]; -} - -@end - -CGFloat const MMMGolden = 1.47093999 * 1.10; // 110% adjusted. -CGFloat const MMMInverseGolden = 1 / MMMGolden; +#import // // @@ -151,34 +53,6 @@ - (CGSize)intrinsicContentSize { // // -@implementation MMMContainerView - -- (id)init { - - if (self = [super initWithFrame:CGRectZero]) { - self.translatesAutoresizingMaskIntoConstraints = NO; - } - - return self; -} - -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { - - UIView *view = [super hitTest:point withEvent:event]; - - if (view == self) { - return nil; - } else { - return view; - } -} - -@end - -// -// -// - #pragma mark - Auto Layout helpers shared between UIView and UILayoutGuide static inline BOOL MMMLayoutUtilsIsKindOfCenterAlignment(MMMLayoutAlignment alignment) { diff --git a/Sources/MMMCommonUIObjC/MMMLayoutUtils.h b/Sources/MMMCommonUIObjC/MMMLayoutUtils.h new file mode 100644 index 0000000..775e12f --- /dev/null +++ b/Sources/MMMCommonUIObjC/MMMLayoutUtils.h @@ -0,0 +1,122 @@ +// +// MMMCommonUI. Part of MMMTemple. +// Copyright (C) 2016-2020 MediaMonks. All rights reserved. +// + +@import UIKit; + +NS_ASSUME_NONNULL_BEGIN + +/** + * This is to group a few simple layout helpers. + */ +@interface MMMLayoutUtils : NSObject + +/** + * A rect with the given size positioned inside of the target rect in such a way that anchor points of both rects align. + * + * Anchor points are given relative to the sizes of the corresponding rects, similar to CALayer's `anchorPoint` + * property. For example, `CGPointMake(0.5, 0.5)` represents a center of any rect; `CGPointMake(1, 0.5)` means + * the center point of the right vertical edge. + * + * Note that the origin of the rect returned is rounded to the nearest pixels (not points!). + * + * See `rectWithSize:inRect:contentMode:` for a shortcut supporting UIViewContentMode. + */ ++ (CGRect)rectWithSize:(CGSize)size anchor:(CGPoint)anchor withinRect:(CGRect)targetRect anchor:(CGPoint)targetAnchor + NS_SWIFT_NAME(rect(withSize:anchor:withinRect:anchor:)); + +/** + * A shortcut for the above method with anchors being the same for both source and target rect. + * (This way the resulting rect will be always inside of the target one, assuming anchors are within [0; 1] range.) + */ ++ (CGRect)rectWithSize:(CGSize)size withinRect:(CGRect)targetRect anchor:(CGPoint)anchor + NS_SWIFT_NAME(rect(withSize:withinRect:anchor:)); + +/** + * A frame for the `sourceRect` positioned within the `targetRect` according to standard `UIViewContentMode` flags + * related to the layout (i.e. all except `UIViewContentModeRedraw`). + * + * Note that the origin of the resulting rectangle is always rounded to the nearest pixel. + */ ++ (CGRect)rectWithSize:(CGSize)size withinRect:(CGRect)targetRect contentMode:(UIViewContentMode)contentMode + NS_SWIFT_NAME(rect(withSize:withinRect:contentMode:)); + +/** + * A frame of the given size with its center at the specified point (assuming the center is defined by the given anchor + * point). + * + * Note that the origin of the resulting rectangle is rounded to the nearest pixel boundary. + */ ++ (CGRect)rectWithSize:(CGSize)size atPoint:(CGPoint)center anchor:(CGPoint)anchor + NS_SWIFT_NAME(rect(withSize:atPoint:anchor:)); + +/** Same as rectWithSize:center:anchor: with anchor set to (0.5, 0.5). */ ++ (CGRect)rectWithSize:(CGSize)size center:(CGPoint)center + NS_SWIFT_NAME(rect(withSize:center:)); + +@end + +/** + * Suppose you need to contrain a view so its center divides its container in certain ratio different from 1:1 + * (e.g. golden section): + * + * ┌─────────┐ ◆ + * │ │ │ + * │ │ │ a + * │┌───────┐│ │ + * ─│┼ ─ ─ ─ ┼│─◆ ratio = a / b + * │└───────┘│ │ + * │ │ │ + * │ │ │ + * │ │ │ b + * │ │ │ + * │ │ │ + * │ │ │ + * └─────────┘ ◆ + * + * You cannot put this ratio directly into the `multiplier` parameter of the corresponding NSLayoutConstraints relating + * the centers of the views, because the `multiplier` would be the ratio between the distance to the center + * of the view (`h`) and the distance to the center of the container (`H`) instead: + * + * ◆ ┌─────────┐ ◆ + * │ │ │ │ + * │ │ │ │ a = h + * H │ │┌───────┐│ │ + * │ │├ ─ ─ ─ ┼│─◆ multiplier = h / H + * │ │└───────┘│ │ ratio = a / b = h / (2 * H - h) + * ◆─│─ ─ ─ ─ ─│ │ + * │ │ │ + * │ │ │ b = 2 * H - h + * │ │ │ + * │ │ │ + * │ │ │ + * └─────────┘ ◆ + * + * I.e. the `multiplier` is h / H (assuming the view is the first in the definition of the constraint), + * but the ratio we are interested would be h / (2 * H - h) if expressed in the distances to centers. + * + * If you have a desired ratio and want to get a `multiplier`, which when applied, results in the layout dividing + * the container in this ratio, then you can use this function as shortcut. + * + * Detailed calculations: + * ratio = h / (2 * H - h) ==> 2 * H * ratio - h * ratio = h ==> 2 * H * ratio / h - ratio = 1 + * ==> 1 + ratio = 2 * H * ratio / h ==> (1 + ratio) / (2 * ratio) = H / h + * where H / h is the inverse of our `multiplier`, so the actual multiplier is (2 * ratio) / (1 + ratio). + */ +static +NS_SWIFT_NAME(MMMLayoutUtils.centerMultiplier(forRatio:)) +inline CGFloat MMMCenterMultiplierForRatio(CGFloat ratio) { + return (2 * ratio) / (1 + ratio); +} + +/** Golden ratio constant. */ +extern CGFloat const MMMGolden NS_SWIFT_NAME(MMMLayoutUtils.golden); + +/** 1 divided by golden ratio. */ +extern CGFloat const MMMInverseGolden NS_SWIFT_NAME(MMMLayoutUtils.inverseGolden); + +#define MMM_GOLDEN (MMMGolden) +#define MMM_INVERSE_GOLDEN (MMMInverseGolden) + +NS_ASSUME_NONNULL_END diff --git a/Sources/MMMCommonUIObjC/MMMLayoutUtils.m b/Sources/MMMCommonUIObjC/MMMLayoutUtils.m new file mode 100644 index 0000000..18a3f5f --- /dev/null +++ b/Sources/MMMCommonUIObjC/MMMLayoutUtils.m @@ -0,0 +1,115 @@ +// +// MMMCommonUI. Part of MMMTemple. +// Copyright (C) 2016-2020 MediaMonks. All rights reserved. +// + +#import "MMMLayoutUtils.h" + +#if SWIFT_PACKAGE +@import MMMCommonCoreObjC; +#else +@import MMMCommonCore; +#endif + +#import "MMMCommonUIMisc.h" +#import + +// +// +// +@implementation MMMLayoutUtils + ++ (CGRect)rectWithSize:(CGSize)size anchor:(CGPoint)anchor withinRect:(CGRect)targetRect anchor:(CGPoint)targetAnchor { + return MMMPixelIntegralRect(CGRectMake( + targetRect.origin.x + targetRect.size.width * targetAnchor.x - size.width * anchor.x, + targetRect.origin.y + targetRect.size.height * targetAnchor.y - size.height * anchor.y, + size.width, + size.height + )); +} + ++ (CGRect)rectWithSize:(CGSize)size withinRect:(CGRect)targetRect anchor:(CGPoint)anchor { + return MMMPixelIntegralRect(CGRectMake( + targetRect.origin.x + (targetRect.size.width - size.width) * anchor.x, + targetRect.origin.y + (targetRect.size.height - size.height) * anchor.y, + size.width, + size.height + )); +} + ++ (CGRect)rectWithSize:(CGSize)size withinRect:(CGRect)targetRect contentMode:(UIViewContentMode)contentMode { + + switch (contentMode) { + + case UIViewContentModeScaleToFill: + // Not much sense using this routine with this mode, but well, maybe it's coming from the corresponding property of UIView here + return targetRect; + + case UIViewContentModeScaleAspectFit: + case UIViewContentModeScaleAspectFill: + { + double scaleX = targetRect.size.width / size.width; + double scaleY = targetRect.size.height / size.height; + double scale = (contentMode == UIViewContentModeScaleAspectFit) ? MIN(scaleX, scaleY) : MAX(scaleX, scaleY); + CGFloat resultWidth = size.width * scale; + CGFloat resultHeight = size.height * scale; + return MMMPixelIntegralRect( + CGRectMake( + targetRect.origin.x + (targetRect.size.width - resultWidth) * 0.5f, + targetRect.origin.y + (targetRect.size.height - resultHeight) * 0.5f, + resultWidth, + resultHeight + ) + ); + } + + case UIViewContentModeRedraw: + NSAssert(NO, @"UIViewContentModeRedraw does not make any sense for %s", sel_getName(_cmd)); + return targetRect; + + case UIViewContentModeCenter: + return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0.5, 0.5)]; + + case UIViewContentModeTop: + return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0.5, 0)]; + + case UIViewContentModeBottom: + return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0.5, 1)]; + + case UIViewContentModeLeft: + return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0, 0.5)]; + + case UIViewContentModeRight: + return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(1, 0.5)]; + + case UIViewContentModeTopLeft: + return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0, 0)]; + + case UIViewContentModeTopRight: + return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(1, 0)]; + + case UIViewContentModeBottomLeft: + return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(0, 1)]; + + case UIViewContentModeBottomRight: + return [self rectWithSize:size withinRect:targetRect anchor:CGPointMake(1, 1)]; + } +} + ++ (CGRect)rectWithSize:(CGSize)size atPoint:(CGPoint)point anchor:(CGPoint)anchor { + return MMMPixelIntegralRect(CGRectMake( + point.x - size.width * anchor.x, + point.y - size.height * anchor.y, + size.width, + size.height + )); +} + ++ (CGRect)rectWithSize:(CGSize)size center:(CGPoint)center { + return [self rectWithSize:size atPoint:center anchor:CGPointMake(.5f, .5f)]; +} + +@end + +CGFloat const MMMGolden = 1.47093999 * 1.10; // 110% adjusted. +CGFloat const MMMInverseGolden = 1 / MMMGolden; diff --git a/Sources/MMMCommonUIObjC/MMMStubView.m b/Sources/MMMCommonUIObjC/MMMStubView.m index b840ca7..3547aba 100644 --- a/Sources/MMMCommonUIObjC/MMMStubView.m +++ b/Sources/MMMCommonUIObjC/MMMStubView.m @@ -6,7 +6,7 @@ #import "MMMStubView.h" #import "MMMCommonUIMisc.h" -#import "MMMLayout.h" +#import "MMMLayoutUtils.h" @implementation MMMStubView { UILabel *_label;