Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions DKVerticalColorPicker/DKVerticalColorPicker.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,36 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSInteger, DKColorPickerTouchType) {
DKColorPickerTouchTypeTouchesBegan,
DKColorPickerTouchTypeTouchesMoved,
DKColorPickerTouchTypeTouchesEnded
};

static const CGFloat END_OF_GRAYSCALE_SECTION = 30;

static const CGFloat END_OF_WHITE_SECTION = END_OF_GRAYSCALE_SECTION + 5;

static const CGFloat COLOR_SATURATION = 0.8;

/*!
A delegate that gets notifications when the color picked changes.
*/
@protocol DKVerticalColorPickerDelegate <NSObject>
@optional
-(void)colorPicked:(UIColor *)color;
- (void)colorPicked:(UIColor *)aColor withTouchType:(DKColorPickerTouchType)aTouchType;
@end

IB_DESIGNABLE

@interface DKVerticalColorPicker : UIView

@property (nonatomic, weak) IBOutlet id<DKVerticalColorPickerDelegate> delegate; //set after inited
@property (nonatomic) IBInspectable UIColor *selectedColor; //setting this will update the UI & notify the delegate
@property(nonatomic, weak) IBOutlet id <DKVerticalColorPickerDelegate> delegate; //set after inited
@property(nonatomic) IBInspectable UIColor *selectedColor; //setting this will update the UI & notify the delegate

- (UIColor *)getColor:(CGFloat)aY;
-(CGFloat) getYFromColor: (UIColor *) aColor;
@end
181 changes: 134 additions & 47 deletions DKVerticalColorPicker/DKVerticalColorPicker.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ of this software and associated documentation files (the "Software"), to deal

@interface DKVerticalColorPicker ()

@property (nonatomic) CGFloat currentSelectionY;
@property(nonatomic) CGFloat currentSelectionY;

@end

Expand All @@ -36,7 +36,8 @@ @implementation DKVerticalColorPicker
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
if (self)
{
self.currentSelectionY = 0.0;
self.backgroundColor = [UIColor clearColor];
}
Expand All @@ -47,36 +48,125 @@ - (instancetype)initWithFrame:(CGRect)frame
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
if (self)
{
self.currentSelectionY = 0.0;
self.backgroundColor = [UIColor clearColor];
}
return self;
}

- (void)drawRect:(CGRect)rect {
- (void)drawRect:(CGRect)rect
{
// Drawing code
[super drawRect:rect];

//draw wings
[[UIColor blackColor] set];
CGFloat tempYPlace = self.currentSelectionY;
if (tempYPlace < 0.0) {
if (tempYPlace < 0.0)
{
tempYPlace = 0.0;
} else if (tempYPlace >= self.frame.size.height) {
tempYPlace = self.frame.size.height - 1.0;
} else if (tempYPlace >= self.frame.size.height)
{
tempYPlace = self.frame.size.height - 1.0f;
}
CGRect temp = CGRectMake(0.0, tempYPlace, self.frame.size.width, 1.0);
UIRectFill(temp);

//draw central bar over it
CGFloat cbxbegin = self.frame.size.width * 0.2;
CGFloat cbwidth = self.frame.size.width * 0.6;
for (int y = 0; y < self.frame.size.height; y++) {
[[UIColor colorWithHue:(y/self.frame.size.height) saturation:1.0 brightness:1.0 alpha:1.0] set];
CGRect temp = CGRectMake(cbxbegin, y, cbwidth, 1.0);
UIRectFill(temp);
CGFloat cbxbegin = self.frame.size.width * 0.2f;
CGFloat cbwidth = self.frame.size.width * 0.6f;
for (int y = 0; y < self.frame.size.height; y++)
{
UIColor *theColor = [self getColor:y];
[theColor set];
CGRect theColorRect = CGRectMake(cbxbegin, y, cbwidth, 1.0);
UIRectFill(theColorRect);
}
}


CGFloat projectNormal(CGFloat n, CGFloat start, CGFloat end)
{
return start + (n * (end - start));
}

CGFloat normalize(CGFloat value, CGFloat startValue, CGFloat endValue)
{
return (value - startValue) / (endValue - startValue);
}

CGFloat mapInputToRange(CGFloat input, CGFloat startValue, CGFloat endValue, CGFloat outputStart, CGFloat outputEnd)
{
return projectNormal(MAX(0, MIN(1, normalize(input, startValue, endValue))), outputStart, outputEnd);
}

- (UIColor *)getColor:(CGFloat)aY
{
CGFloat theMinY = 0;
CGFloat theMaxY = [self getMaxY];

if (aY < END_OF_GRAYSCALE_SECTION)
{
return [self getGrayscaleColor:aY
fromMinY:theMinY
toMaxY:END_OF_GRAYSCALE_SECTION];
}
else if (aY < END_OF_WHITE_SECTION)
{
return [self getWhiteColor];
}
else
{
return [self getRainbowHueColor:aY fromMinY:END_OF_WHITE_SECTION toMaxY:theMaxY];
}
}

- (CGFloat)getMaxY
{
return self.frame.size.height;
}

-(CGFloat) getYFromColor: (UIColor *) aColor
{
CGFloat hue = 0.0, saturation = 0.0, brightness = 0.0, alpha = 0.0;
if ([aColor getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha])
{
if( saturation == 0 )
{
return brightness*END_OF_GRAYSCALE_SECTION;
}
else
{
return END_OF_WHITE_SECTION + hue*([ self getMaxY] - END_OF_WHITE_SECTION);
}
}

return 0;
}

- (UIColor *)getWhiteColor
{
return [UIColor colorWithHue:0 saturation:0 brightness:1 alpha:1.0];
}

- (UIColor *)getGrayscaleColor:(CGFloat)aY fromMinY:(CGFloat)aMinY toMaxY:(CGFloat)aMaxY
{
CGFloat hue = 0;
CGFloat s = 0;
CGFloat b = mapInputToRange(aY, aMinY, aMaxY, 0, 1);
UIColor *theColor = [UIColor colorWithHue:hue saturation:s brightness:b alpha:1.0];
return theColor;
}

- (UIColor *)getRainbowHueColor:(CGFloat)aY fromMinY:(CGFloat)aMinY toMaxY:(CGFloat)aMaxY
{
CGFloat hue = mapInputToRange(aY, aMinY, aMaxY, 0, 1);
CGFloat s = COLOR_SATURATION;
CGFloat b = 1;
UIColor *theColor = [UIColor colorWithHue:hue saturation:s brightness:b alpha:1.0];
return theColor;
}

/*!
Expand All @@ -86,16 +176,13 @@ - (void)setSelectedColor:(UIColor *)selectedColor
{
if (selectedColor != _selectedColor)
{
CGFloat hue = 0.0, temp = 0.0;
if ([selectedColor getHue:&hue saturation:&temp brightness:&temp alpha:&temp])
{
self.currentSelectionY = floorf(hue * self.frame.size.height);
[self setNeedsDisplay];
}
self.currentSelectionY = [ self getYFromColor: selectedColor ];
[self setNeedsDisplay];

_selectedColor = selectedColor;
if([self.delegate respondsToSelector:@selector(colorPicked:)])
if ([self.delegate respondsToSelector:@selector(colorPicked:withTouchType:)])
{
[self.delegate colorPicked:_selectedColor];
[self.delegate colorPicked:_selectedColor withTouchType: DKColorPickerTouchTypeTouchesEnded ];
}
}
}
Expand All @@ -104,42 +191,42 @@ - (void)setSelectedColor:(UIColor *)selectedColor

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//update color
self.currentSelectionY = [((UITouch *)[touches anyObject]) locationInView:self].y;
_selectedColor = [UIColor colorWithHue:(self.currentSelectionY / self.frame.size.height) saturation:1.0 brightness:1.0 alpha:1.0];
//notify delegate
if([self.delegate respondsToSelector:@selector(colorPicked:)])
{
[self.delegate colorPicked:self.selectedColor];
}
[self updateColor:touches];
[self notifyDelegate:DKColorPickerTouchTypeTouchesBegan];
[self setNeedsDisplay];
}

- (void)updateColor:(const NSSet *)touches
{
self.currentSelectionY = [((UITouch *) [touches anyObject]) locationInView:self].y;
_selectedColor = [self getColor:self.currentSelectionY];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//update color
self.currentSelectionY = [((UITouch *)[touches anyObject]) locationInView:self].y;
_selectedColor = [UIColor colorWithHue:(self.currentSelectionY / self.frame.size.height) saturation:1.0 brightness:1.0 alpha:1.0];
//notify delegate
if([self.delegate respondsToSelector:@selector(colorPicked:)])
{
[self.delegate colorPicked:self.selectedColor];
}
[self updateColor:touches];
[self notifyDelegate:DKColorPickerTouchTypeTouchesMoved];
[self setNeedsDisplay];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//update color
self.currentSelectionY = [((UITouch *)[touches anyObject]) locationInView:self].y;
_selectedColor = [UIColor colorWithHue:(self.currentSelectionY / self.frame.size.height) saturation:1.0 brightness:1.0 alpha:1.0];
//notify delegate
if([self.delegate respondsToSelector:@selector(colorPicked:)])
[self updateColor:touches];

[self notifyDelegate:DKColorPickerTouchTypeTouchesEnded];
[self setNeedsDisplay];
}

- (void)notifyDelegate:(DKColorPickerTouchType)aTouchType
{
if ([self.delegate respondsToSelector:@selector(colorPicked:withTouchType:)])
{
[self.delegate colorPicked:self.selectedColor];
[self.delegate colorPicked:self.selectedColor withTouchType:aTouchType];
}
[self setNeedsDisplay];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{

}
@end
2 changes: 1 addition & 1 deletion DKVerticalColorPicker/ViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

@interface ViewController : UIViewController <DKVerticalColorPickerDelegate>

-(void)colorPicked:(UIColor *)color;
- (void)colorPicked:(UIColor *)aColor withTouchType:(DKColorPickerTouchType)aTouchType;

@end

4 changes: 2 additions & 2 deletions DKVerticalColorPicker/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ - (void)didReceiveMemoryWarning {
// Dispose of any resources that can be recreated.
}

-(void)colorPicked:(UIColor *)color
- (void)colorPicked:(UIColor *)aColor withTouchType:(DKColorPickerTouchType)aTouchType
{
self.sampleView.backgroundColor = color;
self.sampleView.backgroundColor = aColor;
}

@end
64 changes: 54 additions & 10 deletions DKVerticalColorPickerTests/DKVerticalColorPickerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,77 @@

#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "DKVerticalColorPicker.h"

@interface DKVerticalColorPickerTests : XCTestCase

@end

@implementation DKVerticalColorPickerTests

- (void)setUp {
- (void)setUp
{
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}

- (void)tearDown {
- (void)tearDown
{
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}

- (void)testExample {
// This is an example of a functional test case.
XCTAssert(YES, @"Pass");
- (void)testBlack
{
DKVerticalColorPicker* thePicker = [self createTestColorPicker];
CGFloat theY = 0;
UIColor *theBlackColor = [UIColor colorWithHue:0 saturation:0 brightness:0 alpha:1];
XCTAssertTrue([self isColor:theBlackColor
equalToColor:[thePicker getColor:theY]], @"should start with black");
}

- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
- (void)testWhite
{
DKVerticalColorPicker* thePicker = [self createTestColorPicker];
CGFloat theY = END_OF_GRAYSCALE_SECTION + 2.0f;
UIColor *theWhiteColor = [UIColor colorWithHue:0 saturation:0 brightness:1 alpha:1];
XCTAssertTrue([self isColor:theWhiteColor
equalToColor:[thePicker getColor:theY]], @"should start with white");
}

- (void)testColor
{
DKVerticalColorPicker* thePicker = [self createTestColorPicker];
CGFloat theY = 100;
UIColor *theColor = [UIColor colorWithHue:1 saturation: 0.8 brightness:1 alpha:1];
XCTAssertTrue([self isColor:theColor
equalToColor:[thePicker getColor:theY]], @"should end with color");
}

- (void)testGetYFromColor
{
DKVerticalColorPicker* thePicker = [self createTestColorPicker];

UIColor *theBlackColor = [UIColor colorWithHue:0 saturation:0 brightness:0 alpha:1];
XCTAssertEqual( 0, [ thePicker getYFromColor: theBlackColor], @"should start with black at zero");

UIColor *theWhiteColor = [UIColor colorWithHue:0 saturation:0 brightness:1 alpha:1];
XCTAssertEqual( END_OF_GRAYSCALE_SECTION, [ thePicker getYFromColor: theWhiteColor], @"should show white");

UIColor *theColor = [UIColor colorWithHue:1 saturation: 0.8 brightness:1 alpha:1];
XCTAssertEqual( 100, [ thePicker getYFromColor: theColor], @"should end with red");
}

- (DKVerticalColorPicker*)createTestColorPicker
{
int theHeight = 100;
return [[DKVerticalColorPicker alloc] initWithFrame:CGRectMake(0, 0, 50, theHeight)];
}


- (BOOL)isColor:(UIColor *)aColor equalToColor:(UIColor *)otherColor
{
return CGColorEqualToColor(aColor.CGColor, otherColor.CGColor);
}

@end