BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / image_button_cell.mm
blob222ba36c7a53b31f23d7c85af56691994d02d284
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.
5 #import "chrome/browser/ui/cocoa/image_button_cell.h"
7 #include "base/logging.h"
8 #include "base/mac/mac_util.h"
9 #import "chrome/browser/themes/theme_service.h"
10 #import "chrome/browser/ui/cocoa/rect_path_utils.h"
11 #import "chrome/browser/ui/cocoa/themed_window.h"
12 #import "ui/base/cocoa/nsview_additions.h"
13 #include "ui/gfx/image/image.h"
14 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
16 // When the window doesn't have focus then we want to draw the button with a
17 // slightly lighter color. We do this by just reducing the alpha.
18 const CGFloat kImageNoFocusAlpha = 0.65;
20 @interface ImageButtonCell (Private)
21 - (void)sharedInit;
22 - (image_button_cell::ButtonState)currentButtonState;
23 - (NSImage*)imageForID:(NSInteger)imageID
24            controlView:(NSView*)controlView;
25 @end
27 @implementation ImageButtonCell
29 @synthesize isMouseInside = isMouseInside_;
31 // For nib instantiations
32 - (id)initWithCoder:(NSCoder*)decoder {
33   if ((self = [super initWithCoder:decoder])) {
34     [self sharedInit];
35   }
36   return self;
39 // For programmatic instantiations
40 - (id)initTextCell:(NSString*)string {
41   if ((self = [super initTextCell:string])) {
42     [self sharedInit];
43   }
44   return self;
47 - (void)sharedInit {
48   [self setHighlightsBy:NSNoCellMask];
50   // We need to set this so that we can override |-mouseEntered:| and
51   // |-mouseExited:| to change the button image on hover states.
52   [self setShowsBorderOnlyWhileMouseInside:YES];
55 - (NSImage*)imageForState:(image_button_cell::ButtonState)state
56                      view:(NSView*)controlView{
57   if (image_[state].imageId)
58     return [self imageForID:image_[state].imageId controlView:controlView];
59   return image_[state].image;
62 - (void)drawImageWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
63   image_button_cell::ButtonState state = [self currentButtonState];
64   BOOL windowHasFocus = [[controlView window] isMainWindow] ||
65                         [[controlView window] isKeyWindow];
66   CGFloat alpha = [self imageAlphaForWindowState:[controlView window]];
67   NSImage* image = [self imageForState:state view:controlView];
69   if (!windowHasFocus) {
70     NSImage* defaultImage = [self
71       imageForState:image_button_cell::kDefaultStateBackground
72                view:controlView];
73     NSImage* hoverImage = [self
74       imageForState:image_button_cell::kHoverStateBackground
75                view:controlView];
76     if ([self currentButtonState] == image_button_cell::kDefaultState &&
77         defaultImage) {
78       image = defaultImage;
79       alpha = 1.0;
80     } else if ([self currentButtonState] == image_button_cell::kHoverState &&
81         hoverImage) {
82       image = hoverImage;
83       alpha = 1.0;
84     }
85   }
87   NSRect imageRect;
88   imageRect.size = [image size];
89   imageRect.origin.x = cellFrame.origin.x +
90     roundf((NSWidth(cellFrame) - NSWidth(imageRect)) / 2.0);
91   imageRect.origin.y = cellFrame.origin.y +
92     roundf((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0);
94   [image drawInRect:imageRect
95            fromRect:NSZeroRect
96           operation:NSCompositeSourceOver
97            fraction:alpha
98      respectFlipped:YES
99               hints:nil];
102 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
103   [self drawImageWithFrame:cellFrame inView:controlView];
104   [self drawFocusRingWithFrame:cellFrame inView:controlView];
107 - (void)setImageID:(NSInteger)imageID
108     forButtonState:(image_button_cell::ButtonState)state {
109   DCHECK_GE(state, 0);
110   DCHECK_LT(state, image_button_cell::kButtonStateCount);
112   image_[state].image.reset();
113   image_[state].imageId = imageID;
114   [[self controlView] setNeedsDisplay:YES];
117 // Sets the image for the given button state using an image.
118 - (void)setImage:(NSImage*)image
119   forButtonState:(image_button_cell::ButtonState)state {
120   DCHECK_GE(state, 0);
121   DCHECK_LT(state, image_button_cell::kButtonStateCount);
123   image_[state].image.reset([image retain]);
124   image_[state].imageId = 0;
125   [[self controlView] setNeedsDisplay:YES];
128 - (CGFloat)imageAlphaForWindowState:(NSWindow*)window {
129   BOOL windowHasFocus = [window isMainWindow] || [window isKeyWindow];
130   return windowHasFocus ? 1.0 : kImageNoFocusAlpha;
133 - (ui::ThemeProvider*)themeProviderForWindow:(NSWindow*)window {
134   return [window themeProvider];
137 - (void)drawFocusRingWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
138   // Draw custom focus ring only if AppKit won't draw one automatically.
139   // The new focus ring APIs became available with 10.7, but did not get
140   // applied to buttons (only editable text fields) until 10.8.
141   if (base::mac::IsOSMountainLionOrLater())
142     return;
144   if (![self showsFirstResponder])
145     return;
146   gfx::ScopedNSGraphicsContextSaveGState scoped_state;
147   const CGFloat lineWidth = [controlView cr_lineWidth];
148   rect_path_utils::FrameRectWithInset(rect_path_utils::RoundedCornerAll,
149                                       NSInsetRect(cellFrame, 0, lineWidth),
150                                       0.0,            // insetX
151                                       0.0,            // insetY
152                                       3.0,            // outerRadius
153                                       lineWidth * 2,  // lineWidth
154                                       [controlView
155                                           cr_keyboardFocusIndicatorColor]);
158 - (image_button_cell::ButtonState)currentButtonState {
159   bool (^has)(image_button_cell::ButtonState) =
160       ^(image_button_cell::ButtonState state) {
161           return image_[state].image || image_[state].imageId;
162       };
163   if (![self isEnabled] && has(image_button_cell::kDisabledState))
164     return image_button_cell::kDisabledState;
165   if ([self isHighlighted] && has(image_button_cell::kPressedState))
166     return image_button_cell::kPressedState;
167   if ([self isMouseInside] && has(image_button_cell::kHoverState))
168     return image_button_cell::kHoverState;
169   return image_button_cell::kDefaultState;
172 - (NSImage*)imageForID:(NSInteger)imageID
173            controlView:(NSView*)controlView {
174   if (!imageID)
175     return nil;
177   ui::ThemeProvider* themeProvider =
178       [self themeProviderForWindow:[controlView window]];
179   if (!themeProvider)
180     return nil;
182   return themeProvider->GetNSImageNamed(imageID);
185 - (void)setIsMouseInside:(BOOL)isMouseInside {
186   if (isMouseInside_ != isMouseInside) {
187     isMouseInside_ = isMouseInside;
188     NSView<ImageButton>* control =
189         static_cast<NSView<ImageButton>*>([self controlView]);
190     if ([control respondsToSelector:@selector(mouseInsideStateDidChange:)]) {
191       [control mouseInsideStateDidChange:isMouseInside];
192     }
193     [control setNeedsDisplay:YES];
194   }
197 - (void)setShowsBorderOnlyWhileMouseInside:(BOOL)show {
198   VLOG_IF(1, !show) << "setShowsBorderOnlyWhileMouseInside:NO ignored";
201 - (BOOL)showsBorderOnlyWhileMouseInside {
202   // Always returns YES so that buttons always get mouse tracking even when
203   // disabled. The reload button (and possibly others) depend on this.
204   return YES;
207 - (void)mouseEntered:(NSEvent*)theEvent {
208   [self setIsMouseInside:YES];
211 - (void)mouseExited:(NSEvent*)theEvent {
212   [self setIsMouseInside:NO];
215 @end