| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h" | 5 #import "chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #import "chrome/browser/cocoa/image_utils.h" | 8 #import "chrome/browser/cocoa/image_utils.h" |
| 9 #import "chrome/browser/cocoa/location_bar/location_bar_decoration.h" | 9 #import "chrome/browser/cocoa/location_bar/location_bar_decoration.h" |
| 10 | 10 |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 @implementation AutocompleteTextAttachmentCell | 206 @implementation AutocompleteTextAttachmentCell |
| 207 | 207 |
| 208 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView { | 208 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView { |
| 209 // Draw image with |DrawImageInRect()| to get consistent | 209 // Draw image with |DrawImageInRect()| to get consistent |
| 210 // flipped treatment. | 210 // flipped treatment. |
| 211 DrawImageInRect([self image], aView, cellFrame); | 211 DrawImageInRect([self image], aView, cellFrame); |
| 212 } | 212 } |
| 213 | 213 |
| 214 @end | 214 @end |
| 215 | 215 |
| 216 @implementation AutocompleteTextFieldIcon | |
| 217 | |
| 218 @synthesize rect = rect_; | |
| 219 @synthesize view = view_; | |
| 220 | |
| 221 // Private helper. | |
| 222 - (id)initWithView:(LocationBarViewMac::LocationBarImageView*)view | |
| 223 isLabel:(BOOL)isLabel { | |
| 224 self = [super init]; | |
| 225 if (self) { | |
| 226 isLabel_ = isLabel; | |
| 227 view_ = view; | |
| 228 rect_ = NSZeroRect; | |
| 229 } | |
| 230 return self; | |
| 231 } | |
| 232 | |
| 233 - (id)initImageWithView:(LocationBarViewMac::LocationBarImageView*)view { | |
| 234 return [self initWithView:view isLabel:NO]; | |
| 235 } | |
| 236 | |
| 237 - (id)initLabelWithView:(LocationBarViewMac::LocationBarImageView*)view { | |
| 238 return [self initWithView:view isLabel:YES]; | |
| 239 } | |
| 240 | |
| 241 - (void)positionInFrame:(NSRect)frame { | |
| 242 if (isLabel_) { | |
| 243 NSAttributedString* label = view_->GetLabel(); | |
| 244 DCHECK(label); | |
| 245 const CGFloat labelWidth = ceil([label size].width); | |
| 246 rect_ = NSMakeRect(NSMaxX(frame) - labelWidth, | |
| 247 NSMinY(frame) + kIconLabelYOffset, | |
| 248 labelWidth, NSHeight(frame) - kIconLabelYOffset); | |
| 249 } else { | |
| 250 const NSSize imageSize = view_->GetImageSize(); | |
| 251 const CGFloat yOffset = floor((NSHeight(frame) - imageSize.height) / 2); | |
| 252 rect_ = NSMakeRect(NSMaxX(frame) - imageSize.width, | |
| 253 NSMinY(frame) + yOffset, | |
| 254 imageSize.width, imageSize.height); | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 - (void)drawInView:(NSView*)controlView { | |
| 259 // Make sure someone called |-positionInFrame:|. | |
| 260 DCHECK(!NSIsEmptyRect(rect_)); | |
| 261 if (isLabel_) { | |
| 262 NSAttributedString* label = view_->GetLabel(); | |
| 263 [label drawInRect:rect_]; | |
| 264 } else { | |
| 265 DrawImageInRect(view_->GetImage(), controlView, rect_); | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 @end | |
| 270 | |
| 271 @implementation AutocompleteTextFieldCell | 216 @implementation AutocompleteTextFieldCell |
| 272 | 217 |
| 273 // @synthesize doesn't seem to compile for this transition. | 218 // @synthesize doesn't seem to compile for this transition. |
| 274 - (NSAttributedString*)hintString { | 219 - (NSAttributedString*)hintString { |
| 275 return hintString_.get(); | 220 return hintString_.get(); |
| 276 } | 221 } |
| 277 | 222 |
| 278 - (CGFloat)baselineAdjust { | 223 - (CGFloat)baselineAdjust { |
| 279 return kBaselineAdjust; | 224 return kBaselineAdjust; |
| 280 } | 225 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 | 302 |
| 358 // If too wide, don't keep the hint. | 303 // If too wide, don't keep the hint. |
| 359 hintString_.reset(WidthForHint(as) > width ? nil : [as copy]); | 304 hintString_.reset(WidthForHint(as) > width ? nil : [as copy]); |
| 360 } | 305 } |
| 361 } | 306 } |
| 362 | 307 |
| 363 - (void)clearHint { | 308 - (void)clearHint { |
| 364 hintString_.reset(); | 309 hintString_.reset(); |
| 365 } | 310 } |
| 366 | 311 |
| 367 - (void)setContentSettingViewsList: | |
| 368 (LocationBarViewMac::ContentSettingViews*)views { | |
| 369 content_setting_views_ = views; | |
| 370 } | |
| 371 | |
| 372 - (void)clearDecorations { | 312 - (void)clearDecorations { |
| 373 leftDecorations_.clear(); | 313 leftDecorations_.clear(); |
| 374 rightDecorations_.clear(); | 314 rightDecorations_.clear(); |
| 375 } | 315 } |
| 376 | 316 |
| 377 - (void)addLeftDecoration:(LocationBarDecoration*)decoration { | 317 - (void)addLeftDecoration:(LocationBarDecoration*)decoration { |
| 378 leftDecorations_.push_back(decoration); | 318 leftDecorations_.push_back(decoration); |
| 379 } | 319 } |
| 380 | 320 |
| 381 - (void)addRightDecoration:(LocationBarDecoration*)decoration { | 321 - (void)addRightDecoration:(LocationBarDecoration*)decoration { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 // Get the frame adjusted for decorations. | 365 // Get the frame adjusted for decorations. |
| 426 std::vector<LocationBarDecoration*> decorations; | 366 std::vector<LocationBarDecoration*> decorations; |
| 427 std::vector<NSRect> decorationFrames; | 367 std::vector<NSRect> decorationFrames; |
| 428 NSRect textFrame = [super textFrameForFrame:cellFrame]; | 368 NSRect textFrame = [super textFrameForFrame:cellFrame]; |
| 429 CalculatePositionsInFrame(textFrame, leftDecorations_, rightDecorations_, | 369 CalculatePositionsInFrame(textFrame, leftDecorations_, rightDecorations_, |
| 430 &decorations, &decorationFrames, &textFrame); | 370 &decorations, &decorationFrames, &textFrame); |
| 431 | 371 |
| 432 // NOTE: This function must closely match the logic in | 372 // NOTE: This function must closely match the logic in |
| 433 // |-drawInteriorWithFrame:inView:|. | 373 // |-drawInteriorWithFrame:inView:|. |
| 434 | 374 |
| 435 // Leave room for items on the right (SSL label, page actions, etc). | |
| 436 // Icons are laid out in |cellFrame| rather than |textFrame| for | |
| 437 // consistency with drawing code. | |
| 438 NSArray* icons = [self layedOutIcons:cellFrame]; | |
| 439 if ([icons count]) { | |
| 440 // Max x for resulting text frame. | |
| 441 const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]); | |
| 442 textFrame.size.width = maxX - NSMinX(textFrame); | |
| 443 } | |
| 444 | |
| 445 // Keyword string or hint string if they fit. | 375 // Keyword string or hint string if they fit. |
| 446 if (hintString_) { | 376 if (hintString_) { |
| 447 const CGFloat hintWidth(WidthForHint(hintString_)); | 377 const CGFloat hintWidth(WidthForHint(hintString_)); |
| 448 | 378 |
| 449 // TODO(shess): This could be better. Show the hint until the | 379 // TODO(shess): This could be better. Show the hint until the |
| 450 // non-hint text bumps against it? | 380 // non-hint text bumps against it? |
| 451 if (hintWidth < NSWidth(textFrame)) { | 381 if (hintWidth < NSWidth(textFrame)) { |
| 452 textFrame.size.width -= hintWidth; | 382 textFrame.size.width -= hintWidth; |
| 453 } | 383 } |
| 454 } | 384 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 476 | 406 |
| 477 // Draw the decorations first. | 407 // Draw the decorations first. |
| 478 for (size_t i = 0; i < decorations.size(); ++i) { | 408 for (size_t i = 0; i < decorations.size(); ++i) { |
| 479 if (decorations[i]) | 409 if (decorations[i]) |
| 480 decorations[i]->DrawInFrame(decorationFrames[i], controlView); | 410 decorations[i]->DrawInFrame(decorationFrames[i], controlView); |
| 481 } | 411 } |
| 482 | 412 |
| 483 // NOTE: This function must closely match the logic in | 413 // NOTE: This function must closely match the logic in |
| 484 // |-textFrameForFrame:|. | 414 // |-textFrameForFrame:|. |
| 485 | 415 |
| 486 NSArray* icons = [self layedOutIcons:cellFrame]; | |
| 487 for (AutocompleteTextFieldIcon* icon in icons) { | |
| 488 [icon drawInView:controlView]; | |
| 489 } | |
| 490 if ([icons count]) { | |
| 491 // Max x for resulting text frame. | |
| 492 const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]); | |
| 493 workingFrame.size.width = maxX - NSMinX(workingFrame); | |
| 494 } | |
| 495 | |
| 496 // Keyword string or hint string if they fit. | 416 // Keyword string or hint string if they fit. |
| 497 if (hintString_) { | 417 if (hintString_) { |
| 498 const CGFloat hintWidth(WidthForHint(hintString_)); | 418 const CGFloat hintWidth(WidthForHint(hintString_)); |
| 499 | 419 |
| 500 // TODO(shess): This could be better. Show the hint until the | 420 // TODO(shess): This could be better. Show the hint until the |
| 501 // non-hint text bumps against it? | 421 // non-hint text bumps against it? |
| 502 if (hintWidth < NSWidth(workingFrame)) { | 422 if (hintWidth < NSWidth(workingFrame)) { |
| 503 [self drawHintWithFrame:cellFrame inView:controlView]; | 423 [self drawHintWithFrame:cellFrame inView:controlView]; |
| 504 workingFrame.size.width -= hintWidth; | 424 workingFrame.size.width -= hintWidth; |
| 505 } | 425 } |
| 506 } | 426 } |
| 507 | 427 |
| 508 // Superclass draws text portion WRT original |cellFrame|. | 428 // Superclass draws text portion WRT original |cellFrame|. |
| 509 [super drawInteriorWithFrame:cellFrame inView:controlView]; | 429 [super drawInteriorWithFrame:cellFrame inView:controlView]; |
| 510 } | 430 } |
| 511 | 431 |
| 512 - (NSArray*)layedOutIcons:(NSRect)cellFrame { | |
| 513 // Trim the decoration area from |cellFrame|. This is duplicate | |
| 514 // work WRT the caller in some cases, but locating this here is | |
| 515 // simpler, and this code will go away soon. | |
| 516 std::vector<LocationBarDecoration*> decorations; | |
| 517 std::vector<NSRect> decorationFrames; | |
| 518 CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_, | |
| 519 &decorations, &decorationFrames, &cellFrame); | |
| 520 | |
| 521 // The set of views to display right-justified in the cell, from | |
| 522 // left to right. | |
| 523 NSMutableArray* result = [NSMutableArray array]; | |
| 524 | |
| 525 // Collect the image views for bulk processing. | |
| 526 // TODO(shess): Refactor with LocationBarViewMac to make the | |
| 527 // different types of items more consistent. | |
| 528 std::vector<LocationBarViewMac::LocationBarImageView*> views; | |
| 529 | |
| 530 if (content_setting_views_) { | |
| 531 views.insert(views.end(), | |
| 532 content_setting_views_->begin(), | |
| 533 content_setting_views_->end()); | |
| 534 } | |
| 535 | |
| 536 // Load the visible views into |result|. | |
| 537 for (std::vector<LocationBarViewMac::LocationBarImageView*>::const_iterator | |
| 538 iter = views.begin(); iter != views.end(); ++iter) { | |
| 539 if ((*iter)->IsVisible()) { | |
| 540 scoped_nsobject<AutocompleteTextFieldIcon> icon( | |
| 541 [[AutocompleteTextFieldIcon alloc] initImageWithView:*iter]); | |
| 542 [result addObject:icon]; | |
| 543 } | |
| 544 } | |
| 545 | |
| 546 // Padding from right-hand decoration. There should always be at | |
| 547 // least one (the star). | |
| 548 cellFrame.size.width -= kDecorationHorizontalPad; | |
| 549 | |
| 550 // Position each view within the frame from right to left. | |
| 551 for (AutocompleteTextFieldIcon* icon in [result reverseObjectEnumerator]) { | |
| 552 [icon positionInFrame:cellFrame]; | |
| 553 | |
| 554 // Trim the icon's space from the frame. | |
| 555 cellFrame.size.width = | |
| 556 NSMinX([icon rect]) - NSMinX(cellFrame) - kDecorationHorizontalPad; | |
| 557 } | |
| 558 return result; | |
| 559 } | |
| 560 | |
| 561 // Returns the decoration under |theEvent|, or NULL if none. | |
| 562 // Like |-iconForEvent:inRect:ofView:|, but for decorations. | |
| 563 - (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent | 432 - (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent |
| 564 inRect:(NSRect)cellFrame | 433 inRect:(NSRect)cellFrame |
| 565 ofView:(AutocompleteTextField*)controlView | 434 ofView:(AutocompleteTextField*)controlView |
| 566 { | 435 { |
| 567 const BOOL flipped = [controlView isFlipped]; | 436 const BOOL flipped = [controlView isFlipped]; |
| 568 const NSPoint location = | 437 const NSPoint location = |
| 569 [controlView convertPoint:[theEvent locationInWindow] fromView:nil]; | 438 [controlView convertPoint:[theEvent locationInWindow] fromView:nil]; |
| 570 | 439 |
| 571 std::vector<LocationBarDecoration*> decorations; | 440 std::vector<LocationBarDecoration*> decorations; |
| 572 std::vector<NSRect> decorationFrames; | 441 std::vector<NSRect> decorationFrames; |
| 573 NSRect textFrame; | 442 NSRect textFrame; |
| 574 CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_, | 443 CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_, |
| 575 &decorations, &decorationFrames, &textFrame); | 444 &decorations, &decorationFrames, &textFrame); |
| 576 | 445 |
| 577 for (size_t i = 0; i < decorations.size(); ++i) { | 446 for (size_t i = 0; i < decorations.size(); ++i) { |
| 578 if (NSMouseInRect(location, decorationFrames[i], flipped)) | 447 if (NSMouseInRect(location, decorationFrames[i], flipped)) |
| 579 return decorations[i]; | 448 return decorations[i]; |
| 580 } | 449 } |
| 581 | 450 |
| 582 return NULL; | 451 return NULL; |
| 583 } | 452 } |
| 584 | 453 |
| 585 - (AutocompleteTextFieldIcon*)iconForEvent:(NSEvent*)theEvent | |
| 586 inRect:(NSRect)cellFrame | |
| 587 ofView:(AutocompleteTextField*)controlView { | |
| 588 const BOOL flipped = [controlView isFlipped]; | |
| 589 const NSPoint location = | |
| 590 [controlView convertPoint:[theEvent locationInWindow] fromView:nil]; | |
| 591 | |
| 592 for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) { | |
| 593 if (NSMouseInRect(location, [icon rect], flipped)) | |
| 594 return icon; | |
| 595 } | |
| 596 | |
| 597 return nil; | |
| 598 } | |
| 599 | |
| 600 - (NSMenu*)decorationMenuForEvent:(NSEvent*)theEvent | 454 - (NSMenu*)decorationMenuForEvent:(NSEvent*)theEvent |
| 601 inRect:(NSRect)cellFrame | 455 inRect:(NSRect)cellFrame |
| 602 ofView:(AutocompleteTextField*)controlView { | 456 ofView:(AutocompleteTextField*)controlView { |
| 603 LocationBarDecoration* decoration = | 457 LocationBarDecoration* decoration = |
| 604 [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView]; | 458 [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView]; |
| 605 if (decoration) | 459 if (decoration) |
| 606 return decoration->GetMenu(); | 460 return decoration->GetMenu(); |
| 607 | |
| 608 AutocompleteTextFieldIcon* | |
| 609 icon = [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; | |
| 610 if (icon) | |
| 611 return [icon view]->GetMenu(); | |
| 612 return nil; | 461 return nil; |
| 613 } | 462 } |
| 614 | 463 |
| 615 - (BOOL)mouseDown:(NSEvent*)theEvent | 464 - (BOOL)mouseDown:(NSEvent*)theEvent |
| 616 inRect:(NSRect)cellFrame | 465 inRect:(NSRect)cellFrame |
| 617 ofView:(AutocompleteTextField*)controlView { | 466 ofView:(AutocompleteTextField*)controlView { |
| 618 LocationBarDecoration* decoration = | 467 LocationBarDecoration* decoration = |
| 619 [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView]; | 468 [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView]; |
| 620 AutocompleteTextFieldIcon* icon = | 469 if (!decoration) |
| 621 [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; | |
| 622 if (!decoration && !icon) | |
| 623 return NO; | 470 return NO; |
| 624 | 471 |
| 625 NSRect decorationRect = NSZeroRect; | 472 NSRect decorationRect = |
| 626 if (icon) { | 473 [self frameForDecoration:decoration inFrame:cellFrame]; |
| 627 decorationRect = [icon rect]; | |
| 628 } else if (decoration) { | |
| 629 decorationRect = [self frameForDecoration:decoration inFrame:cellFrame]; | |
| 630 } | |
| 631 | 474 |
| 632 // If the icon is draggable, then initiate a drag if the user drags | 475 // If the decoration is draggable, then initiate a drag if the user |
| 633 // or holds the mouse down for awhile. | 476 // drags or holds the mouse down for awhile. |
| 634 if ((icon && [icon view]->IsDraggable()) || | 477 if (decoration->IsDraggable()) { |
| 635 (decoration && decoration->IsDraggable())) { | |
| 636 DCHECK(icon || decoration); | |
| 637 NSDate* timeout = | 478 NSDate* timeout = |
| 638 [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout]; | 479 [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout]; |
| 639 NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask | | 480 NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask | |
| 640 NSLeftMouseUpMask) | 481 NSLeftMouseUpMask) |
| 641 untilDate:timeout | 482 untilDate:timeout |
| 642 inMode:NSEventTrackingRunLoopMode | 483 inMode:NSEventTrackingRunLoopMode |
| 643 dequeue:YES]; | 484 dequeue:YES]; |
| 644 if (!event || [event type] == NSLeftMouseDragged) { | 485 if (!event || [event type] == NSLeftMouseDragged) { |
| 645 NSPasteboard* pboard = nil; | 486 NSPasteboard* pboard = decoration->GetDragPasteboard(); |
| 646 if (icon) pboard = [icon view]->GetDragPasteboard(); | |
| 647 if (decoration) pboard = decoration->GetDragPasteboard(); | |
| 648 DCHECK(pboard); | 487 DCHECK(pboard); |
| 649 | 488 |
| 650 // TODO(shess): My understanding is that the -isFlipped | 489 // TODO(shess): My understanding is that the -isFlipped |
| 651 // adjustment should not be necessary. But without it, the | 490 // adjustment should not be necessary. But without it, the |
| 652 // image is nowhere near the cursor. Perhaps the icon's rect is | 491 // image is nowhere near the cursor. Perhaps the decorations's |
| 653 // incorrectly calculated? | 492 // rect is incorrectly calculated? |
| 654 // http://crbug.com/40711 | 493 // http://crbug.com/40711 |
| 655 NSPoint dragPoint = decorationRect.origin; | 494 NSPoint dragPoint = decorationRect.origin; |
| 656 if ([controlView isFlipped]) | 495 if ([controlView isFlipped]) |
| 657 dragPoint.y += NSHeight(decorationRect); | 496 dragPoint.y += NSHeight(decorationRect); |
| 658 | 497 |
| 659 NSImage* image = nil; | 498 NSImage* image = decoration->GetDragImage(); |
| 660 if (icon) image = [icon view]->GetImage(); | 499 DCHECK(image); |
| 661 if (decoration) image = decoration->GetDragImage(); | |
| 662 [controlView dragImage:image | 500 [controlView dragImage:image |
| 663 at:dragPoint | 501 at:dragPoint |
| 664 offset:NSZeroSize | 502 offset:NSZeroSize |
| 665 event:event ? event : theEvent | 503 event:event ? event : theEvent |
| 666 pasteboard:pboard | 504 pasteboard:pboard |
| 667 source:self | 505 source:self |
| 668 slideBack:YES]; | 506 slideBack:YES]; |
| 669 return YES; | 507 return YES; |
| 670 } | 508 } |
| 671 | 509 |
| 672 // On mouse-up fall through to mouse-pressed case. | 510 // On mouse-up fall through to mouse-pressed case. |
| 673 DCHECK_EQ([event type], NSLeftMouseUp); | 511 DCHECK_EQ([event type], NSLeftMouseUp); |
| 674 } | 512 } |
| 675 | 513 |
| 676 if (icon) { | 514 if (!decoration->OnMousePressed(decorationRect)) |
| 677 [icon view]->OnMousePressed(decorationRect); | 515 return NO; |
| 678 } else if (decoration) { | |
| 679 if (!decoration->OnMousePressed(decorationRect)) | |
| 680 return NO; | |
| 681 } | |
| 682 | 516 |
| 683 return YES; | 517 return YES; |
| 684 } | 518 } |
| 685 | 519 |
| 686 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { | 520 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { |
| 687 return NSDragOperationCopy; | 521 return NSDragOperationCopy; |
| 688 } | 522 } |
| 689 | 523 |
| 690 @end | 524 @end |
| OLD | NEW |