| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 #include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h" | 5 #include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h" |
| 6 | 6 |
| 7 #include "base/sys_string_conversions.h" | 7 #include "base/sys_string_conversions.h" |
| 8 #include "chrome/browser/autocomplete/autocomplete_edit.h" | 8 #include "chrome/browser/autocomplete/autocomplete_edit.h" |
| 9 #include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h" | 9 #include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h" |
| 10 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" | 10 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" |
| 11 #include "chrome/browser/cocoa/nsimage_cache.h" | 11 #include "chrome/browser/cocoa/nsimage_cache.h" |
| 12 | 12 |
| 13 namespace { | 13 namespace { |
| 14 | 14 |
| 15 // How to round off the popup's corners. Goal is to match star and go |
| 16 // buttons. |
| 17 const CGFloat kPopupRoundingRadius = 4.0; |
| 18 |
| 19 // How far to offset the image column from the left. |
| 20 const CGFloat kImageXOffset = 8.0; |
| 21 |
| 22 // How far to offset the text column from the left. |
| 23 const CGFloat kTextXOffset = 33.0; |
| 24 |
| 15 // Background colors for different states of the popup elements. | 25 // Background colors for different states of the popup elements. |
| 16 NSColor* BackgroundColor() { | 26 NSColor* BackgroundColor() { |
| 17 return [NSColor controlBackgroundColor]; | 27 return [NSColor controlBackgroundColor]; |
| 18 } | 28 } |
| 19 NSColor* SelectedBackgroundColor() { | 29 NSColor* SelectedBackgroundColor() { |
| 20 return [NSColor selectedControlColor]; | 30 return [NSColor selectedControlColor]; |
| 21 } | 31 } |
| 22 NSColor* HoveredBackgroundColor() { | 32 NSColor* HoveredBackgroundColor() { |
| 23 return [NSColor controlColor]; | 33 return [NSColor controlColor]; |
| 24 } | 34 } |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 225 return [popup_ isVisible] ? true : false; | 235 return [popup_ isVisible] ? true : false; |
| 226 } | 236 } |
| 227 | 237 |
| 228 void AutocompletePopupViewMac::CreatePopupIfNeeded() { | 238 void AutocompletePopupViewMac::CreatePopupIfNeeded() { |
| 229 if (!popup_) { | 239 if (!popup_) { |
| 230 popup_.reset([[NSWindow alloc] initWithContentRect:NSZeroRect | 240 popup_.reset([[NSWindow alloc] initWithContentRect:NSZeroRect |
| 231 styleMask:NSBorderlessWindowMask | 241 styleMask:NSBorderlessWindowMask |
| 232 backing:NSBackingStoreBuffered | 242 backing:NSBackingStoreBuffered |
| 233 defer:YES]); | 243 defer:YES]); |
| 234 [popup_ setMovableByWindowBackground:NO]; | 244 [popup_ setMovableByWindowBackground:NO]; |
| 235 [popup_ setOpaque:YES]; | 245 // The window will have rounded borders. |
| 236 [popup_ setHasShadow:YES]; | 246 [popup_ setAlphaValue:1.0]; |
| 247 [popup_ setOpaque:NO]; |
| 237 [popup_ setLevel:NSNormalWindowLevel]; | 248 [popup_ setLevel:NSNormalWindowLevel]; |
| 238 | 249 |
| 239 AutocompleteMatrix* matrix = | 250 AutocompleteMatrix* matrix = |
| 240 [[[AutocompleteMatrix alloc] initWithFrame:NSZeroRect] autorelease]; | 251 [[[AutocompleteMatrix alloc] initWithFrame:NSZeroRect] autorelease]; |
| 241 [matrix setTarget:matrix_target_]; | 252 [matrix setTarget:matrix_target_]; |
| 242 [matrix setAction:@selector(select:)]; | 253 [matrix setAction:@selector(select:)]; |
| 243 [popup_ setContentView:matrix]; | 254 [popup_ setContentView:matrix]; |
| 244 } | 255 } |
| 245 } | 256 } |
| 246 | 257 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 272 [cell setImage:MatchIcon(match)]; | 283 [cell setImage:MatchIcon(match)]; |
| 273 [cell setAttributedTitle:MatchText(match, [field_ font])]; | 284 [cell setAttributedTitle:MatchText(match, [field_ font])]; |
| 274 } | 285 } |
| 275 | 286 |
| 276 // Layout the popup and size it to land underneath the field. | 287 // Layout the popup and size it to land underneath the field. |
| 277 // TODO(shess) Consider refactoring to remove this depenency, | 288 // TODO(shess) Consider refactoring to remove this depenency, |
| 278 // because the popup doesn't need any of the field-like aspects of | 289 // because the popup doesn't need any of the field-like aspects of |
| 279 // field_. The edit view could expose helper methods for attaching | 290 // field_. The edit view could expose helper methods for attaching |
| 280 // the window to the field. | 291 // the window to the field. |
| 281 | 292 |
| 282 // Locate |field_| on the screen. | 293 // Locate |field_| on the screen, and pad the left and right sides |
| 294 // by the height to make it wide enough to include the star and go |
| 295 // buttons. |
| 296 // TODO(shess): This assumes that those buttons will be square. |
| 297 // Better to plumb through so that this code can get the rect from |
| 298 // the toolbar controller? |
| 283 NSRect r = [field_ convertRect:[field_ bounds] toView:nil]; | 299 NSRect r = [field_ convertRect:[field_ bounds] toView:nil]; |
| 300 r.origin.x -= r.size.height; |
| 301 r.size.width += 2 * r.size.height; |
| 284 r.origin = [[field_ window] convertBaseToScreen:r.origin]; | 302 r.origin = [[field_ window] convertBaseToScreen:r.origin]; |
| 285 DCHECK_GT(r.size.width, 0.0); | 303 DCHECK_GT(r.size.width, 0.0); |
| 286 | 304 |
| 287 // Set the cell size to fit a line of text in the cell's font. All | 305 // Set the cell size to fit a line of text in the cell's font. All |
| 288 // cells should use the same font and each should layout in one | 306 // cells should use the same font and each should layout in one |
| 289 // line, so they should all be about the same height. | 307 // line, so they should all be about the same height. |
| 290 const NSSize cellSize = [[matrix cellAtRow:0 column:0] cellSize]; | 308 const NSSize cellSize = [[matrix cellAtRow:0 column:0] cellSize]; |
| 291 DCHECK_GT(cellSize.height, 0.0); | 309 DCHECK_GT(cellSize.height, 0.0); |
| 292 [matrix setCellSize:NSMakeSize(r.size.width, cellSize.height)]; | 310 [matrix setCellSize:NSMakeSize(r.size.width, cellSize.height)]; |
| 293 | 311 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 | 368 |
| 351 - (NSColor*)backgroundColor { | 369 - (NSColor*)backgroundColor { |
| 352 if ([self state] == NSOnState) { | 370 if ([self state] == NSOnState) { |
| 353 return SelectedBackgroundColor(); | 371 return SelectedBackgroundColor(); |
| 354 } else if ([self isHighlighted]) { | 372 } else if ([self isHighlighted]) { |
| 355 return HoveredBackgroundColor(); | 373 return HoveredBackgroundColor(); |
| 356 } | 374 } |
| 357 return BackgroundColor(); | 375 return BackgroundColor(); |
| 358 } | 376 } |
| 359 | 377 |
| 378 // The default NSButtonCell drawing leaves the image flush left and |
| 379 // the title next to the image. This spaces things out to line up |
| 380 // with the star button and autocomplete field. |
| 381 // TODO(shess): Determine if the star button can change size (other |
| 382 // than scaling coordinates), in which case this needs to be more |
| 383 // dynamic. |
| 384 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { |
| 385 [[self backgroundColor] set]; |
| 386 NSRectFill(cellFrame); |
| 387 |
| 388 // Put the image centered vertically but in a fixed column. |
| 389 // TODO(shess) Currently, the images are all 16x16 png files, so |
| 390 // left-justified works out fine. If that changes, it may be |
| 391 // appropriate to align them on their centers instead of their |
| 392 // left-hand sides. |
| 393 NSImage* image = [self image]; |
| 394 if (image) { |
| 395 NSRect imageRect = cellFrame; |
| 396 imageRect.size = [image size]; |
| 397 imageRect.origin.y += |
| 398 floor((NSHeight(cellFrame) - NSHeight(imageRect)) / 2); |
| 399 imageRect.origin.x += kImageXOffset; |
| 400 [self drawImage:image withFrame:imageRect inView:controlView]; |
| 401 } |
| 402 |
| 403 // Adjust the title position to be lined up under the field's text. |
| 404 NSAttributedString* title = [self attributedTitle]; |
| 405 if (title) { |
| 406 NSRect titleRect = cellFrame; |
| 407 titleRect.size.width -= kTextXOffset; |
| 408 titleRect.origin.x += kTextXOffset; |
| 409 [self drawTitle:title withFrame:titleRect inView:controlView]; |
| 410 } |
| 411 } |
| 412 |
| 360 @end | 413 @end |
| 361 | 414 |
| 362 @implementation AutocompleteMatrix | 415 @implementation AutocompleteMatrix |
| 363 | 416 |
| 364 // Remove all tracking areas and initialize the one we want. Removing | 417 // Remove all tracking areas and initialize the one we want. Removing |
| 365 // all might be overkill, but it's unclear why there would be others | 418 // all might be overkill, but it's unclear why there would be others |
| 366 // for the popup window. | 419 // for the popup window. |
| 367 - (void)resetTrackingArea { | 420 - (void)resetTrackingArea { |
| 368 for (NSTrackingArea* trackingArea in [self trackingAreas]) { | 421 for (NSTrackingArea* trackingArea in [self trackingAreas]) { |
| 369 [self removeTrackingArea:trackingArea]; | 422 [self removeTrackingArea:trackingArea]; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 - (void)mouseEntered:(NSEvent*)theEvent { | 484 - (void)mouseEntered:(NSEvent*)theEvent { |
| 432 [self highlightRowUnder:theEvent]; | 485 [self highlightRowUnder:theEvent]; |
| 433 } | 486 } |
| 434 - (void)mouseMoved:(NSEvent*)theEvent { | 487 - (void)mouseMoved:(NSEvent*)theEvent { |
| 435 [self highlightRowUnder:theEvent]; | 488 [self highlightRowUnder:theEvent]; |
| 436 } | 489 } |
| 437 - (void)mouseExited:(NSEvent*)theEvent { | 490 - (void)mouseExited:(NSEvent*)theEvent { |
| 438 [self highlightRowAt:-1]; | 491 [self highlightRowAt:-1]; |
| 439 } | 492 } |
| 440 | 493 |
| 494 // This handles drawing the decorations of the rounded popup window, |
| 495 // calling on NSMatrix to draw the actual contents. |
| 496 - (void)drawRect:(NSRect)rect { |
| 497 // Background clear so we can round the corners. |
| 498 [[NSColor clearColor] set]; |
| 499 NSRectFill([self frame]); |
| 500 |
| 501 // The toolbar items we're mirroring for shape are inset slightly |
| 502 // for width. I don't know why, which is why I didn't make this a |
| 503 // constant, yet. The factor of 0.5 on both dimensions is to put |
| 504 // the stroke down the middle of the pixels. |
| 505 const NSRect border(NSInsetRect([self bounds], 1.5, 0.5)); |
| 506 NSBezierPath* path = |
| 507 [NSBezierPath bezierPathWithRoundedRect:border |
| 508 xRadius:kPopupRoundingRadius |
| 509 yRadius:kPopupRoundingRadius]; |
| 510 |
| 511 // Draw the matrix clipped to our border. |
| 512 [NSGraphicsContext saveGraphicsState]; |
| 513 [path addClip]; |
| 514 [super drawRect:rect]; |
| 515 [NSGraphicsContext restoreGraphicsState]; |
| 516 |
| 517 // Put a border over that. |
| 518 // TODO(shess): Theme the color? |
| 519 [[NSColor lightGrayColor] setStroke]; |
| 520 [path setLineWidth:1.0]; |
| 521 [path stroke]; |
| 522 } |
| 523 |
| 441 @end | 524 @end |
| 442 | 525 |
| 443 @implementation AutocompleteMatrixTarget | 526 @implementation AutocompleteMatrixTarget |
| 444 | 527 |
| 445 - initWithPopupView:(AutocompletePopupViewMac*)view { | 528 - initWithPopupView:(AutocompletePopupViewMac*)view { |
| 446 self = [super init]; | 529 self = [super init]; |
| 447 if (self) { | 530 if (self) { |
| 448 popup_view_ = view; | 531 popup_view_ = view; |
| 449 } | 532 } |
| 450 return self; | 533 return self; |
| 451 } | 534 } |
| 452 | 535 |
| 453 - (void)select:sender { | 536 - (void)select:sender { |
| 454 DCHECK(popup_view_); | 537 DCHECK(popup_view_); |
| 455 popup_view_->AcceptInput(); | 538 popup_view_->AcceptInput(); |
| 456 } | 539 } |
| 457 | 540 |
| 458 @end | 541 @end |
| OLD | NEW |