Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / image_button_cell.mm
1 // Copyright (c) 2011 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 "chrome/browser/ui/cocoa/image_button_cell.h"
6
7 #include "base/logging.h"
8 #import "chrome/browser/themes/theme_service.h"
9 #import "chrome/browser/ui/cocoa/rect_path_utils.h"
10 #import "chrome/browser/ui/cocoa/themed_window.h"
11 #import "ui/base/cocoa/nsview_additions.h"
12 #include "ui/gfx/image/image.h"
13 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
14
15 // When the window doesn't have focus then we want to draw the button with a
16 // slightly lighter color. We do this by just reducing the alpha.
17 const CGFloat kImageNoFocusAlpha = 0.65;
18
19 @interface ImageButtonCell (Private)
20 - (void)sharedInit;
21 - (image_button_cell::ButtonState)currentButtonState;
22 - (NSImage*)imageForID:(NSInteger)imageID
23            controlView:(NSView*)controlView;
24 @end
25
26 @implementation ImageButtonCell
27
28 @synthesize isMouseInside = isMouseInside_;
29
30 // For nib instantiations
31 - (id)initWithCoder:(NSCoder*)decoder {
32   if ((self = [super initWithCoder:decoder])) {
33     [self sharedInit];
34   }
35   return self;
36 }
37
38 // For programmatic instantiations
39 - (id)initTextCell:(NSString*)string {
40   if ((self = [super initTextCell:string])) {
41     [self sharedInit];
42   }
43   return self;
44 }
45
46 - (void)sharedInit {
47   [self setHighlightsBy:NSNoCellMask];
48
49   // We need to set this so that we can override |-mouseEntered:| and
50   // |-mouseExited:| to change the button image on hover states.
51   [self setShowsBorderOnlyWhileMouseInside:YES];
52 }
53
54 - (NSImage*)imageForState:(image_button_cell::ButtonState)state
55                      view:(NSView*)controlView{
56   if (image_[state].imageId)
57     return [self imageForID:image_[state].imageId controlView:controlView];
58   return image_[state].image;
59 }
60
61 - (void)drawImageWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
62   image_button_cell::ButtonState state = [self currentButtonState];
63   BOOL windowHasFocus = [[controlView window] isMainWindow] ||
64                         [[controlView window] isKeyWindow];
65   CGFloat alpha = [self imageAlphaForWindowState:[controlView window]];
66   NSImage* image = [self imageForState:state view:controlView];
67
68   if (!windowHasFocus) {
69     NSImage* defaultImage = [self
70       imageForState:image_button_cell::kDefaultStateBackground
71                view:controlView];
72     NSImage* hoverImage = [self
73       imageForState:image_button_cell::kHoverStateBackground
74                view:controlView];
75     if ([self currentButtonState] == image_button_cell::kDefaultState &&
76         defaultImage) {
77       image = defaultImage;
78       alpha = 1.0;
79     } else if ([self currentButtonState] == image_button_cell::kHoverState &&
80         hoverImage) {
81       image = hoverImage;
82       alpha = 1.0;
83     }
84   }
85
86   NSRect imageRect;
87   imageRect.size = [image size];
88   imageRect.origin.x = cellFrame.origin.x +
89     roundf((NSWidth(cellFrame) - NSWidth(imageRect)) / 2.0);
90   imageRect.origin.y = cellFrame.origin.y +
91     roundf((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0);
92
93   [image drawInRect:imageRect
94            fromRect:NSZeroRect
95           operation:NSCompositeSourceOver
96            fraction:alpha
97      respectFlipped:YES
98               hints:nil];
99 }
100
101 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
102   [self drawImageWithFrame:cellFrame inView:controlView];
103   // Only draw custom focus ring if the 10.7 focus ring APIs are not available.
104   // TODO(groby): Remove once we build against the 10.7 SDK.
105   if (![self respondsToSelector:@selector(drawFocusRingMaskWithFrame:inView:)])
106     [self drawFocusRingWithFrame:cellFrame inView:controlView];
107 }
108
109 - (void)setImageID:(NSInteger)imageID
110     forButtonState:(image_button_cell::ButtonState)state {
111   DCHECK_GE(state, 0);
112   DCHECK_LT(state, image_button_cell::kButtonStateCount);
113
114   image_[state].image.reset();
115   image_[state].imageId = imageID;
116   [[self controlView] setNeedsDisplay:YES];
117 }
118
119 // Sets the image for the given button state using an image.
120 - (void)setImage:(NSImage*)image
121   forButtonState:(image_button_cell::ButtonState)state {
122   DCHECK_GE(state, 0);
123   DCHECK_LT(state, image_button_cell::kButtonStateCount);
124
125   image_[state].image.reset([image retain]);
126   image_[state].imageId = 0;
127   [[self controlView] setNeedsDisplay:YES];
128 }
129
130 - (CGFloat)imageAlphaForWindowState:(NSWindow*)window {
131   BOOL windowHasFocus = [window isMainWindow] || [window isKeyWindow];
132   return windowHasFocus ? 1.0 : kImageNoFocusAlpha;
133 }
134
135 - (void)drawFocusRingWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
136   if (![self showsFirstResponder])
137     return;
138   gfx::ScopedNSGraphicsContextSaveGState scoped_state;
139   const CGFloat lineWidth = [controlView cr_lineWidth];
140   rect_path_utils::FrameRectWithInset(rect_path_utils::RoundedCornerAll,
141                                       NSInsetRect(cellFrame, 0, lineWidth),
142                                       0.0,            // insetX
143                                       0.0,            // insetY
144                                       3.0,            // outerRadius
145                                       lineWidth * 2,  // lineWidth
146                                       [controlView
147                                           cr_keyboardFocusIndicatorColor]);
148 }
149
150 - (image_button_cell::ButtonState)currentButtonState {
151   bool (^has)(image_button_cell::ButtonState) =
152       ^(image_button_cell::ButtonState state) {
153           return image_[state].image || image_[state].imageId;
154       };
155   if (![self isEnabled] && has(image_button_cell::kDisabledState))
156     return image_button_cell::kDisabledState;
157   if ([self isHighlighted] && has(image_button_cell::kPressedState))
158     return image_button_cell::kPressedState;
159   if ([self isMouseInside] && has(image_button_cell::kHoverState))
160     return image_button_cell::kHoverState;
161   return image_button_cell::kDefaultState;
162 }
163
164 - (NSImage*)imageForID:(NSInteger)imageID
165            controlView:(NSView*)controlView {
166   if (!imageID)
167     return nil;
168
169   ui::ThemeProvider* themeProvider = [[controlView window] themeProvider];
170   if (!themeProvider)
171     return nil;
172
173   return themeProvider->GetNSImageNamed(imageID);
174 }
175
176 - (void)setIsMouseInside:(BOOL)isMouseInside {
177   if (isMouseInside_ != isMouseInside) {
178     isMouseInside_ = isMouseInside;
179     NSView<ImageButton>* control =
180         static_cast<NSView<ImageButton>*>([self controlView]);
181     if ([control respondsToSelector:@selector(mouseInsideStateDidChange:)]) {
182       [control mouseInsideStateDidChange:isMouseInside];
183     }
184     [control setNeedsDisplay:YES];
185   }
186 }
187
188 - (void)setShowsBorderOnlyWhileMouseInside:(BOOL)show {
189   VLOG_IF(1, !show) << "setShowsBorderOnlyWhileMouseInside:NO ignored";
190 }
191
192 - (BOOL)showsBorderOnlyWhileMouseInside {
193   // Always returns YES so that buttons always get mouse tracking even when
194   // disabled. The reload button (and possibly others) depend on this.
195   return YES;
196 }
197
198 - (void)mouseEntered:(NSEvent*)theEvent {
199   [self setIsMouseInside:YES];
200 }
201
202 - (void)mouseExited:(NSEvent*)theEvent {
203   [self setIsMouseInside:NO];
204 }
205
206 @end