1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#import <Cocoa/Cocoa.h>
6
7#include "base/logging.h"
8#import "base/mac/scoped_nsobject.h"
9#include "chrome/browser/ui/browser_dialogs.h"
10#include "content/public/browser/color_chooser.h"
11#include "content/public/browser/web_contents.h"
12#include "skia/ext/skia_utils_mac.h"
13
14class ColorChooserMac;
15
16// A Listener class to act as a event target for NSColorPanel and send
17// the results to the C++ class, ColorChooserMac.
18@interface ColorPanelCocoa : NSObject<NSWindowDelegate> {
19 @private
20  // We don't call DidChooseColor if the change wasn't caused by the user
21  // interacting with the panel.
22  BOOL nonUserChange_;
23  ColorChooserMac* chooser_;  // weak, owns this
24}
25
26- (id)initWithChooser:(ColorChooserMac*)chooser;
27
28// Called from NSColorPanel.
29- (void)didChooseColor:(NSColorPanel*)panel;
30
31// Sets color to the NSColorPanel as a non user change.
32- (void)setColor:(NSColor*)color;
33
34@end
35
36class ColorChooserMac : public content::ColorChooser {
37 public:
38  static ColorChooserMac* Open(content::WebContents* web_contents,
39                               SkColor initial_color);
40
41  ColorChooserMac(content::WebContents* tab, SkColor initial_color);
42  virtual ~ColorChooserMac();
43
44  // Called from ColorPanelCocoa.
45  void DidChooseColorInColorPanel(SkColor color);
46  void DidCloseColorPabel();
47
48  virtual void End() OVERRIDE;
49  virtual void SetSelectedColor(SkColor color) OVERRIDE;
50
51 private:
52  static ColorChooserMac* current_color_chooser_;
53
54  // The web contents invoking the color chooser.  No ownership because it will
55  // outlive this class.
56  content::WebContents* web_contents_;
57  base::scoped_nsobject<ColorPanelCocoa> panel_;
58};
59
60ColorChooserMac* ColorChooserMac::current_color_chooser_ = NULL;
61
62// static
63ColorChooserMac* ColorChooserMac::Open(content::WebContents* web_contents,
64                                       SkColor initial_color) {
65  if (current_color_chooser_)
66    current_color_chooser_->End();
67  DCHECK(!current_color_chooser_);
68  current_color_chooser_ =
69      new ColorChooserMac(web_contents, initial_color);
70  return current_color_chooser_;
71}
72
73ColorChooserMac::ColorChooserMac(content::WebContents* web_contents,
74                                 SkColor initial_color)
75    : web_contents_(web_contents) {
76  panel_.reset([[ColorPanelCocoa alloc] initWithChooser:this]);
77  [panel_ setColor:gfx::SkColorToDeviceNSColor(initial_color)];
78  [[NSColorPanel sharedColorPanel] makeKeyAndOrderFront:nil];
79}
80
81ColorChooserMac::~ColorChooserMac() {
82  // Always call End() before destroying.
83  DCHECK(!panel_);
84}
85
86void ColorChooserMac::DidChooseColorInColorPanel(SkColor color) {
87  if (web_contents_)
88    web_contents_->DidChooseColorInColorChooser(color);
89}
90
91void ColorChooserMac::DidCloseColorPabel() {
92  End();
93}
94
95void ColorChooserMac::End() {
96  panel_.reset();
97  DCHECK(current_color_chooser_ == this);
98  current_color_chooser_ = NULL;
99  if (web_contents_)
100      web_contents_->DidEndColorChooser();
101}
102
103void ColorChooserMac::SetSelectedColor(SkColor color) {
104  [panel_ setColor:gfx::SkColorToDeviceNSColor(color)];
105}
106
107@implementation ColorPanelCocoa
108
109- (id)initWithChooser:(ColorChooserMac*)chooser {
110  if ((self = [super init])) {
111    chooser_ = chooser;
112    NSColorPanel* panel = [NSColorPanel sharedColorPanel];
113    [panel setShowsAlpha:NO];
114    [panel setDelegate:self];
115    [panel setTarget:self];
116    [panel setAction:@selector(didChooseColor:)];
117  }
118  return self;
119}
120
121- (void)dealloc {
122  NSColorPanel* panel = [NSColorPanel sharedColorPanel];
123  if ([panel delegate] == self) {
124    [panel setDelegate:nil];
125    [panel setTarget:nil];
126    [panel setAction:nil];
127  }
128
129  [super dealloc];
130}
131
132- (void)windowWillClose:(NSNotification*)notification {
133  chooser_->DidCloseColorPabel();
134  nonUserChange_ = NO;
135}
136
137- (void)didChooseColor:(NSColorPanel*)panel {
138  if (nonUserChange_) {
139    nonUserChange_ = NO;
140    return;
141  }
142  chooser_->DidChooseColorInColorPanel(gfx::NSDeviceColorToSkColor(
143      [[panel color] colorUsingColorSpaceName:NSDeviceRGBColorSpace]));
144  nonUserChange_ = NO;
145}
146
147- (void)setColor:(NSColor*)color {
148  nonUserChange_ = YES;
149  [[NSColorPanel sharedColorPanel] setColor:color];
150}
151
152namespace chrome {
153
154content::ColorChooser* ShowColorChooser(content::WebContents* web_contents,
155                                        SkColor initial_color) {
156  return ColorChooserMac::Open(web_contents, initial_color);
157}
158
159}  // namepace chrome
160
161@end
162