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 |