123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- //
- // FLEXArgumentInputColorView.m
- // Flipboard
- //
- // Created by Ryan Olson on 6/30/14.
- // Copyright (c) 2020 FLEX Team. All rights reserved.
- //
- #import "FLEXArgumentInputColorView.h"
- #import "FLEXUtility.h"
- #import "FLEXRuntimeUtility.h"
- #import "fakes.h"
- @protocol FLEXColorComponentInputViewDelegate;
- @interface FLEXColorComponentInputView : UIView
- #if !TARGET_OS_TV
- @property (nonatomic) UISlider *slider;
- #else
- @property (nonatomic) KBSlider *slider;
- #endif
- @property (nonatomic) UILabel *valueLabel;
- @property (nonatomic, weak) id <FLEXColorComponentInputViewDelegate> delegate;
- @end
- @protocol FLEXColorComponentInputViewDelegate <NSObject>
- - (void)colorComponentInputViewValueDidChange:(FLEXColorComponentInputView *)colorComponentInputView;
- @end
- @implementation FLEXColorComponentInputView
- - (id)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- #if !TARGET_OS_TV
- self.slider = [UISlider new];
- #else
- self.slider = [[KBSlider alloc] initWithFrame:CGRectMake(0, 0, 1000, 53)];
- #endif
- [self.slider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
- [self addSubview:self.slider];
-
- self.valueLabel = [UILabel new];
- self.valueLabel.backgroundColor = self.backgroundColor;
- self.valueLabel.font = [UIFont systemFontOfSize:14.0];
- self.valueLabel.textAlignment = NSTextAlignmentRight;
- [self addSubview:self.valueLabel];
-
- [self updateValueLabel];
- }
- return self;
- }
- - (void)setBackgroundColor:(UIColor *)backgroundColor {
- [super setBackgroundColor:backgroundColor];
- self.slider.backgroundColor = backgroundColor;
- self.valueLabel.backgroundColor = backgroundColor;
- }
- - (void)layoutSubviews {
- [super layoutSubviews];
-
- const CGFloat kValueLabelWidth = 50.0;
- UIEdgeInsets sliderInset = UIEdgeInsetsZero;
- #if TARGET_OS_TV
- sliderInset.left = 40;
- sliderInset.right = 40;
- #endif
- [self.slider sizeToFit];
- CGFloat sliderWidth = self.bounds.size.width - kValueLabelWidth - sliderInset.left - sliderInset.right;
- self.slider.frame = CGRectMake(sliderInset.left, 0, sliderWidth, self.slider.frame.size.height);
-
- [self.valueLabel sizeToFit];
- CGFloat valueLabelOriginX = CGRectGetMaxX(self.slider.frame) + sliderInset.right/2.0;
- CGFloat valueLabelOriginY = FLEXFloor((self.slider.frame.size.height - self.valueLabel.frame.size.height) / 2.0);
- self.valueLabel.frame = CGRectMake(valueLabelOriginX, valueLabelOriginY, kValueLabelWidth, self.valueLabel.frame.size.height);
- }
- - (void)sliderChanged:(id)sender {
- [self.delegate colorComponentInputViewValueDidChange:self];
- [self updateValueLabel];
- }
- - (void)updateValueLabel {
- self.valueLabel.text = [NSString stringWithFormat:@"%.3f", self.slider.value];
- }
- - (CGSize)sizeThatFits:(CGSize)size {
- CGFloat height = [self.slider sizeThatFits:size].height;
- return CGSizeMake(size.width, height);
- }
- @end
- @interface FLEXColorPreviewBox : UIView
- @property (nonatomic) UIColor *color;
- @property (nonatomic) UIView *colorOverlayView;
- @end
- @implementation FLEXColorPreviewBox
- - (id)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- self.layer.borderWidth = 1.0;
- self.layer.borderColor = UIColor.blackColor.CGColor;
- self.backgroundColor = [UIColor colorWithPatternImage:[[self class] backgroundPatternImage]];
-
- self.colorOverlayView = [[UIView alloc] initWithFrame:self.bounds];
- self.colorOverlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- self.colorOverlayView.backgroundColor = UIColor.clearColor;
- [self addSubview:self.colorOverlayView];
- }
- return self;
- }
- - (void)setColor:(UIColor *)color {
- self.colorOverlayView.backgroundColor = color;
- }
- - (UIColor *)color {
- return self.colorOverlayView.backgroundColor;
- }
- + (UIImage *)backgroundPatternImage {
- const CGFloat kSquareDimension = 5.0;
- CGSize squareSize = CGSizeMake(kSquareDimension, kSquareDimension);
- CGSize imageSize = CGSizeMake(2.0 * kSquareDimension, 2.0 * kSquareDimension);
-
- UIGraphicsBeginImageContextWithOptions(imageSize, YES, UIScreen.mainScreen.scale);
-
- [UIColor.whiteColor setFill];
- UIRectFill(CGRectMake(0, 0, imageSize.width, imageSize.height));
-
- [UIColor.grayColor setFill];
- UIRectFill(CGRectMake(squareSize.width, 0, squareSize.width, squareSize.height));
- UIRectFill(CGRectMake(0, squareSize.height, squareSize.width, squareSize.height));
-
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- return image;
- }
- @end
- @interface FLEXArgumentInputColorView () <FLEXColorComponentInputViewDelegate>
- @property (nonatomic) FLEXColorPreviewBox *colorPreviewBox;
- @property (nonatomic) UILabel *hexLabel;
- @property (nonatomic) FLEXColorComponentInputView *alphaInput;
- @property (nonatomic) FLEXColorComponentInputView *redInput;
- @property (nonatomic) FLEXColorComponentInputView *greenInput;
- @property (nonatomic) FLEXColorComponentInputView *blueInput;
- @end
- @implementation FLEXArgumentInputColorView
- - (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
- self = [super initWithArgumentTypeEncoding:typeEncoding];
- if (self) {
- self.colorPreviewBox = [FLEXColorPreviewBox new];
- [self addSubview:self.colorPreviewBox];
-
- self.hexLabel = [UILabel new];
- self.hexLabel.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.9];
- self.hexLabel.textAlignment = NSTextAlignmentCenter;
- self.hexLabel.font = [UIFont systemFontOfSize:12.0];
- [self addSubview:self.hexLabel];
-
- self.alphaInput = [FLEXColorComponentInputView new];
- self.alphaInput.slider.minimumTrackTintColor = UIColor.blackColor;
- self.alphaInput.delegate = self;
- [self addSubview:self.alphaInput];
-
- self.redInput = [FLEXColorComponentInputView new];
- self.redInput.slider.minimumTrackTintColor = UIColor.redColor;
- self.redInput.delegate = self;
- [self addSubview:self.redInput];
-
- self.greenInput = [FLEXColorComponentInputView new];
- self.greenInput.slider.minimumTrackTintColor = UIColor.greenColor;
- self.greenInput.delegate = self;
- [self addSubview:self.greenInput];
-
- self.blueInput = [FLEXColorComponentInputView new];
- self.blueInput.slider.minimumTrackTintColor = UIColor.blueColor;
- self.blueInput.delegate = self;
- [self addSubview:self.blueInput];
- }
- return self;
- }
- - (void)setBackgroundColor:(UIColor *)backgroundColor {
- [super setBackgroundColor:backgroundColor];
- self.alphaInput.backgroundColor = backgroundColor;
- self.redInput.backgroundColor = backgroundColor;
- self.greenInput.backgroundColor = backgroundColor;
- self.blueInput.backgroundColor = backgroundColor;
- }
- - (void)layoutSubviews {
- [super layoutSubviews];
-
- CGFloat runningOriginY = 0;
- CGSize constrainSize = CGSizeMake(self.bounds.size.width, CGFLOAT_MAX);
-
- self.colorPreviewBox.frame = CGRectMake(0, runningOriginY, self.bounds.size.width, [[self class] colorPreviewBoxHeight]);
- runningOriginY = CGRectGetMaxY(self.colorPreviewBox.frame) + [[self class] inputViewVerticalPadding];
-
- [self.hexLabel sizeToFit];
- const CGFloat kLabelVerticalOutsetAmount = 0.0;
- const CGFloat kLabelHorizontalOutsetAmount = 2.0;
- UIEdgeInsets labelOutset = UIEdgeInsetsMake(-kLabelVerticalOutsetAmount, -kLabelHorizontalOutsetAmount, -kLabelVerticalOutsetAmount, -kLabelHorizontalOutsetAmount);
- self.hexLabel.frame = UIEdgeInsetsInsetRect(self.hexLabel.frame, labelOutset);
- CGFloat hexLabelOriginX = self.colorPreviewBox.layer.borderWidth;
- CGFloat hexLabelOriginY = CGRectGetMaxY(self.colorPreviewBox.frame) - self.colorPreviewBox.layer.borderWidth - self.hexLabel.frame.size.height;
- self.hexLabel.frame = CGRectMake(hexLabelOriginX, hexLabelOriginY, self.hexLabel.frame.size.width, self.hexLabel.frame.size.height);
-
- NSArray<FLEXColorComponentInputView *> *colorComponentInputViews = @[self.alphaInput, self.redInput, self.greenInput, self.blueInput];
- for (FLEXColorComponentInputView *inputView in colorComponentInputViews) {
- CGSize fitSize = [inputView sizeThatFits:constrainSize];
- inputView.frame = CGRectMake(0, runningOriginY, fitSize.width, fitSize.height);
- runningOriginY = CGRectGetMaxY(inputView.frame) + [[self class] inputViewVerticalPadding];
- }
- }
- - (void)setInputValue:(id)inputValue {
- if ([inputValue isKindOfClass:[UIColor class]]) {
- [self updateWithColor:inputValue];
- } else if ([inputValue isKindOfClass:[NSValue class]]) {
- const char *type = [inputValue objCType];
- if (strcmp(type, @encode(CGColorRef)) == 0) {
- CGColorRef colorRef;
- [inputValue getValue:&colorRef];
- UIColor *color = [[UIColor alloc] initWithCGColor:colorRef];
- [self updateWithColor:color];
- }
- } else {
- [self updateWithColor:UIColor.clearColor];
- }
- }
- - (id)inputValue {
- return [UIColor colorWithRed:self.redInput.slider.value green:self.greenInput.slider.value blue:self.blueInput.slider.value alpha:self.alphaInput.slider.value];
- }
- - (void)colorComponentInputViewValueDidChange:(FLEXColorComponentInputView *)colorComponentInputView {
- [self updateColorPreview];
- }
- - (void)updateWithColor:(UIColor *)color {
- CGFloat red, green, blue, white, alpha;
- if ([color getRed:&red green:&green blue:&blue alpha:&alpha]) {
- self.alphaInput.slider.value = alpha;
- [self.alphaInput updateValueLabel];
- self.redInput.slider.value = red;
- [self.redInput updateValueLabel];
- self.greenInput.slider.value = green;
- [self.greenInput updateValueLabel];
- self.blueInput.slider.value = blue;
- [self.blueInput updateValueLabel];
- } else if ([color getWhite:&white alpha:&alpha]) {
- self.alphaInput.slider.value = alpha;
- [self.alphaInput updateValueLabel];
- self.redInput.slider.value = white;
- [self.redInput updateValueLabel];
- self.greenInput.slider.value = white;
- [self.greenInput updateValueLabel];
- self.blueInput.slider.value = white;
- [self.blueInput updateValueLabel];
- }
- [self updateColorPreview];
- }
- - (void)updateColorPreview {
- self.colorPreviewBox.color = self.inputValue;
- unsigned char redByte = self.redInput.slider.value * 255;
- unsigned char greenByte = self.greenInput.slider.value * 255;
- unsigned char blueByte = self.blueInput.slider.value * 255;
- self.hexLabel.text = [NSString stringWithFormat:@"#%02X%02X%02X", redByte, greenByte, blueByte];
- [self setNeedsLayout];
- }
- - (CGSize)sizeThatFits:(CGSize)size {
- CGFloat height = 0;
- height += [[self class] colorPreviewBoxHeight];
- height += [[self class] inputViewVerticalPadding];
- height += [self.alphaInput sizeThatFits:size].height;
- height += [[self class] inputViewVerticalPadding];
- height += [self.redInput sizeThatFits:size].height;
- height += [[self class] inputViewVerticalPadding];
- height += [self.greenInput sizeThatFits:size].height;
- height += [[self class] inputViewVerticalPadding];
- height += [self.blueInput sizeThatFits:size].height;
- return CGSizeMake(size.width, height);
- }
- + (CGFloat)inputViewVerticalPadding {
- return 10.0;
- }
- + (CGFloat)colorPreviewBoxHeight {
- return 40.0;
- }
- + (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
- NSParameterAssert(type);
- // We don't care if currentValue is a color or not; we will default to +clearColor
- return (strcmp(type, @encode(CGColorRef)) == 0) || (strcmp(type, FLEXEncodeClass(UIColor)) == 0);
- }
- @end
|