| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/views/status_bubble_views.h" | 5 #include "chrome/browser/views/status_bubble_views.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "chrome/common/animation.h" | 10 #include "chrome/common/animation.h" |
| 11 #include "chrome/common/gfx/chrome_canvas.h" | 11 #include "chrome/common/gfx/chrome_canvas.h" |
| 12 #include "chrome/common/gfx/text_elider.h" | 12 #include "chrome/common/gfx/text_elider.h" |
| 13 #include "chrome/common/l10n_util.h" | 13 #include "chrome/common/l10n_util.h" |
| 14 #include "chrome/common/l10n_util_win.h" | 14 #include "chrome/common/l10n_util_win.h" |
| 15 #include "chrome/common/resource_bundle.h" | 15 #include "chrome/common/resource_bundle.h" |
| 16 #include "chrome/views/controls/label.h" | 16 #include "chrome/views/controls/label.h" |
| 17 #include "chrome/views/widget/root_view.h" | 17 #include "chrome/views/widget/root_view.h" |
| 18 #include "chrome/views/widget/widget_win.h" | 18 #include "chrome/views/widget/widget_win.h" |
| 19 #include "googleurl/src/gurl.h" | 19 #include "googleurl/src/gurl.h" |
| 20 #include "grit/generated_resources.h" | 20 #include "grit/generated_resources.h" |
| 21 #include "grit/theme_resources.h" | 21 #include "grit/theme_resources.h" |
| 22 #include "net/base/net_util.h" | 22 #include "net/base/net_util.h" |
| 23 #include "SkPaint.h" | 23 #include "SkPaint.h" |
| 24 #include "SkPath.h" | 24 #include "SkPath.h" |
| 25 #include "SkRect.h" | 25 #include "SkRect.h" |
| 26 | 26 |
| 27 // The color of the background bubble. | 27 // The color of the background bubble. |
| 28 static const SkColor kBubbleColor = SkColorSetRGB(222, 234, 248); | 28 static const SkColor kBubbleColor = SkColorSetRGB(222, 234, 248); |
| 29 | 29 |
| 30 // The alpha and color of the bubble's shadow. This is a composite of the above | 30 // The alpha and color of the bubble's shadow. |
| 31 // background color with 30% gray. | 31 static const SkColor kShadowColor = SkColorSetARGB(30, 0, 0, 0); |
| 32 static const SkColor kShadowColor = SkColorSetRGB(196, 206, 212); | |
| 33 | |
| 34 // How wide the bubble's shadow is. | |
| 35 static const int kShadowSize = 1; | |
| 36 | 32 |
| 37 // The roundedness of the edges of our bubble. | 33 // The roundedness of the edges of our bubble. |
| 38 static const int kBubbleCornerRadius = 4; | 34 static const int kBubbleCornerRadius = 4; |
| 39 | 35 |
| 40 // How close the mouse can get to the infobubble before it starts sliding | 36 // How close the mouse can get to the infobubble before it starts sliding |
| 41 // off-screen. | 37 // off-screen. |
| 42 static const int kMousePadding = 20; | 38 static const int kMousePadding = 20; |
| 43 | 39 |
| 44 // The color of the text | 40 // The color of the text |
| 45 static const SkColor kTextColor = SkColorSetRGB(100, 100, 100); | 41 static const SkColor kTextColor = SkColorSetRGB(100, 100, 100); |
| 46 | 42 |
| 47 // The color of the highlight text | 43 // The color of the highlight text |
| 48 static const SkColor kTextHighlightColor = SkColorSetRGB(242, 250, 255); | 44 static const SkColor kTextHighlightColor = SkColorSetRGB(242, 250, 255); |
| 49 | 45 |
| 50 static const int kTextPadding = 3; | 46 // The horizontal offset of the text within the status bubble, not including the |
| 51 static const int kTextPositionX = 4; | 47 // outer shadow ring. |
| 52 static const int kTextPositionY = 1; | 48 static const int kTextPositionX = 3; |
| 49 |
| 50 // The minimum horizontal space between the (right) end of the text and the edge |
| 51 // of the status bubble, not including the outer shadow ring, or a 1 px gap we |
| 52 // leave so we can shit all the text by 1 px to produce a "highlight" effect. |
| 53 static const int kTextHorizPadding = 1; |
| 53 | 54 |
| 54 // Delays before we start hiding or showing the bubble after we receive a | 55 // Delays before we start hiding or showing the bubble after we receive a |
| 55 // show or hide request. | 56 // show or hide request. |
| 56 static const int kShowDelay = 80; | 57 static const int kShowDelay = 80; |
| 57 static const int kHideDelay = 250; | 58 static const int kHideDelay = 250; |
| 58 | 59 |
| 59 // How long each fade should last for. | 60 // How long each fade should last for. |
| 60 static const int kShowFadeDurationMS = 120; | 61 static const int kShowFadeDurationMS = 120; |
| 61 static const int kHideFadeDurationMS = 200; | 62 static const int kHideFadeDurationMS = 200; |
| 62 static const int kFramerate = 25; | 63 static const int kFramerate = 25; |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 | 320 |
| 320 void StatusBubbleViews::StatusView::Paint(ChromeCanvas* canvas) { | 321 void StatusBubbleViews::StatusView::Paint(ChromeCanvas* canvas) { |
| 321 SkPaint paint; | 322 SkPaint paint; |
| 322 paint.setStyle(SkPaint::kFill_Style); | 323 paint.setStyle(SkPaint::kFill_Style); |
| 323 paint.setFlags(SkPaint::kAntiAlias_Flag); | 324 paint.setFlags(SkPaint::kAntiAlias_Flag); |
| 324 paint.setColor(kBubbleColor); | 325 paint.setColor(kBubbleColor); |
| 325 | 326 |
| 326 RECT parent_rect; | 327 RECT parent_rect; |
| 327 ::GetWindowRect(popup_->GetNativeView(), &parent_rect); | 328 ::GetWindowRect(popup_->GetNativeView(), &parent_rect); |
| 328 | 329 |
| 329 // Draw our background. | |
| 330 SkRect rect; | |
| 331 int width = parent_rect.right - parent_rect.left; | |
| 332 int height = parent_rect.bottom - parent_rect.top; | |
| 333 | |
| 334 // Figure out how to round the bubble's four corners. | 330 // Figure out how to round the bubble's four corners. |
| 335 SkScalar rad[8]; | 331 SkScalar rad[8]; |
| 336 | 332 |
| 337 // Top Edges - if the bubble is in its bottom position (sticking downwards), | 333 // Top Edges - if the bubble is in its bottom position (sticking downwards), |
| 338 // then we square the top edges. Otherwise, we square the edges based on the | 334 // then we square the top edges. Otherwise, we square the edges based on the |
| 339 // position of the bubble within the window (the bubble is positioned in the | 335 // position of the bubble within the window (the bubble is positioned in the |
| 340 // southeast corner in RTL and in the southwest corner in LTR). | 336 // southeast corner in RTL and in the southwest corner in LTR). |
| 341 if (style_ == STYLE_BOTTOM) { | 337 if (style_ == STYLE_BOTTOM) { |
| 342 // Top Left corner. | 338 // Top Left corner. |
| 343 rad[0] = 0; | 339 rad[0] = 0; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 // Bottom Right Corner. | 376 // Bottom Right Corner. |
| 381 rad[4] = SkIntToScalar(kBubbleCornerRadius); | 377 rad[4] = SkIntToScalar(kBubbleCornerRadius); |
| 382 rad[5] = SkIntToScalar(kBubbleCornerRadius); | 378 rad[5] = SkIntToScalar(kBubbleCornerRadius); |
| 383 | 379 |
| 384 // Bottom Left Corner. | 380 // Bottom Left Corner. |
| 385 rad[6] = SkIntToScalar(kBubbleCornerRadius); | 381 rad[6] = SkIntToScalar(kBubbleCornerRadius); |
| 386 rad[7] = SkIntToScalar(kBubbleCornerRadius); | 382 rad[7] = SkIntToScalar(kBubbleCornerRadius); |
| 387 } | 383 } |
| 388 | 384 |
| 389 // Draw the bubble's shadow. | 385 // Draw the bubble's shadow. |
| 386 int width = parent_rect.right - parent_rect.left; |
| 387 int height = parent_rect.bottom - parent_rect.top; |
| 388 SkRect rect; |
| 389 rect.set(0, 0, |
| 390 SkIntToScalar(width), |
| 391 SkIntToScalar(height)); |
| 392 SkPath shadow_path; |
| 393 shadow_path.addRoundRect(rect, rad, SkPath::kCW_Direction); |
| 390 SkPaint shadow_paint; | 394 SkPaint shadow_paint; |
| 391 shadow_paint.setFlags(SkPaint::kAntiAlias_Flag); | 395 shadow_paint.setFlags(SkPaint::kAntiAlias_Flag); |
| 392 shadow_paint.setColor(kShadowColor); | 396 shadow_paint.setColor(kShadowColor); |
| 393 | |
| 394 rect.set(0, 0, | |
| 395 SkIntToScalar(width), | |
| 396 SkIntToScalar(height)); | |
| 397 | |
| 398 SkPath shadow_path; | |
| 399 shadow_path.addRoundRect(rect, rad, SkPath::kCW_Direction); | |
| 400 canvas->drawPath(shadow_path, shadow_paint); | 397 canvas->drawPath(shadow_path, shadow_paint); |
| 401 | 398 |
| 402 // Draw the bubble. | 399 // Draw the bubble. |
| 400 rect.set(SkIntToScalar(kShadowThickness), |
| 401 SkIntToScalar(kShadowThickness), |
| 402 SkIntToScalar(width - kShadowThickness), |
| 403 SkIntToScalar(height - kShadowThickness)); |
| 403 SkPath path; | 404 SkPath path; |
| 404 rect.set(SkIntToScalar(kShadowSize), | |
| 405 SkIntToScalar(kShadowSize), | |
| 406 SkIntToScalar(width - kShadowSize), | |
| 407 SkIntToScalar(height - kShadowSize)); | |
| 408 | |
| 409 path.addRoundRect(rect, rad, SkPath::kCW_Direction); | 405 path.addRoundRect(rect, rad, SkPath::kCW_Direction); |
| 410 canvas->drawPath(path, paint); | 406 canvas->drawPath(path, paint); |
| 411 | 407 |
| 412 | |
| 413 int text_width = std::min(static_cast<int>(parent_rect.right - | |
| 414 parent_rect.left - kTextPositionX - | |
| 415 kTextPadding), | |
| 416 static_cast<int>(views::Label::GetFont() | |
| 417 .GetStringWidth(text_))); | |
| 418 | |
| 419 // Draw highlight text and then the text body. In order to make sure the text | 408 // Draw highlight text and then the text body. In order to make sure the text |
| 420 // is aligned to the right on RTL UIs, we mirror the text bounds if the | 409 // is aligned to the right on RTL UIs, we mirror the text bounds if the |
| 421 // locale is RTL. | 410 // locale is RTL. |
| 422 gfx::Rect body_bounds(kTextPositionX, | 411 // The "- 1" on the end of the width and height ensures that when we add one |
| 423 kTextPositionY, | 412 // to x() and y() for the highlight text, we still won't overlap the shadow. |
| 413 int text_width = std::min(views::Label::GetFont().GetStringWidth(text_), |
| 414 width - (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1); |
| 415 gfx::Rect body_bounds(kShadowThickness + kTextPositionX, |
| 416 kShadowThickness, |
| 424 text_width, | 417 text_width, |
| 425 parent_rect.bottom - parent_rect.top); | 418 height - (kShadowThickness * 2) - 1); |
| 426 body_bounds.set_x(MirroredLeftPointForRect(body_bounds)); | 419 body_bounds.set_x(MirroredLeftPointForRect(body_bounds)); |
| 427 canvas->DrawStringInt(text_, | 420 canvas->DrawStringInt(text_, |
| 428 views::Label::GetFont(), | 421 views::Label::GetFont(), |
| 429 kTextHighlightColor, | 422 kTextHighlightColor, |
| 430 body_bounds.x() + 1, | 423 body_bounds.x() + 1, |
| 431 body_bounds.y() + 1, | 424 body_bounds.y() + 1, |
| 432 body_bounds.width(), | 425 body_bounds.width(), |
| 433 body_bounds.height()); | 426 body_bounds.height()); |
| 434 | 427 |
| 435 canvas->DrawStringInt(text_, | 428 canvas->DrawStringInt(text_, |
| 436 views::Label::GetFont(), | 429 views::Label::GetFont(), |
| 437 kTextColor, | 430 kTextColor, |
| 438 body_bounds.x(), | 431 body_bounds.x(), |
| 439 body_bounds.y(), | 432 body_bounds.y(), |
| 440 body_bounds.width(), | 433 body_bounds.width(), |
| 441 body_bounds.height()); | 434 body_bounds.height()); |
| 442 } | 435 } |
| 443 | 436 |
| 444 // StatusBubble --------------------------------------------------------------- | 437 // StatusBubble --------------------------------------------------------------- |
| 445 | 438 |
| 439 const int StatusBubbleViews::kShadowThickness = 1; |
| 440 |
| 446 StatusBubbleViews::StatusBubbleViews(views::Widget* frame) | 441 StatusBubbleViews::StatusBubbleViews(views::Widget* frame) |
| 447 : popup_(NULL), | 442 : popup_(NULL), |
| 448 frame_(frame), | 443 frame_(frame), |
| 449 view_(NULL), | 444 view_(NULL), |
| 450 opacity_(0), | 445 opacity_(0), |
| 451 position_(0, 0), | 446 position_(0, 0), |
| 452 size_(0, 0), | 447 size_(0, 0), |
| 453 offset_(0) { | 448 offset_(0) { |
| 454 } | 449 } |
| 455 | 450 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 // display, display that status instead. | 501 // display, display that status instead. |
| 507 if (url.is_empty() && !status_text_.empty()) { | 502 if (url.is_empty() && !status_text_.empty()) { |
| 508 url_text_ = std::wstring(); | 503 url_text_ = std::wstring(); |
| 509 view_->SetText(status_text_); | 504 view_->SetText(status_text_); |
| 510 return; | 505 return; |
| 511 } | 506 } |
| 512 | 507 |
| 513 // Set Elided Text corresponding to the GURL object. | 508 // Set Elided Text corresponding to the GURL object. |
| 514 RECT parent_rect; | 509 RECT parent_rect; |
| 515 ::GetWindowRect(popup_->GetNativeView(), &parent_rect); | 510 ::GetWindowRect(popup_->GetNativeView(), &parent_rect); |
| 516 int text_width = static_cast<int>(parent_rect.right - | 511 int text_width = static_cast<int>(parent_rect.right - parent_rect.left - |
| 517 parent_rect.left - kTextPositionX - | 512 (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1); |
| 518 kTextPadding); | |
| 519 url_text_ = gfx::ElideUrl(url, view_->Label::GetFont(), text_width, | 513 url_text_ = gfx::ElideUrl(url, view_->Label::GetFont(), text_width, |
| 520 languages); | 514 languages); |
| 521 | 515 |
| 522 // An URL is always treated as a left-to-right string. On right-to-left UIs | 516 // An URL is always treated as a left-to-right string. On right-to-left UIs |
| 523 // we need to explicitly mark the URL as LTR to make sure it is displayed | 517 // we need to explicitly mark the URL as LTR to make sure it is displayed |
| 524 // correctly. | 518 // correctly. |
| 525 if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT && | 519 if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT && |
| 526 !url_text_.empty()) | 520 !url_text_.empty()) |
| 527 l10n_util::WrapStringWithLTRFormatting(&url_text_); | 521 l10n_util::WrapStringWithLTRFormatting(&url_text_); |
| 528 view_->SetText(url_text_); | 522 view_->SetText(url_text_); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 if (cursor_location.x > size_.cx) { | 570 if (cursor_location.x > size_.cx) { |
| 577 offset = static_cast<int>(static_cast<float>(offset) * ( | 571 offset = static_cast<int>(static_cast<float>(offset) * ( |
| 578 static_cast<float>(kMousePadding - | 572 static_cast<float>(kMousePadding - |
| 579 (cursor_location.x - size_.cx)) / | 573 (cursor_location.x - size_.cx)) / |
| 580 static_cast<float>(kMousePadding))); | 574 static_cast<float>(kMousePadding))); |
| 581 } | 575 } |
| 582 | 576 |
| 583 // Cap the offset and change the visual presentation of the bubble | 577 // Cap the offset and change the visual presentation of the bubble |
| 584 // depending on where it ends up (so that rounded corners square off | 578 // depending on where it ends up (so that rounded corners square off |
| 585 // and mate to the edges of the tab content). | 579 // and mate to the edges of the tab content). |
| 586 if (offset >= size_.cy - kShadowSize * 2) { | 580 if (offset >= size_.cy - kShadowThickness * 2) { |
| 587 offset = size_.cy - kShadowSize * 2; | 581 offset = size_.cy - kShadowThickness * 2; |
| 588 view_->SetStyle(StatusView::STYLE_BOTTOM); | 582 view_->SetStyle(StatusView::STYLE_BOTTOM); |
| 589 } else if (offset > kBubbleCornerRadius / 2 - kShadowSize) { | 583 } else if (offset > kBubbleCornerRadius / 2 - kShadowThickness) { |
| 590 view_->SetStyle(StatusView::STYLE_FLOATING); | 584 view_->SetStyle(StatusView::STYLE_FLOATING); |
| 591 } else { | 585 } else { |
| 592 view_->SetStyle(StatusView::STYLE_STANDARD); | 586 view_->SetStyle(StatusView::STYLE_STANDARD); |
| 593 } | 587 } |
| 594 | 588 |
| 595 offset_ = offset; | 589 offset_ = offset; |
| 596 popup_->MoveWindow(top_left.x() + position_.x, | 590 popup_->MoveWindow(top_left.x() + position_.x, |
| 597 top_left.y() + position_.y + offset_, | 591 top_left.y() + position_.y + offset_, |
| 598 size_.cx, | 592 size_.cx, |
| 599 size_.cy); | 593 size_.cy); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 627 frame_->GetBounds(&frame_bounds, false); | 621 frame_->GetBounds(&frame_bounds, false); |
| 628 int mirrored_x = frame_bounds.width() - x - w; | 622 int mirrored_x = frame_bounds.width() - x - w; |
| 629 position_.SetPoint(mirrored_x, y); | 623 position_.SetPoint(mirrored_x, y); |
| 630 } else { | 624 } else { |
| 631 position_.SetPoint(x, y); | 625 position_.SetPoint(x, y); |
| 632 } | 626 } |
| 633 | 627 |
| 634 size_.SetSize(w, h); | 628 size_.SetSize(w, h); |
| 635 Reposition(); | 629 Reposition(); |
| 636 } | 630 } |
| OLD | NEW |