Skip to content

Commit

Permalink
ColorPicker: Make it possible to select 'no color'
Browse files Browse the repository at this point in the history
  • Loading branch information
gnachman committed Nov 17, 2015
1 parent 3deb85a commit 4164bab
Show file tree
Hide file tree
Showing 23 changed files with 309 additions and 91 deletions.
Binary file modified ColorPicker/ColorPicker.framework/Versions/A/ColorPicker
Binary file not shown.
Expand Up @@ -10,6 +10,7 @@

@property(nonatomic, retain) NSColor *color;
@property(nonatomic, assign) BOOL alphaAllowed;
@property(nonatomic, assign) BOOL noColorAllowed;

// Called just before popover opens.
@property(nonatomic, copy) void (^willOpenPopover)();
Expand Down
@@ -1,5 +1,10 @@
#import <Cocoa/Cocoa.h>

typedef NS_OPTIONS(NSInteger, CPKMainViewControllerOptions) {
CPKMainViewControllerOptionsAlpha = (1 << 0), // Show opacity control
CPKMainViewControllerOptionsNoColor = (1 << 1), // Allow selection of "no color"
};

/**
* The view controller for the color picker. This can go inside a popover, or something else if
* you like.
Expand All @@ -23,7 +28,13 @@
*/
- (instancetype)initWithBlock:(void (^)(NSColor *))block
color:(NSColor *)color
alphaAllowed:(BOOL)alphaAllowed;
alphaAllowed:(BOOL)alphaAllowed DEPRECATED_ATTRIBUTE;

- (instancetype)initWithBlock:(void (^)(NSColor *))block
useSystemColorPicker:(void (^)())useSystemColorPickerBlock
color:(NSColor *)color
options:(CPKMainViewControllerOptions)options;


// Changes the selected color.
- (void)selectColor:(NSColor *)color;
Expand Down
@@ -1,4 +1,5 @@
#import <Cocoa/Cocoa.h>
#import "CPKMainViewController.h"

/**
* A popover that houses a color picker.
Expand Down Expand Up @@ -30,6 +31,14 @@
preferredEdge:(NSRectEdge)preferredEdge
initialColor:(NSColor *)color
alphaAllowed:(BOOL)alphaAllowed
selectionDidChange:(void (^)(NSColor *))block;
selectionDidChange:(void (^)(NSColor *))block DEPRECATED_ATTRIBUTE;

+ (instancetype)presentRelativeToRect:(NSRect)positioningRect
ofView:(NSView *)positioningView
preferredEdge:(NSRectEdge)preferredEdge
initialColor:(NSColor *)color
options:(CPKMainViewControllerOptions)options
selectionDidChange:(void (^)(NSColor *))block
useSystemColorPicker:(void (^)())useSystemColorPicker;

@end
Binary file not shown.
16 changes: 16 additions & 0 deletions ColorPicker/ColorPicker.xcodeproj/project.pbxproj
Expand Up @@ -78,6 +78,8 @@
A6184F861BAA93F50088EF3C /* ActiveEyedropper.png in Resources */ = {isa = PBXBuildFile; fileRef = A6184F841BAA93F50088EF3C /* ActiveEyedropper.png */; };
A6184F871BAA93F50088EF3C /* ActiveEyedropper@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A6184F851BAA93F50088EF3C /* ActiveEyedropper@2x.png */; };
A628B0061BF5ACE800B68248 /* ColorPicker.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = A6184EA81BA874020088EF3C /* ColorPicker.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
A628B0101BF9A0D600B68248 /* NoColor.png in Resources */ = {isa = PBXBuildFile; fileRef = A628B00E1BF9A0D600B68248 /* NoColor.png */; };
A628B0111BF9A0D600B68248 /* NoColor@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A628B00F1BF9A0D600B68248 /* NoColor@2x.png */; };
A662E7901BD4932A00B79B8B /* HSB.png in Resources */ = {isa = PBXBuildFile; fileRef = A662E78E1BD4932A00B79B8B /* HSB.png */; };
A662E7911BD4932A00B79B8B /* HSB@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A662E78F1BD4932A00B79B8B /* HSB@2x.png */; };
A662E7941BD4933A00B79B8B /* RGB.png in Resources */ = {isa = PBXBuildFile; fileRef = A662E7921BD4933A00B79B8B /* RGB.png */; };
Expand Down Expand Up @@ -188,6 +190,8 @@
A6184F801BAA928A0088EF3C /* Eyedropper@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Eyedropper@2x.png"; sourceTree = "<group>"; };
A6184F841BAA93F50088EF3C /* ActiveEyedropper.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ActiveEyedropper.png; sourceTree = "<group>"; };
A6184F851BAA93F50088EF3C /* ActiveEyedropper@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ActiveEyedropper@2x.png"; sourceTree = "<group>"; };
A628B00E1BF9A0D600B68248 /* NoColor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = NoColor.png; path = Images.xcassets/NoColor/NoColor.png; sourceTree = "<group>"; };
A628B00F1BF9A0D600B68248 /* NoColor@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "NoColor@2x.png"; path = "Images.xcassets/NoColor/NoColor@2x.png"; sourceTree = "<group>"; };
A662E78E1BD4932A00B79B8B /* HSB.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = HSB.png; path = Images.xcassets/HSB/HSB.png; sourceTree = "<group>"; };
A662E78F1BD4932A00B79B8B /* HSB@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "HSB@2x.png"; path = "Images.xcassets/HSB/HSB@2x.png"; sourceTree = "<group>"; };
A662E7921BD4933A00B79B8B /* RGB.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = RGB.png; path = Images.xcassets/RGB/RGB.png; sourceTree = "<group>"; };
Expand Down Expand Up @@ -361,6 +365,7 @@
A6184F2D1BA9D55D0088EF3C /* Resources */ = {
isa = PBXGroup;
children = (
A628B00D1BF9A0CC00B68248 /* NoColor */,
A662E78B1BD492F600B79B8B /* HSB */,
A662E78A1BD492F200B79B8B /* RGB */,
1D3368881BCDB61200D3B564 /* ActiveEscapeHatch */,
Expand Down Expand Up @@ -447,6 +452,15 @@
path = Images.xcassets/ActiveEyedropper;
sourceTree = "<group>";
};
A628B00D1BF9A0CC00B68248 /* NoColor */ = {
isa = PBXGroup;
children = (
A628B00E1BF9A0D600B68248 /* NoColor.png */,
A628B00F1BF9A0D600B68248 /* NoColor@2x.png */,
);
name = NoColor;
sourceTree = "<group>";
};
A662E78A1BD492F200B79B8B /* RGB */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -601,6 +615,7 @@
files = (
A6184F751BAA2AC60088EF3C /* Remove.png in Resources */,
A6184F421BA9D5700088EF3C /* SelectedColorIndicator@2x.png in Resources */,
A628B0101BF9A0D600B68248 /* NoColor.png in Resources */,
A6184F821BAA928A0088EF3C /* Eyedropper@2x.png in Resources */,
A6184F3E1BA9D5700088EF3C /* Add@2x.png in Resources */,
1D3368871BCDB60700D3B564 /* EscapeHatch@2x.png in Resources */,
Expand All @@ -613,6 +628,7 @@
A6184F6E1BAA15B80088EF3C /* SelectionIndicator@2x.png in Resources */,
A6184F871BAA93F50088EF3C /* ActiveEyedropper@2x.png in Resources */,
A6184F5D1BAA083F0088EF3C /* SwatchCheckerboard@2x.png in Resources */,
A628B0111BF9A0D600B68248 /* NoColor@2x.png in Resources */,
A662E7901BD4932A00B79B8B /* HSB.png in Resources */,
1D33688B1BCDB62100D3B564 /* ActiveEscapeHatch.png in Resources */,
A6184F5C1BAA083F0088EF3C /* SwatchCheckerboard.png in Resources */,
Expand Down
1 change: 1 addition & 0 deletions ColorPicker/ColorPicker/CPKColorWell.h
Expand Up @@ -10,6 +10,7 @@

@property(nonatomic, retain) NSColor *color;
@property(nonatomic, assign) BOOL alphaAllowed;
@property(nonatomic, assign) BOOL noColorAllowed;

// Called just before popover opens.
@property(nonatomic, copy) void (^willOpenPopover)();
Expand Down
123 changes: 87 additions & 36 deletions ColorPicker/ColorPicker/CPKColorWell.m
Expand Up @@ -22,6 +22,9 @@ @interface CPKColorWellView : CPKSwatchView
/** User can adjust alpha value. */
@property(nonatomic, assign) BOOL alphaAllowed;

/** Use can choose to have no color. */
@property(nonatomic, assign) BOOL noColorAllowed;

/** Color well is disabled? */
@property(nonatomic, assign) BOOL disabled;

Expand All @@ -44,7 +47,9 @@ @interface CPKColorWellView() <NSDraggingDestination, NSDraggingSource, NSPopove
@interface CPKColorWell() <CPKColorWellViewDelegate>
@end

@implementation CPKColorWellView
@implementation CPKColorWellView {
NSPoint _mouseDownLocation;
}

- (instancetype)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
Expand Down Expand Up @@ -73,6 +78,7 @@ - (void)awakeFromNib {

// Use mouseDown so this will work in a NSTableView.
- (void)mouseDown:(NSEvent *)theEvent {
_mouseDownLocation = [self convertPoint:theEvent.locationInWindow fromView:nil];
if (!self.delegate.isContinuous && theEvent.clickCount == 1) {
[self openPopOver];
}
Expand All @@ -92,6 +98,13 @@ - (void)openPopOver {
}

- (void)mouseDragged:(NSEvent *)theEvent {
NSPoint location = [self convertPoint:theEvent.locationInWindow fromView:nil];
CGFloat distance = sqrt(pow(_mouseDownLocation.x - location.x, 2) +
pow(_mouseDownLocation.y - location.y, 2));
const CGFloat kDragThreshold = 5; // Minimum drag distance before initiating a drag.
if (distance < kDragThreshold) {
return;
}
NSColor *color = self.selectedColor ?: [NSColor clearColor];
NSDraggingItem *dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:color];

Expand Down Expand Up @@ -163,6 +176,10 @@ - (void)colorPanelColorDidChange:(id)sender {
[self.delegate colorChangedByDrag:[sender color]];
}

- (void)noColorChosenInSystemColorPicker:(id)sender {
[self colorPanelColorDidChange:nil];
}

- (void)useColorPicker:(id)sender {
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:kCPKUseSystemColorPicker];
[[NSColorPanel sharedColorPanel] close];
Expand All @@ -173,9 +190,13 @@ - (void)useColorPicker:(id)sender {
}

- (void)showSystemColorPicker {
static const CGFloat kMarginBetweenAccessoryViews = 4;

NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel];

// Add an accessory view to use ColorPicker.
NSView *container = [[NSView alloc] init];

NSImage *image = [self cpk_imageNamed:@"ActiveEscapeHatch"];
NSRect frame;
frame.origin = NSZeroPoint;
Expand All @@ -186,13 +207,31 @@ - (void)showSystemColorPicker {
button.imagePosition = NSImageOnly;
[button setTarget:self];
[button setAction:@selector(useColorPicker:)];
colorPanel.accessoryView = button;

[container addSubview:button];

if (self.noColorAllowed) {
frame.origin.x = NSMaxX(frame) + kMarginBetweenAccessoryViews;
button = [[NSButton alloc] initWithFrame:frame];
image = [self cpk_imageNamed:@"NoColor"];
button.bordered = NO;
button.image = image;
button.imagePosition = NSImageOnly;
[button setTarget:self];
[button setAction:@selector(noColorChosenInSystemColorPicker:)];
[container addSubview:button];
}

container.frame = NSMakeRect(0, 0, NSMaxX(button.frame), NSMaxY(button.frame));
colorPanel.accessoryView = container;

[colorPanel setTarget:self];
[colorPanel setAction:@selector(colorPanelColorDidChange:)];
[colorPanel orderFront:nil];
colorPanel.showsAlpha = self.alphaAllowed;
colorPanel.color = self.selectedColor;
if (self.selectedColor) {
colorPanel.color = self.selectedColor;
}
}

- (void)openPopOverRelativeToRect:(NSRect)presentationRect ofView:(NSView *)presentingView {
Expand All @@ -204,18 +243,20 @@ - (void)openPopOverRelativeToRect:(NSRect)presentationRect ofView:(NSView *)pres
}
__weak __typeof(self) weakSelf = self;
self.selectedColor = self.color;
CPKMainViewControllerOptions options = 0;
if (self.alphaAllowed) {
options |= CPKMainViewControllerOptionsAlpha;
}
if (self.noColorAllowed) {
options |= CPKMainViewControllerOptionsNoColor;
}
self.popover =
[CPKPopover presentRelativeToRect:presentationRect
ofView:presentingView
preferredEdge:NSRectEdgeMinY
initialColor:self.color
alphaAllowed:self.alphaAllowed
options:options
selectionDidChange:^(NSColor *color) {
if (!color) {
[weakSelf.popover close];
[self showSystemColorPicker];
return;
}
weakSelf.selectedColor = color;
if (weakSelf.delegate.isContinuous) {
weakSelf.color = color;
Expand All @@ -224,7 +265,11 @@ - (void)openPopOverRelativeToRect:(NSRect)presentationRect ofView:(NSView *)pres
}
}
[weakSelf setNeedsDisplay:YES];
}];
}
useSystemColorPicker:^() {
[weakSelf.popover close];
[self showSystemColorPicker];
}];
self.open = YES;
self.popover.willClose = ^() {
if (weakSelf.willClosePopover) {
Expand Down Expand Up @@ -285,31 +330,32 @@ - (void)awakeFromNib {
}

- (void)load {
if (_view) {
return;
}

// This makes target/action work on older OS versions.
[self setCell:[[NSActionCell alloc] init]];
_continuous = YES;
_view = [[CPKColorWellView alloc] initWithFrame:self.bounds];
_view.delegate = self;
[self addSubview:_view];
_view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
self.autoresizesSubviews = YES;
_view.alphaAllowed = _alphaAllowed;
__weak __typeof(self) weakSelf = self;
_view.colorDidChange = ^(NSColor *color) {
[weakSelf sendAction:weakSelf.action to:weakSelf.target];
};
_view.willClosePopover = ^(NSColor *color) {
if (!weakSelf.continuous) {
[weakSelf sendAction:weakSelf.action to:weakSelf.target];
}
if (weakSelf.willClosePopover) {
weakSelf.willClosePopover();
if (_view) {
return;
}
};

// This makes target/action work on older OS versions.
[self setCell:[[NSActionCell alloc] init]];
_continuous = YES;
_view = [[CPKColorWellView alloc] initWithFrame:self.bounds];
_view.delegate = self;
[self addSubview:_view];
_view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
self.autoresizesSubviews = YES;
_view.alphaAllowed = _alphaAllowed;
_view.noColorAllowed = _noColorAllowed;
__weak __typeof(self) weakSelf = self;
_view.colorDidChange = ^(NSColor *color) {
[weakSelf sendAction:weakSelf.action to:weakSelf.target];
};
_view.willClosePopover = ^(NSColor *color) {
if (!weakSelf.continuous) {
[weakSelf sendAction:weakSelf.action to:weakSelf.target];
}
if (weakSelf.willClosePopover) {
weakSelf.willClosePopover();
}
};
}

- (NSColor *)color {
Expand All @@ -322,8 +368,13 @@ - (void)setColor:(NSColor *)color {
}

- (void)setAlphaAllowed:(BOOL)alphaAllowed {
_alphaAllowed = alphaAllowed;
_view.alphaAllowed = alphaAllowed;
_alphaAllowed = alphaAllowed;
_view.alphaAllowed = alphaAllowed;
}

- (void)setNoColorAllowed:(BOOL)noColorAllowed {
_noColorAllowed = noColorAllowed;
_view.noColorAllowed = noColorAllowed;
}

- (void)setEnabled:(BOOL)enabled {
Expand Down
15 changes: 15 additions & 0 deletions ColorPicker/ColorPicker/CPKControlsView.h
Expand Up @@ -11,6 +11,9 @@ extern NSString *const kCPKUseSystemColorPicker;
/** Should the "Remove Favorite" button be enabled? */
@property(nonatomic) BOOL removeEnabled;

/** Block called when you clicks on "No Color". */
@property(nonatomic, copy) void (^selectNoColorBlock)();

/** Block called when user clicks on "Add Favorite". */
@property(nonatomic, copy) void (^addFavoriteBlock)();

Expand All @@ -32,6 +35,18 @@ extern NSString *const kCPKUseSystemColorPicker;
/** Reports this view's nominal height */
+ (CGFloat)desiredHeight;

/**
* Designated initializer.
*
* @param frameRect Initial frame
* @param noColorAllowed If set, a control to set "no color" will be added.
*
* @return Initialized instance.
*/
- (instancetype)initWithFrame:(NSRect)frameRect noColorAllowed:(BOOL)noColorAllowed NS_DESIGNATED_INITIALIZER;

- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;

/** Updates the swatch color. */
- (void)setSwatchColor:(NSColor *)color;

Expand Down

0 comments on commit 4164bab

Please sign in to comment.