summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/autocomplete_text_field_cell.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/cocoa/autocomplete_text_field_cell.mm')
-rw-r--r--chrome/browser/cocoa/autocomplete_text_field_cell.mm563
1 files changed, 403 insertions, 160 deletions
diff --git a/chrome/browser/cocoa/autocomplete_text_field_cell.mm b/chrome/browser/cocoa/autocomplete_text_field_cell.mm
index 7b7f35c..9801892 100644
--- a/chrome/browser/cocoa/autocomplete_text_field_cell.mm
+++ b/chrome/browser/cocoa/autocomplete_text_field_cell.mm
@@ -7,6 +7,20 @@
#include "app/resource_bundle.h"
#include "base/logging.h"
#include "gfx/font.h"
+#include "grit/theme_resources.h"
+
+@interface AutocompleteTextAttachmentCell : NSTextAttachmentCell {
+}
+
+// TODO(shess):
+// Override -cellBaselineOffset to allow the image to be shifted up or
+// down relative to the containing text's baseline.
+
+// Draw the image using |DrawImageInRect()| helper function for
+// |-setFlipped:| consistency with other image drawing.
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView;
+
+@end
namespace {
@@ -35,16 +49,28 @@ const NSInteger kKeywordYInset = 4;
// technique would be nice to have, though.
const NSInteger kKeywordHintImageBaseline = -6;
+// Drops the magnifying glass icon so that it looks centered in the
+// keyword-search bubble.
+const NSInteger kKeywordSearchImageBaseline = -5;
+
// The amount of padding on either side reserved for drawing an icon.
const NSInteger kIconHorizontalPad = 3;
// How far to shift bounding box of hint icon label down from top of field.
-const NSInteger kIconLabelYOffset = 5;
+const NSInteger kIconLabelYOffset = 7;
// How far the editor insets itself, for purposes of determining if
// decorations need to be trimmed.
const CGFloat kEditorHorizontalInset = 3.0;
+// Cause the location icon to line up above the icons in the popup.
+const CGFloat kLocationIconXOffset = 6.0;
+const CGFloat kLocationIconXPad = 1.0;
+
+// How long to wait for mouse-up on the location icon before assuming
+// that the user wants to drag.
+const NSTimeInterval kLocationIconDragTimeout = 0.25;
+
// Conveniences to centralize width+offset calculations.
CGFloat WidthForHint(NSAttributedString* hintString) {
return kHintXOffset + ceil([hintString size].width);
@@ -54,20 +80,103 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) {
2 * kKeywordTokenInset;
}
+// Convenience to draw |image| in the |rect| portion of |view|.
+void DrawImageInRect(NSImage* image, NSView* view, const NSRect& rect) {
+ // If there is an image, make sure we calculated the target size
+ // correctly.
+ DCHECK(!image || NSEqualSizes([image size], rect.size));
+ [image setFlipped:[view isFlipped]];
+ [image drawInRect:rect
+ fromRect:NSZeroRect // Entire image
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+}
+
+// Helper function to generate an attributed string containing
+// |anImage|. If |baselineAdjustment| is 0, the image sits on the
+// text baseline, positive values shift it up, negative values shift
+// it down.
+NSAttributedString* AttributedStringForImage(NSImage* anImage,
+ CGFloat baselineAdjustment) {
+ scoped_nsobject<AutocompleteTextAttachmentCell> attachmentCell(
+ [[AutocompleteTextAttachmentCell alloc] initImageCell:anImage]);
+ scoped_nsobject<NSTextAttachment> attachment(
+ [[NSTextAttachment alloc] init]);
+ [attachment setAttachmentCell:attachmentCell];
+
+ scoped_nsobject<NSMutableAttributedString> as(
+ [[NSAttributedString attributedStringWithAttachment:attachment]
+ mutableCopy]);
+ [as addAttribute:NSBaselineOffsetAttributeName
+ value:[NSNumber numberWithFloat:baselineAdjustment]
+ range:NSMakeRange(0, [as length])];
+
+ return [[as copy] autorelease];
+}
+
} // namespace
+@implementation AutocompleteTextAttachmentCell
+
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView {
+ // Draw image with |DrawImageInRect()| to get consistent
+ // |-setFlipped:| treatment.
+ DrawImageInRect([self image], aView, cellFrame);
+}
+
+@end
+
@implementation AutocompleteTextFieldIcon
@synthesize rect = rect_;
@synthesize view = view_;
-+ (AutocompleteTextFieldIcon*)
- iconWithRect:(NSRect)rect
- view:(LocationBarViewMac::LocationBarImageView*)view {
- AutocompleteTextFieldIcon* result = [[AutocompleteTextFieldIcon alloc] init];
- [result setRect:rect];
- [result setView:view];
- return [result autorelease];
+// Private helper.
+- (id)initWithView:(LocationBarViewMac::LocationBarImageView*)view
+ isLabel:(BOOL)isLabel {
+ self = [super init];
+ if (self) {
+ isLabel_ = isLabel;
+ view_ = view;
+ rect_ = NSZeroRect;
+ }
+ return self;
+}
+
+- (id)initImageWithView:(LocationBarViewMac::LocationBarImageView*)view {
+ return [self initWithView:view isLabel:NO];
+}
+
+- (id)initLabelWithView:(LocationBarViewMac::LocationBarImageView*)view {
+ return [self initWithView:view isLabel:YES];
+}
+
+- (void)positionInFrame:(NSRect)frame {
+ if (isLabel_) {
+ NSAttributedString* label = view_->GetLabel();
+ DCHECK(label);
+ const CGFloat labelWidth = ceil([label size].width);
+ rect_ = NSMakeRect(NSMaxX(frame) - labelWidth,
+ NSMinY(frame) + kIconLabelYOffset,
+ labelWidth, NSHeight(frame) - kIconLabelYOffset);
+ } else {
+ const NSSize imageSize = view_->GetImageSize();
+ const CGFloat yOffset = floor((NSHeight(frame) - imageSize.height) / 2);
+ rect_ = NSMakeRect(NSMaxX(frame) - imageSize.width,
+ NSMinY(frame) + yOffset,
+ imageSize.width, imageSize.height);
+ }
+}
+
+- (void)drawInView:(NSView*)controlView {
+ // Make sure someone called |-positionInFrame:|.
+ DCHECK(!NSIsEmptyRect(rect_));
+ if (isLabel_) {
+ NSAttributedString* label = view_->GetLabel();
+ [label drawInRect:rect_];
+ } else {
+ DrawImageInRect(view_->GetImage(), controlView, rect_);
+ }
}
@end
@@ -96,18 +205,40 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) {
// Adjust for space between editor and decorations.
width -= 2 * kEditorHorizontalInset;
- // If |fullString| won't fit, choose |partialString|.
+ // Get the magnifying glass to put at the front of the string.
+ NSImage* image =
+ AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_SEARCH);
+ const NSSize imageSize = [image size];
+
+ // Based on what fits, choose |fullString| with the image,
+ // |fullString| without the image, or |partialString|.
NSDictionary* attributes =
[NSDictionary dictionaryWithObject:[self font]
forKey:NSFontAttributeName];
NSString* s = fullString;
- if ([s sizeWithAttributes:attributes].width > width) {
+ const CGFloat sWidth = [s sizeWithAttributes:attributes].width;
+ if (sWidth + imageSize.width > width) {
+ image = nil;
+ }
+ if (sWidth > width) {
if (partialString) {
s = partialString;
}
}
- keywordString_.reset(
- [[NSAttributedString alloc] initWithString:s attributes:attributes]);
+
+ scoped_nsobject<NSMutableAttributedString> as(
+ [[NSMutableAttributedString alloc] initWithString:s
+ attributes:attributes]);
+
+ // Insert the image at the front of the string if it didn't make
+ // things too wide.
+ if (image) {
+ NSAttributedString* is =
+ AttributedStringForImage(image, kKeywordSearchImageBaseline);
+ [as insertAttributedString:is atIndex:0];
+ }
+
+ keywordString_.reset([as copy]);
}
// Convenience for the attributes used in the right-justified info
@@ -155,21 +286,8 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) {
initWithString:s attributes:[self hintAttributes]]);
// Build an attachment containing the hint image.
- scoped_nsobject<NSTextAttachmentCell> attachmentCell(
- [[NSTextAttachmentCell alloc] initImageCell:anImage]);
- scoped_nsobject<NSTextAttachment> attachment(
- [[NSTextAttachment alloc] init]);
- [attachment setAttachmentCell:attachmentCell];
-
- // The attachment's baseline needs to be adjusted so the image
- // doesn't sit on the same baseline as the text and make
- // everything too tall.
- scoped_nsobject<NSMutableAttributedString> is(
- [[NSAttributedString attributedStringWithAttachment:attachment]
- mutableCopy]);
- [is addAttribute:NSBaselineOffsetAttributeName
- value:[NSNumber numberWithFloat:kKeywordHintImageBaseline]
- range:NSMakeRange(0, [is length])];
+ NSAttributedString* is =
+ AttributedStringForImage(anImage, kKeywordHintImageBaseline);
// Stuff the image attachment between the prefix and suffix.
[as insertAttributedString:is atIndex:[prefixString length]];
@@ -213,8 +331,16 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) {
page_action_views_ = list;
}
-- (void)setSecurityImageView:(LocationBarViewMac::SecurityImageView*)view {
- security_image_view_ = view;
+- (void)setLocationIconView:(LocationBarViewMac::LocationIconView*)view {
+ locationIconView_ = view;
+}
+
+- (void)setStarIconView:(LocationBarViewMac::LocationBarImageView*)view {
+ starIconView_ = view;
+}
+
+- (void)setSecurityLabelView:(LocationBarViewMac::LocationBarImageView*)view {
+ securityLabelView_ = view;
}
- (void)setContentSettingViewsList:
@@ -226,69 +352,81 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) {
- (NSRect)textFrameForFrame:(NSRect)cellFrame {
NSRect textFrame([super textFrameForFrame:cellFrame]);
- if (hintString_) {
+ // NOTE: This function must closely match the logic in
+ // |-drawInteriorWithFrame:inView:|.
+
+ // Location icon is not shown in keyword search mode.
+ if (!keywordString_ && locationIconView_ && locationIconView_->IsVisible()) {
+ const NSRect iconFrame = [self locationIconFrameForFrame:cellFrame];
+ const CGFloat newOrigin = NSMaxX(iconFrame) + kLocationIconXPad;
+ textFrame.size.width = NSMaxX(textFrame) - newOrigin;
+ textFrame.origin.x = newOrigin;
+ }
+
+ // Leave room for items on the right (SSL label, page actions, etc).
+ // Icons are laid out in |cellFrame| rather than |textFrame| for
+ // consistency with drawing code.
+ NSArray* icons = [self layedOutIcons:cellFrame];
+ if ([icons count]) {
+ // Max x for resulting text frame.
+ const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]);
+ textFrame.size.width = maxX - NSMinX(textFrame);
+ }
+
+ // Keyword string or hint string if they fit.
+ if (keywordString_) {
+ DCHECK(!hintString_);
+ const CGFloat keywordWidth(WidthForKeyword(keywordString_));
+
+ if (keywordWidth < NSWidth(textFrame)) {
+ textFrame.origin.x += keywordWidth;
+ textFrame.size.width -= keywordWidth;
+ }
+ } else if (hintString_) {
DCHECK(!keywordString_);
const CGFloat hintWidth(WidthForHint(hintString_));
// TODO(shess): This could be better. Show the hint until the
// non-hint text bumps against it?
- if (hintWidth < NSWidth(cellFrame)) {
+ if (hintWidth < NSWidth(textFrame)) {
textFrame.size.width -= hintWidth;
}
- } else if (keywordString_) {
- DCHECK(!hintString_);
- const CGFloat keywordWidth(WidthForKeyword(keywordString_));
+ }
- // TODO(shess): This could be better. There's support for a
- // "short" version of the keyword string, work that in in a
- // follow-on pass.
- if (keywordWidth < NSWidth(cellFrame)) {
- textFrame.origin.x += keywordWidth;
- textFrame.size.width = NSMaxX(cellFrame) - NSMinX(textFrame);
+ // SSL label if it fits.
+ if (securityLabelView_ && securityLabelView_->IsVisible() &&
+ securityLabelView_->GetLabel()) {
+ NSAttributedString* label = securityLabelView_->GetLabel();
+ const CGFloat labelWidth = ceil([label size].width) + kIconHorizontalPad;
+ if (NSWidth(textFrame) > labelWidth) {
+ textFrame.size.width -= labelWidth;
}
- } else {
- // Leave room for images on the right (lock icon etc).
- NSArray* iconFrames = [self layedOutIcons:cellFrame];
- CGFloat width = 0;
- if ([iconFrames count] > 0)
- width = NSMaxX(cellFrame) - NSMinX([[iconFrames lastObject] rect]);
- if (width > 0)
- width += kIconHorizontalPad;
- if (width < NSWidth(cellFrame))
- textFrame.size.width -= width;
}
return textFrame;
}
-// Returns a rect of size |imageSize| centered vertically and right-justified in
-// the |box|, with its top left corner |margin| pixels from the right end of the
-// box. (The image thus occupies part of the |margin|.)
-- (NSRect)rightJustifyImage:(NSSize)imageSize
- inRect:(NSRect)box
- withMargin:(CGFloat)margin {
- box.origin.x += box.size.width - margin;
- box.origin.y += floor((box.size.height - imageSize.height) / 2);
- box.size = imageSize;
- return box;
+- (NSRect)locationIconFrameForFrame:(NSRect)cellFrame {
+ if (!locationIconView_ || !locationIconView_->IsVisible())
+ return NSZeroRect;
+
+ const NSSize imageSize = locationIconView_->GetImageSize();
+ const CGFloat yOffset = floor((NSHeight(cellFrame) - imageSize.height) / 2);
+ return NSMakeRect(NSMinX(cellFrame) + kLocationIconXOffset,
+ NSMinY(cellFrame) + yOffset,
+ imageSize.width, imageSize.height);
}
-- (NSRect)securityImageFrameForFrame:(NSRect)cellFrame {
- if (!security_image_view_ || !security_image_view_->IsVisible()) {
+- (NSRect)starIconFrameForFrame:(NSRect)cellFrame {
+ if (!starIconView_ || !starIconView_->IsVisible())
return NSZeroRect;
- }
-
- // Calculate the total width occupied by the image, label, and padding.
- NSSize imageSize = [security_image_view_->GetImage() size];
- CGFloat widthUsed = imageSize.width + kIconHorizontalPad;
- NSAttributedString* label = security_image_view_->GetLabel();
- if (label) {
- widthUsed += ceil([label size].width) + kHintXOffset;
- }
- return [self rightJustifyImage:imageSize
- inRect:cellFrame
- withMargin:widthUsed];
+ // The star icon is always at the RHS.
+ scoped_nsobject<AutocompleteTextFieldIcon> icon(
+ [[AutocompleteTextFieldIcon alloc] initImageWithView:starIconView_]);
+ cellFrame.size.width -= kHintXOffset;
+ [icon positionInFrame:cellFrame];
+ return [icon rect];
}
- (size_t)pageActionCount {
@@ -365,118 +503,223 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) {
[path stroke];
// Draw text w/in the rectangle.
- infoFrame.origin.x += 4.0;
- infoFrame.origin.y += 1.0;
+ infoFrame.origin.x += 3.0;
[keywordString_.get() drawInRect:infoFrame];
}
-- (void)drawImageView:(LocationBarViewMac::LocationBarImageView*)imageView
- inFrame:(NSRect)imageFrame
- inView:(NSView*)controlView {
- // If there's a label, draw it to the right of the icon. The caller must have
- // left sufficient space.
- NSAttributedString* label = imageView->GetLabel();
- if (label) {
- CGFloat labelWidth = ceil([label size].width) + kHintXOffset;
- NSRect textFrame(NSMakeRect(NSMaxX(imageFrame) + kIconHorizontalPad,
- imageFrame.origin.y + kIconLabelYOffset,
- labelWidth,
- imageFrame.size.height - kIconLabelYOffset));
- [label drawInRect:textFrame];
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ NSRect workingFrame = cellFrame;
+
+ // NOTE: This function must closely match the logic in
+ // |-textFrameForFrame:|.
+
+ // Location icon is not shown in keyword search mode.
+ if (!keywordString_ && locationIconView_ && locationIconView_->IsVisible()) {
+ const NSRect iconFrame = [self locationIconFrameForFrame:cellFrame];
+ DrawImageInRect(locationIconView_->GetImage(), controlView, iconFrame);
+ const CGFloat newOrigin = NSMaxX(iconFrame) + kLocationIconXPad;
+ workingFrame.size.width = NSMaxX(workingFrame) - newOrigin;
+ workingFrame.origin.x = newOrigin;
}
- // Draw the entire image.
- NSRect imageRect = NSZeroRect;
- NSImage* image = imageView->GetImage();
- image.size = [image size];
- [image setFlipped:[controlView isFlipped]];
- [image drawInRect:imageFrame
- fromRect:imageRect
- operation:NSCompositeSourceOver
- fraction:1.0];
-}
+ NSArray* icons = [self layedOutIcons:cellFrame];
+ for (AutocompleteTextFieldIcon* icon in icons) {
+ [icon drawInView:controlView];
+ }
+ if ([icons count]) {
+ // Max x for resulting text frame.
+ const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]);
+ workingFrame.size.width = maxX - NSMinX(workingFrame);
+ }
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- if (hintString_) {
- [self drawHintWithFrame:cellFrame inView:controlView];
- } else if (keywordString_) {
- [self drawKeywordWithFrame:cellFrame inView:controlView];
- } else {
- for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) {
- [self drawImageView:[icon view]
- inFrame:[icon rect]
- inView:controlView];
+ // Keyword string or hint string if they fit.
+ if (keywordString_) {
+ DCHECK(!hintString_);
+ const CGFloat keywordWidth(WidthForKeyword(keywordString_));
+
+ if (keywordWidth < NSWidth(workingFrame)) {
+ [self drawKeywordWithFrame:cellFrame inView:controlView];
+ workingFrame.origin.x += keywordWidth;
+ workingFrame.size.width -= keywordWidth;
+ }
+ } else if (hintString_) {
+ DCHECK(!keywordString_);
+ const CGFloat hintWidth(WidthForHint(hintString_));
+
+ // TODO(shess): This could be better. Show the hint until the
+ // non-hint text bumps against it?
+ if (hintWidth < NSWidth(workingFrame)) {
+ [self drawHintWithFrame:cellFrame inView:controlView];
+ workingFrame.size.width -= hintWidth;
}
}
+ // SSL label if it fits.
+ if (securityLabelView_ && securityLabelView_->IsVisible() &&
+ securityLabelView_->GetLabel()) {
+ NSAttributedString* label = securityLabelView_->GetLabel();
+ const CGFloat labelWidth = ceil([label size].width) + kIconHorizontalPad;
+ if (NSWidth(workingFrame) > labelWidth) {
+ workingFrame.size.width -= kIconHorizontalPad;
+
+ scoped_nsobject<AutocompleteTextFieldIcon> icon(
+ [[AutocompleteTextFieldIcon alloc]
+ initLabelWithView:securityLabelView_]);
+ [icon positionInFrame:workingFrame];
+ [icon drawInView:controlView];
+ DCHECK_EQ(labelWidth, NSWidth([icon rect]) + kIconHorizontalPad);
+ workingFrame.size.width -= NSWidth([icon rect]);
+ }
+ }
+
+ // Superclass draws text portion WRT original |cellFrame|.
[super drawInteriorWithFrame:cellFrame inView:controlView];
}
- (NSArray*)layedOutIcons:(NSRect)cellFrame {
- NSMutableArray* result = [NSMutableArray arrayWithCapacity:0];
- NSRect iconFrame = cellFrame;
- if (security_image_view_ && security_image_view_->IsVisible()) {
- NSRect securityImageFrame = [self securityImageFrameForFrame:iconFrame];
- [result addObject:
- [AutocompleteTextFieldIcon iconWithRect:securityImageFrame
- view:security_image_view_]];
- iconFrame.size.width -= NSMaxX(iconFrame) - NSMinX(securityImageFrame);
+ // The set of views to display right-justified in the cell, from
+ // left to right.
+ NSMutableArray* result = [NSMutableArray array];
+
+ // Collect the image views for bulk processing.
+ // TODO(shess): Refactor with LocationBarViewMac to make the
+ // different types of items more consistent.
+ std::vector<LocationBarViewMac::LocationBarImageView*> views;
+
+ if (content_setting_views_) {
+ views.insert(views.end(),
+ content_setting_views_->begin(),
+ content_setting_views_->end());
}
- const size_t pageActionCount = [self pageActionCount];
- for (size_t i = 0; i < pageActionCount; ++i) {
- LocationBarViewMac::PageActionImageView* view =
- page_action_views_->ViewAt(i);
- if (view->IsVisible()) {
- // If this function is called right after a page action icon has been
- // created, the images for all views will still be loading; in this case,
- // each visible view will give us its default size.
- NSSize iconSize = view->GetPreferredImageSize();
- NSRect pageActionFrame =
- [self rightJustifyImage:iconSize
- inRect:iconFrame
- withMargin:kIconHorizontalPad + iconSize.width];
- [result addObject:
- [AutocompleteTextFieldIcon iconWithRect:pageActionFrame view:view]];
- iconFrame.size.width -= NSMaxX(iconFrame) - NSMinX(pageActionFrame);
- }
+ // TODO(shess): Previous implementation of this method made a
+ // right-to-left array, so add the page-action items in that order.
+ // As part of the refactor mentioned above, lay everything out
+ // nicely left-to-right.
+ for (size_t i = [self pageActionCount]; i-- > 0;) {
+ views.push_back(page_action_views_->ViewAt(i));
}
- if (content_setting_views_) {
- // We use a reverse_iterator here because we're laying out the views from
- // right to left but in the vector they're ordered left to right.
- for (LocationBarViewMac::ContentSettingViews::const_reverse_iterator
- it(content_setting_views_->rbegin());
- it != const_cast<const LocationBarViewMac::ContentSettingViews*>(
- content_setting_views_)->rend();
- ++it) {
- if ((*it)->IsVisible()) {
- NSImage* image = (*it)->GetImage();
- NSRect blockedContentFrame =
- [self rightJustifyImage:[image size]
- inRect:iconFrame
- withMargin:[image size].width + kIconHorizontalPad];
- [result addObject:
- [AutocompleteTextFieldIcon iconWithRect:blockedContentFrame
- view:*it]];
- iconFrame.size.width -= NSMaxX(iconFrame) - NSMinX(blockedContentFrame);
- }
+ // The star icon should always come last.
+ if (starIconView_)
+ views.push_back(starIconView_);
+
+ // Load the visible views into |result|.
+ for (std::vector<LocationBarViewMac::LocationBarImageView*>::const_iterator
+ iter = views.begin(); iter != views.end(); ++iter) {
+ if ((*iter)->IsVisible()) {
+ scoped_nsobject<AutocompleteTextFieldIcon> icon(
+ [[AutocompleteTextFieldIcon alloc] initImageWithView:*iter]);
+ [result addObject:icon];
}
}
+
+ // Leave a boundary at RHS of field.
+ cellFrame.size.width -= kHintXOffset;
+
+ // Position each view within the frame from right to left.
+ for (AutocompleteTextFieldIcon* icon in [result reverseObjectEnumerator]) {
+ [icon positionInFrame:cellFrame];
+
+ // Trim the icon's space from the frame.
+ cellFrame.size.width = NSMinX([icon rect]) - kIconHorizontalPad;
+ }
return result;
}
-- (NSMenu*)actionMenuForEvent:(NSEvent*)event
- inRect:(NSRect)cellFrame
- ofView:(NSView*)aView {
- NSPoint location = [aView convertPoint:[event locationInWindow] fromView:nil];
+- (AutocompleteTextFieldIcon*)iconForEvent:(NSEvent*)theEvent
+ inRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)controlView {
+ const BOOL flipped = [controlView isFlipped];
+ const NSPoint location =
+ [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
+
+ // Special check for location image, it is not in |-layedOutIcons:|.
+ const NSRect locationIconFrame = [self locationIconFrameForFrame:cellFrame];
+ if (NSMouseInRect(location, locationIconFrame, flipped)) {
+ // Make up an icon to return.
+ AutocompleteTextFieldIcon* icon =
+ [[[AutocompleteTextFieldIcon alloc]
+ initImageWithView:locationIconView_] autorelease];
+ [icon setRect:locationIconFrame];
+ return icon;
+ }
- const BOOL flipped = [aView isFlipped];
for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) {
- if (NSMouseInRect(location, [icon rect], flipped)) {
- return [icon view]->GetMenu();
+ if (NSMouseInRect(location, [icon rect], flipped))
+ return icon;
+ }
+
+ return nil;
+}
+
+- (NSMenu*)actionMenuForEvent:(NSEvent*)theEvent
+ inRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)controlView {
+ AutocompleteTextFieldIcon*
+ icon = [self iconForEvent:theEvent inRect:cellFrame ofView:controlView];
+ if (icon)
+ return [icon view]->GetMenu();
+ return nil;
+}
+
+- (BOOL)mouseDown:(NSEvent*)theEvent
+ inRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)controlView {
+ AutocompleteTextFieldIcon* icon =
+ [self iconForEvent:theEvent inRect:cellFrame ofView:controlView];
+ if (!icon)
+ return NO;
+
+ // If the icon is draggable, then initiate a drag if the user drags
+ // or holds the mouse down for awhile.
+ if ([icon view]->IsDraggable()) {
+ NSDate* timeout =
+ [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout];
+ NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask |
+ NSLeftMouseUpMask)
+ untilDate:timeout
+ inMode:NSEventTrackingRunLoopMode
+ dequeue:YES];
+ if (!event || [event type] == NSLeftMouseDragged) {
+ NSPasteboard* pboard = [icon view]->GetDragPasteboard();
+ DCHECK(pboard);
+
+ // TODO(shess): My understanding is that the -isFlipped
+ // adjustment should not be necessary. But without it, the
+ // image is nowhere near the cursor. Perhaps the icon's rect is
+ // incorrectly calculated?
+ // http://crbug.com/40711
+ NSPoint dragPoint = [icon rect].origin;
+ if ([controlView isFlipped])
+ dragPoint.y += NSHeight([icon rect]);
+
+ [controlView dragImage:[icon view]->GetImage()
+ at:dragPoint
+ offset:NSZeroSize
+ event:event ? event : theEvent
+ pasteboard:pboard
+ source:self
+ slideBack:YES];
+ return YES;
}
+
+ // On mouse-up fall through to mouse-pressed case.
+ DCHECK_EQ([event type], NSLeftMouseUp);
}
+
+ [icon view]->OnMousePressed([icon rect]);
+ return YES;
+}
+
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
+ return NSDragOperationCopy;
+}
+
+- (NSPasteboard*)locationDragPasteboard {
+ if (locationIconView_ && locationIconView_->IsDraggable())
+ return locationIconView_->GetDragPasteboard();
+
return nil;
}