polyhorn-ios-sys 0.4.0

Low-level iOS bindings for Polyhorn.
Documentation
#import "PLYScrollView.h"

@implementation PLYScrollView

- (id)init {
    if ((self = [super init])) {
        self.alwaysBounceVertical = YES;
        self.opaque = NO;
        
        if (@available(iOS 11.0, *)) {
            self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        }

        if (@available(iOS 13.0, *)) {
            self.automaticallyAdjustsScrollIndicatorInsets = NO;
        }

        self.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
        self.delaysContentTouches = NO;
    }

    return self;
}

- (void)updateLayout {
    if (self.layout == nil)
        return;
    
    CGRect oldFrame = self.frame;
    CGRect newFrame = [self.layout fetch];
    
    if (CGRectEqualToRect(oldFrame, newFrame))
        return;
    
    self.frame = newFrame;
    
    for (UIView *view in self.subviews)
        [view setNeedsLayout];
}

- (void)updateContentLayout {
    CGSize oldSize = self.contentSize;
    CGSize newSize = [self.contentLayout fetch].size;

    if (CGSizeEqualToSize(oldSize, newSize))
        return;
    
    self.contentSize = newSize;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    [self updateLayout];
    [self updateContentLayout];
}

- (void)setOpaqueBackgroundColor:(UIColor *)color {
    _opaqueBackgroundColor = color;

    [self setNeedsDisplay];
}

- (CGPoint)resolvePoint:(PLYPoint)point {
    CGPoint result = CGPointZero;

    if (point.x.kind == PLYDimensionKindPixels)
        result.x = point.x.value;
    else if (point.x.kind == PLYDimensionKindPercentage)
        result.x = point.x.value * self.bounds.size.width;

    if (point.y.kind == PLYDimensionKindPixels)
        result.y = point.y.value;
    else if (point.y.kind == PLYDimensionKindPercentage)
        result.y = point.y.value * self.bounds.size.height;

    return result;
}

- (void)drawRect:(CGRect)dirtyRect {
    const CGFloat kappa = 4 * (sqrt(2.0) - 1.0) / 3.0;

    CGPoint tl = [self resolvePoint:self.cornerRadii.topLeft];
    CGPoint tr = [self resolvePoint:self.cornerRadii.topRight];
    CGPoint br = [self resolvePoint:self.cornerRadii.bottomRight];
    CGPoint bl = [self resolvePoint:self.cornerRadii.bottomLeft];

    UIBezierPath *path = [UIBezierPath bezierPath];

    // Move to the end of the top-left corner.
    [path moveToPoint:CGPointMake(tl.x, 0.0)];

    // Move to the start of the top-right corner.
    [path addLineToPoint:CGPointMake(self.bounds.size.width - tr.x, 0.0)];

    // Draw the top-right corner.
    [path addCurveToPoint:CGPointMake(self.bounds.size.width, tr.y)
            controlPoint1:CGPointMake(self.bounds.size.width - tr.x + tr.x * kappa, 0.0)
            controlPoint2:CGPointMake(self.bounds.size.width, tr.y - tr.y * kappa)];

    // Move to the start of the bottom-right corner.
    [path addLineToPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height - br.y)];

    // Draw the bottom-right corner.
    [path addCurveToPoint:CGPointMake(self.bounds.size.width - br.x, self.bounds.size.height)
            controlPoint1:CGPointMake(self.bounds.size.width, self.bounds.size.height - br.y + br.y * kappa)
            controlPoint2:CGPointMake(self.bounds.size.width - br.x + br.x * kappa, self.bounds.size.height)];

    // Move to the start of the bottom-left corner.
    [path addLineToPoint:CGPointMake(bl.x, self.bounds.size.height)];

    // Draw the bottom-left corner.
    [path addCurveToPoint:CGPointMake(0.0, self.bounds.size.height - bl.y)
            controlPoint1:CGPointMake(bl.x - bl.x * kappa, self.bounds.size.height)
            controlPoint2:CGPointMake(0.0, self.bounds.size.height - bl.y + bl.y * kappa)];

    // Move to the start of the top-left corner.
    [path addLineToPoint:CGPointMake(0.0, tl.y)];

    // Draw the bottom-left corner.
    [path addCurveToPoint:CGPointMake(tl.x, 0.0)
            controlPoint1:CGPointMake(0.0, tl.y - tl.y * kappa)
            controlPoint2:CGPointMake(tl.x - tl.x * kappa, 0.0)];

    [path closePath];

    [self.opaqueBackgroundColor setFill];
    [path fill];
}

@end