BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / autofill / autofill_tooltip_controller.mm
blobb2a66dc7c08efb0167739d9677dc27b49a38f850
1 // Copyright 2013 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/autofill/autofill_tooltip_controller.h"
7 #include "base/mac/foundation_util.h"
8 #import "chrome/browser/ui/cocoa/autofill/autofill_bubble_controller.h"
9 #import "ui/base/cocoa/base_view.h"
10 #import "ui/base/cocoa/hover_image_button.h"
12 // Delay time before tooltip shows/hides.
13 const NSTimeInterval kTooltipDelay = 0.1;
15 // How far to inset tooltip contents.
16 CGFloat kTooltipInset = 10;
18 #pragma mark AutofillTooltipController - private methods
20 @interface AutofillTooltipController ()
22 // Sets hover state for "mouse over InfoBubble".
23 - (void)setHoveringOnBubble:(BOOL)hoveringOnBubble;
25 // Update the combined hover state - if either button or bubble is hovered,
26 // the combined state is considered "hovered". Notifies delegate if the state
27 // changed.
28 - (void)updateTooltipDisplayState;
30 @end
32 #pragma mark AutofillTooltip
34 // The actual tooltip control - based on HoverButton, which comes with free
35 // hover handling.
36 @interface AutofillTooltip : HoverButton {
37  @private
38   // Not owned - |tooltipController_| owns this object.
39   AutofillTooltipController* tooltipController_;
42 @property(assign, nonatomic) AutofillTooltipController* tooltipController;
44 @end
47 @implementation AutofillTooltip
49 @synthesize tooltipController = tooltipController_;
51 - (void)drawRect:(NSRect)rect {
52  [[self image] drawInRect:rect
53                  fromRect:NSZeroRect
54                 operation:NSCompositeSourceOver
55                  fraction:1.0
56            respectFlipped:YES
57                     hints:nil];
60 - (void)setHoverState:(HoverState)state {
61   [super setHoverState:state];
62   [tooltipController_ updateTooltipDisplayState];
65 - (BOOL)acceptsFirstResponder {
66   return NO;
69 @end
71 #pragma mark AutofillTrackingView
73 // A very basic view that only tracks mouseEntered:/mouseExited: and forwards
74 // them to |tooltipController_|.
75 @interface AutofillTrackingView : BaseView {
76  @private
77   // Not owned - tooltip controller owns tracking view and tooltip.
78   AutofillTooltipController* tooltipController_;
81 @property(assign, nonatomic) AutofillTooltipController* tooltipController;
83 @end
85 @implementation AutofillTrackingView
87 @synthesize tooltipController = tooltipController_;
89 - (void)mouseEntered:(NSEvent*)theEvent {
90   [tooltipController_ setHoveringOnBubble:YES];
93 - (void)mouseExited:(NSEvent*)theEvent {
94   [tooltipController_ setHoveringOnBubble:NO];
97 @end
99 #pragma mark AutofillTooltipController
101 @implementation AutofillTooltipController
103 @synthesize message = message_;
105 - (id)initWithArrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation {
106   if ((self = [super init])) {
107     arrowLocation_ = arrowLocation;
108     view_.reset([[AutofillTooltip alloc] init]);
109     [self setView:view_];
110     [view_ setTooltipController:self];
111   }
112   return self;
115 - (void)dealloc {
116   [view_ setTooltipController:nil];
117   [NSObject cancelPreviousPerformRequestsWithTarget:self];
118   [[NSNotificationCenter defaultCenter]
119       removeObserver:self
120                 name:NSWindowWillCloseNotification
121               object:[bubbleController_ window]];
122   [super dealloc];
125 - (void)setImage:(NSImage*)image {
126   [view_ setImage:image];
127   [view_ setFrameSize:[image size]];
130 - (void)tooltipWindowWillClose:(NSNotification*)notification {
131   bubbleController_ = nil;
134 - (void)displayHover {
135   [bubbleController_ close];
136   bubbleController_ =
137     [[AutofillBubbleController alloc]
138         initWithParentWindow:[[self view] window]
139                      message:[self message]
140                        inset:NSMakeSize(kTooltipInset, kTooltipInset)
141                arrowLocation:arrowLocation_];
142   [bubbleController_ setShouldCloseOnResignKey:NO];
144   // Handle bubble self-deleting.
145   NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
146   [center addObserver:self
147              selector:@selector(tooltipWindowWillClose:)
148                  name:NSWindowWillCloseNotification
149                object:[bubbleController_ window]];
151   // Inject a tracking view so controller can track hover events for the bubble.
152   base::scoped_nsobject<NSView> oldContentView(
153       [[[bubbleController_ window] contentView] retain]);
154   base::scoped_nsobject<AutofillTrackingView> trackingView(
155       [[AutofillTrackingView alloc] initWithFrame:[oldContentView frame]]);
156   [trackingView setTooltipController:self];
157   [trackingView setAutoresizesSubviews:YES];
158   [oldContentView setFrame:[trackingView bounds]];
159   [oldContentView
160       setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
161   [[bubbleController_ window] setContentView:trackingView];
162   [trackingView setSubviews:@[ oldContentView ]];
164   // Compute anchor point (in window coords - views might be flipped).
165   NSRect viewRect = [view_ convertRect:[view_ bounds] toView:nil];
166   NSPoint anchorPoint = NSMakePoint(NSMidX(viewRect), NSMinY(viewRect));
167   [bubbleController_ setAnchorPoint:
168       [[[self view] window] convertBaseToScreen:anchorPoint]];
169   [bubbleController_ showWindow:self];
172 - (void)hideHover {
173   [bubbleController_ close];
176 - (void)setHoveringOnBubble:(BOOL)hoveringOnBubble {
177   isHoveringOnBubble_ = hoveringOnBubble;
178   [self updateTooltipDisplayState];
181 - (void)updateTooltipDisplayState {
182   BOOL newDisplayState =
183       ([view_ hoverState] != kHoverStateNone || isHoveringOnBubble_);
185   if (newDisplayState != shouldDisplayTooltip_) {
186     shouldDisplayTooltip_ = newDisplayState;
188     // Cancel any pending visibility changes.
189     [NSObject cancelPreviousPerformRequestsWithTarget:self];
191     // If the desired visibility disagrees with current visibility, start a
192     // timer to change visibility. (Uses '!!' to force bool values)
193     if (!!bubbleController_ ^ !!shouldDisplayTooltip_) {
194       SEL sel = shouldDisplayTooltip_ ? @selector(displayHover)
195                                       : @selector(hideHover);
196       [self performSelector:sel withObject:nil afterDelay:kTooltipDelay];
197     }
198   }
201 @end