| 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 "app/gfx/canvas.h" | 9 #include "app/gfx/canvas.h" |
| 10 #include "app/gfx/text_elider.h" | 10 #include "app/gfx/text_elider.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 #include "grit/generated_resources.h" | 21 #include "grit/generated_resources.h" |
| 22 #include "grit/theme_resources.h" | 22 #include "grit/theme_resources.h" |
| 23 #include "net/base/net_util.h" | 23 #include "net/base/net_util.h" |
| 24 #include "third_party/skia/include/core/SkPaint.h" | 24 #include "third_party/skia/include/core/SkPaint.h" |
| 25 #include "third_party/skia/include/core/SkPath.h" | 25 #include "third_party/skia/include/core/SkPath.h" |
| 26 #include "third_party/skia/include/core/SkRect.h" | 26 #include "third_party/skia/include/core/SkRect.h" |
| 27 #include "views/controls/label.h" | 27 #include "views/controls/label.h" |
| 28 #include "views/widget/root_view.h" | 28 #include "views/widget/root_view.h" |
| 29 #include "views/widget/widget.h" | 29 #include "views/widget/widget.h" |
| 30 #if defined(OS_WIN) | 30 #if defined(OS_WIN) |
| 31 #include "views/controls/scrollbar/native_scroll_bar.h" | |
| 32 #include "views/widget/widget_win.h" | 31 #include "views/widget/widget_win.h" |
| 33 #endif | 32 #endif |
| 34 | 33 |
| 35 // The alpha and color of the bubble's shadow. | 34 // The alpha and color of the bubble's shadow. |
| 36 static const SkColor kShadowColor = SkColorSetARGB(30, 0, 0, 0); | 35 static const SkColor kShadowColor = SkColorSetARGB(30, 0, 0, 0); |
| 37 | 36 |
| 38 // The roundedness of the edges of our bubble. | 37 // The roundedness of the edges of our bubble. |
| 39 static const int kBubbleCornerRadius = 4; | 38 static const int kBubbleCornerRadius = 4; |
| 40 | 39 |
| 41 // How close the mouse can get to the infobubble before it starts sliding | 40 // How close the mouse can get to the infobubble before it starts sliding |
| 42 // off-screen. | 41 // off-screen. |
| 43 static const int kMousePadding = 20; | 42 static const int kMousePadding = 20; |
| 44 | 43 |
| 45 // The color of the text | 44 // The color of the text |
| 46 static const SkColor kTextColor = SkColorSetRGB(100, 100, 100); | 45 static const SkColor kTextColor = SkColorSetRGB(100, 100, 100); |
| 47 | 46 |
| 48 // The color of the highlight text | 47 // The color of the highlight text |
| 49 static const SkColor kTextHighlightColor = SkColorSetRGB(242, 250, 255); | 48 static const SkColor kTextHighlightColor = SkColorSetRGB(242, 250, 255); |
| 50 | 49 |
| 51 // The horizontal offset of the text within the status bubble, not including the | 50 // The horizontal offset of the text within the status bubble, not including the |
| 52 // outer shadow ring. | 51 // outer shadow ring. |
| 53 static const int kTextPositionX = 3; | 52 static const int kTextPositionX = 3; |
| 54 | 53 |
| 55 // The minimum horizontal space between the (right) end of the text and the edge | 54 // The minimum horizontal space between the (right) end of the text and the edge |
| 56 // of the status bubble, not including the outer shadow ring, or a 1 px gap we | 55 // of the status bubble, not including the outer shadow ring, or a 1 px gap we |
| 57 // leave so we can shift all the text by 1 px to produce a "highlight" effect. | 56 // leave so we can shit all the text by 1 px to produce a "highlight" effect. |
| 58 static const int kTextHorizPadding = 1; | 57 static const int kTextHorizPadding = 1; |
| 59 | 58 |
| 60 // Delays before we start hiding or showing the bubble after we receive a | 59 // Delays before we start hiding or showing the bubble after we receive a |
| 61 // show or hide request. | 60 // show or hide request. |
| 62 static const int kShowDelay = 80; | 61 static const int kShowDelay = 80; |
| 63 static const int kHideDelay = 250; | 62 static const int kHideDelay = 250; |
| 64 | 63 |
| 65 // How long each fade should last for. | 64 // How long each fade should last for. |
| 66 static const int kShowFadeDurationMS = 120; | 65 static const int kShowFadeDurationMS = 120; |
| 67 static const int kHideFadeDurationMS = 200; | 66 static const int kHideFadeDurationMS = 200; |
| 68 static const int kFramerate = 25; | 67 static const int kFramerate = 25; |
| 69 | 68 |
| 70 // How long each expansion step should take. | |
| 71 static const int kExpansionStepDurationMS = 150; | |
| 72 | |
| 73 // View ----------------------------------------------------------------------- | 69 // View ----------------------------------------------------------------------- |
| 74 // StatusView manages the display of the bubble, applying text changes and | 70 // StatusView manages the display of the bubble, applying text changes and |
| 75 // fading in or out the bubble as required. | 71 // fading in or out the bubble as required. |
| 76 class StatusBubbleViews::StatusView : public views::Label, | 72 class StatusBubbleViews::StatusView : public views::Label, |
| 77 public Animation, | 73 public Animation, |
| 78 public AnimationDelegate { | 74 public AnimationDelegate { |
| 79 public: | 75 public: |
| 80 StatusView(StatusBubble* status_bubble, views::Widget* popup, | 76 StatusView(StatusBubble* status_bubble, views::Widget* popup, |
| 81 ThemeProvider* theme_provider) | 77 ThemeProvider* theme_provider) |
| 82 : Animation(kFramerate, this), | 78 : Animation(kFramerate, this), |
| (...skipping 27 matching lines...) Expand all Loading... |
| 110 | 106 |
| 111 enum BubbleStyle { | 107 enum BubbleStyle { |
| 112 STYLE_BOTTOM, | 108 STYLE_BOTTOM, |
| 113 STYLE_FLOATING, | 109 STYLE_FLOATING, |
| 114 STYLE_STANDARD, | 110 STYLE_STANDARD, |
| 115 STYLE_STANDARD_RIGHT | 111 STYLE_STANDARD_RIGHT |
| 116 }; | 112 }; |
| 117 | 113 |
| 118 // Set the bubble text to a certain value, hides the bubble if text is | 114 // Set the bubble text to a certain value, hides the bubble if text is |
| 119 // an empty string. | 115 // an empty string. |
| 120 void SetTextAndAnimate(const std::wstring& text); | |
| 121 | |
| 122 // Set the bubble text to a certain value without triggering animation | |
| 123 // sequence. Called by the StatusViewExpander after bubble has been | |
| 124 // fully expanded. | |
| 125 void SetText(const std::wstring& text); | 116 void SetText(const std::wstring& text); |
| 126 | 117 |
| 127 BubbleStage GetState() const { return stage_; } | 118 BubbleStage GetState() const { return stage_; } |
| 128 | 119 |
| 129 void SetStyle(BubbleStyle style); | 120 void SetStyle(BubbleStyle style); |
| 130 | 121 |
| 131 BubbleStyle GetStyle() const { return style_; } | 122 BubbleStyle GetStyle() const { return style_; } |
| 132 | 123 |
| 133 // Show the bubble instantly. | 124 // Show the bubble instantly. |
| 134 void Show(); | 125 void Show(); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 // fade-in can easily turn into a fade out, opacity_start_ is sometimes | 171 // fade-in can easily turn into a fade out, opacity_start_ is sometimes |
| 181 // a value between 0 and 1. | 172 // a value between 0 and 1. |
| 182 double opacity_start_; | 173 double opacity_start_; |
| 183 double opacity_end_; | 174 double opacity_end_; |
| 184 | 175 |
| 185 // Holds the theme provider of the frame that created us. | 176 // Holds the theme provider of the frame that created us. |
| 186 ThemeProvider* theme_provider_; | 177 ThemeProvider* theme_provider_; |
| 187 }; | 178 }; |
| 188 | 179 |
| 189 void StatusBubbleViews::StatusView::SetText(const std::wstring& text) { | 180 void StatusBubbleViews::StatusView::SetText(const std::wstring& text) { |
| 190 text_ = text; | |
| 191 SchedulePaint(); | |
| 192 } | |
| 193 | |
| 194 void StatusBubbleViews::StatusView::SetTextAndAnimate( | |
| 195 const std::wstring& text) { | |
| 196 if (text.empty()) { | 181 if (text.empty()) { |
| 197 // The string was empty. | 182 // The string was empty. |
| 198 StartHiding(); | 183 StartHiding(); |
| 199 } else { | 184 } else { |
| 200 // We want to show the string. | 185 // We want to show the string. |
| 201 text_ = text; | 186 text_ = text; |
| 202 StartShowing(); | 187 StartShowing(); |
| 203 } | 188 } |
| 204 | 189 |
| 205 SchedulePaint(); | 190 SchedulePaint(); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 SchedulePaint(); | 310 SchedulePaint(); |
| 326 } | 311 } |
| 327 | 312 |
| 328 void StatusBubbleViews::StatusView::AnimateToState(double state) { | 313 void StatusBubbleViews::StatusView::AnimateToState(double state) { |
| 329 SetOpacity(GetCurrentOpacity()); | 314 SetOpacity(GetCurrentOpacity()); |
| 330 } | 315 } |
| 331 | 316 |
| 332 void StatusBubbleViews::StatusView::AnimationEnded( | 317 void StatusBubbleViews::StatusView::AnimationEnded( |
| 333 const Animation* animation) { | 318 const Animation* animation) { |
| 334 SetOpacity(opacity_end_); | 319 SetOpacity(opacity_end_); |
| 320 |
| 335 if (stage_ == BUBBLE_HIDING_FADE) { | 321 if (stage_ == BUBBLE_HIDING_FADE) { |
| 336 stage_ = BUBBLE_HIDDEN; | 322 stage_ = BUBBLE_HIDDEN; |
| 337 popup_->Hide(); | 323 popup_->Hide(); |
| 338 } else if (stage_ == BUBBLE_SHOWING_FADE) { | 324 } else if (stage_ == BUBBLE_SHOWING_FADE) { |
| 339 stage_ = BUBBLE_SHOWN; | 325 stage_ = BUBBLE_SHOWN; |
| 340 } | 326 } |
| 341 } | 327 } |
| 342 | 328 |
| 343 void StatusBubbleViews::StatusView::SetStyle(BubbleStyle style) { | 329 void StatusBubbleViews::StatusView::SetStyle(BubbleStyle style) { |
| 344 if (style_ != style) { | 330 if (style_ != style) { |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 | 446 |
| 461 canvas->DrawStringInt(text_, | 447 canvas->DrawStringInt(text_, |
| 462 views::Label::GetFont(), | 448 views::Label::GetFont(), |
| 463 kTextColor, | 449 kTextColor, |
| 464 body_bounds.x(), | 450 body_bounds.x(), |
| 465 body_bounds.y(), | 451 body_bounds.y(), |
| 466 body_bounds.width(), | 452 body_bounds.width(), |
| 467 body_bounds.height()); | 453 body_bounds.height()); |
| 468 } | 454 } |
| 469 | 455 |
| 470 | |
| 471 // StatusViewExpander --------------------------------------------------------- | |
| 472 // StatusViewExpander manages the expansion and contraction of the status | |
| 473 // bubble as it accommodates URL's too long to fit in the standard bubble. | |
| 474 // Changes are passed through to the StatusView to paint. | |
| 475 class StatusBubbleViews::StatusViewExpander : public Animation, | |
| 476 public AnimationDelegate { | |
| 477 public: | |
| 478 StatusViewExpander(StatusBubble* status_bubble, StatusView* status_view) | |
| 479 : Animation(kFramerate, this), | |
| 480 status_bubble_(status_bubble), | |
| 481 status_view_(status_view), | |
| 482 expansion_start_(0), | |
| 483 expansion_end_(0) { | |
| 484 } | |
| 485 | |
| 486 // Manage the expansion of the bubble. | |
| 487 void StartExpansion(std::wstring expanded_text, int current_width, | |
| 488 int expansion_end); | |
| 489 | |
| 490 // Set width of fully expanded bubble. | |
| 491 void SetExpandedWidth(int expanded_width); | |
| 492 | |
| 493 private: | |
| 494 // Animation functions. | |
| 495 int GetCurrentBubbleWidth(); | |
| 496 void SetBubbleWidth(int width); | |
| 497 void AnimateToState(double state); | |
| 498 void AnimationEnded(const Animation* animation); | |
| 499 | |
| 500 // We are changing the bounds and text of this view. | |
| 501 StatusView* status_view_; | |
| 502 | |
| 503 // Manager that owns us. | |
| 504 StatusBubble* status_bubble_; | |
| 505 | |
| 506 // The currently displayed text. | |
| 507 std::wstring text_; | |
| 508 | |
| 509 // Text elided to fit maximum possible status bar width. | |
| 510 std::wstring expanded_text_; | |
| 511 | |
| 512 // Widths at expansion start and end. | |
| 513 int expansion_start_; | |
| 514 int expansion_end_; | |
| 515 }; | |
| 516 | |
| 517 void StatusBubbleViews::StatusViewExpander::AnimateToState(double state) { | |
| 518 SetBubbleWidth(GetCurrentBubbleWidth()); | |
| 519 } | |
| 520 | |
| 521 void StatusBubbleViews::StatusViewExpander::AnimationEnded( | |
| 522 const Animation* animation) { | |
| 523 SetBubbleWidth(expansion_end_); | |
| 524 status_view_->SetText(expanded_text_); | |
| 525 } | |
| 526 | |
| 527 void StatusBubbleViews::StatusViewExpander::StartExpansion( | |
| 528 std::wstring expanded_text, int expansion_start, | |
| 529 int expansion_end) { | |
| 530 expanded_text_ = expanded_text; | |
| 531 expansion_start_ = expansion_start; | |
| 532 expansion_end_ = expansion_end; | |
| 533 SetDuration(kExpansionStepDurationMS); | |
| 534 Start(); | |
| 535 } | |
| 536 | |
| 537 int StatusBubbleViews::StatusViewExpander::GetCurrentBubbleWidth() { | |
| 538 return static_cast<int>(expansion_start_ + | |
| 539 (expansion_end_ - expansion_start_) * Animation::GetCurrentValue()); | |
| 540 } | |
| 541 | |
| 542 void StatusBubbleViews::StatusViewExpander::SetBubbleWidth(int width) { | |
| 543 status_bubble_->SetBubbleWidth(width); | |
| 544 status_view_->SchedulePaint(); | |
| 545 } | |
| 546 | |
| 547 // StatusBubble --------------------------------------------------------------- | 456 // StatusBubble --------------------------------------------------------------- |
| 548 | 457 |
| 549 const int StatusBubbleViews::kShadowThickness = 1; | 458 const int StatusBubbleViews::kShadowThickness = 1; |
| 550 | 459 |
| 551 StatusBubbleViews::StatusBubbleViews(views::Widget* frame) | 460 StatusBubbleViews::StatusBubbleViews(views::Widget* frame) |
| 552 : offset_(0), | 461 : offset_(0), |
| 553 popup_(NULL), | 462 popup_(NULL), |
| 554 opacity_(0), | 463 opacity_(0), |
| 555 frame_(frame), | 464 frame_(frame), |
| 556 view_(NULL), | 465 view_(NULL), |
| 557 download_shelf_is_visible_(false), | 466 download_shelf_is_visible_(false) { |
| 558 is_expanded_(false), | |
| 559 expand_timer_factory_(this) { | |
| 560 } | 467 } |
| 561 | 468 |
| 562 StatusBubbleViews::~StatusBubbleViews() { | 469 StatusBubbleViews::~StatusBubbleViews() { |
| 563 CancelExpandTimer(); | |
| 564 if (popup_.get()) | 470 if (popup_.get()) |
| 565 popup_->CloseNow(); | 471 popup_->CloseNow(); |
| 566 } | 472 } |
| 567 | 473 |
| 568 void StatusBubbleViews::Init() { | 474 void StatusBubbleViews::Init() { |
| 569 if (!popup_.get()) { | 475 if (!popup_.get()) { |
| 570 #if defined(OS_WIN) | 476 #if defined(OS_WIN) |
| 571 views::WidgetWin* popup = new views::WidgetWin; | 477 views::WidgetWin* popup = new views::WidgetWin; |
| 572 popup->set_delete_on_destroy(false); | 478 popup->set_delete_on_destroy(false); |
| 573 | 479 |
| 574 if (!view_) | 480 if (!view_) |
| 575 view_ = new StatusView(this, popup, frame_->GetThemeProvider()); | 481 view_ = new StatusView(this, popup, frame_->GetThemeProvider()); |
| 576 if (!expand_view_) | |
| 577 expand_view_ = new StatusViewExpander(this, view_); | |
| 578 | 482 |
| 579 popup->set_window_style(WS_POPUP); | 483 popup->set_window_style(WS_POPUP); |
| 580 popup->set_window_ex_style(WS_EX_LAYERED | WS_EX_TOOLWINDOW | | 484 popup->set_window_ex_style(WS_EX_LAYERED | WS_EX_TOOLWINDOW | |
| 581 WS_EX_TRANSPARENT | | 485 WS_EX_TRANSPARENT | |
| 582 l10n_util::GetExtendedTooltipStyles()); | 486 l10n_util::GetExtendedTooltipStyles()); |
| 583 popup->SetOpacity(0x00); | 487 popup->SetOpacity(0x00); |
| 584 popup->Init(frame_->GetNativeView(), gfx::Rect()); | 488 popup->Init(frame_->GetNativeView(), gfx::Rect()); |
| 585 popup->SetContentsView(view_); | 489 popup->SetContentsView(view_); |
| 586 Reposition(); | 490 Reposition(); |
| 587 popup->Show(); | 491 popup->Show(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 624 Reposition(); | 528 Reposition(); |
| 625 } | 529 } |
| 626 | 530 |
| 627 void StatusBubbleViews::SetStatus(const std::wstring& status_text) { | 531 void StatusBubbleViews::SetStatus(const std::wstring& status_text) { |
| 628 if (status_text_ == status_text) | 532 if (status_text_ == status_text) |
| 629 return; | 533 return; |
| 630 | 534 |
| 631 Init(); | 535 Init(); |
| 632 status_text_ = status_text; | 536 status_text_ = status_text; |
| 633 if (!status_text_.empty()) { | 537 if (!status_text_.empty()) { |
| 634 view_->SetTextAndAnimate(status_text); | 538 view_->SetText(status_text); |
| 635 view_->Show(); | 539 view_->Show(); |
| 636 } else if (!url_text_.empty()) { | 540 } else if (!url_text_.empty()) { |
| 637 view_->SetTextAndAnimate(url_text_); | 541 view_->SetText(url_text_); |
| 638 } else { | 542 } else { |
| 639 view_->SetTextAndAnimate(std::wstring()); | 543 view_->SetText(std::wstring()); |
| 640 } | 544 } |
| 641 } | 545 } |
| 642 | 546 |
| 643 void StatusBubbleViews::SetURL(const GURL& url, const std::wstring& languages) { | 547 void StatusBubbleViews::SetURL(const GURL& url, const std::wstring& languages) { |
| 644 languages_ = languages; | |
| 645 url_ = url; | |
| 646 Init(); | 548 Init(); |
| 647 | 549 |
| 648 // If we want to clear a displayed URL but there is a status still to | 550 // If we want to clear a displayed URL but there is a status still to |
| 649 // display, display that status instead. | 551 // display, display that status instead. |
| 650 if (url.is_empty() && !status_text_.empty()) { | 552 if (url.is_empty() && !status_text_.empty()) { |
| 651 url_text_ = std::wstring(); | 553 url_text_ = std::wstring(); |
| 652 view_->SetTextAndAnimate(status_text_); | 554 view_->SetText(status_text_); |
| 653 return; | 555 return; |
| 654 } | 556 } |
| 655 | 557 |
| 656 // Reset expansion state only when bubble is completely hidden. | |
| 657 if (view_->GetState() == StatusView::BUBBLE_HIDDEN) { | |
| 658 is_expanded_ = false; | |
| 659 SetBubbleWidth(GetStandardStatusBubbleWidth()); | |
| 660 } | |
| 661 | |
| 662 // Set Elided Text corresponding to the GURL object. | 558 // Set Elided Text corresponding to the GURL object. |
| 663 gfx::Rect popup_bounds; | 559 gfx::Rect popup_bounds; |
| 664 popup_->GetBounds(&popup_bounds, true); | 560 popup_->GetBounds(&popup_bounds, true); |
| 665 int text_width = static_cast<int>(popup_bounds.width() - | 561 int text_width = static_cast<int>(popup_bounds.width() - |
| 666 (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1); | 562 (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1); |
| 667 url_text_ = gfx::ElideUrl(url, view_->Label::GetFont(), text_width, | 563 url_text_ = gfx::ElideUrl(url, view_->Label::GetFont(), text_width, |
| 668 languages); | 564 languages); |
| 669 | 565 |
| 670 url_parse::Parsed parsed; | |
| 671 std::wstring original_url_text_ = | |
| 672 net::FormatUrl(url, languages, true, true, &parsed, NULL); | |
| 673 | |
| 674 // An URL is always treated as a left-to-right string. On right-to-left UIs | 566 // An URL is always treated as a left-to-right string. On right-to-left UIs |
| 675 // we need to explicitly mark the URL as LTR to make sure it is displayed | 567 // we need to explicitly mark the URL as LTR to make sure it is displayed |
| 676 // correctly. | 568 // correctly. |
| 677 if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT && | 569 if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT && |
| 678 !url_text_.empty()) | 570 !url_text_.empty()) |
| 679 l10n_util::WrapStringWithLTRFormatting(&url_text_); | 571 l10n_util::WrapStringWithLTRFormatting(&url_text_); |
| 680 | 572 view_->SetText(url_text_); |
| 681 view_->SetTextAndAnimate(url_text_); | |
| 682 | |
| 683 CancelExpandTimer(); | |
| 684 | |
| 685 // If bubble is already in expanded state, shift immediately to adjust to | |
| 686 // new text size (shrinking or expanding). Otherwise delay for | |
| 687 // kExpandHoverDelay ms. | |
| 688 if (is_expanded_ && !url.is_empty()) | |
| 689 ExpandBubble(); | |
| 690 else if (original_url_text_.length() > url_text_.length()) | |
| 691 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
| 692 expand_timer_factory_.NewRunnableMethod( | |
| 693 &StatusBubbleViews::ExpandBubble), kExpandHoverDelay); | |
| 694 } | 573 } |
| 695 | 574 |
| 696 void StatusBubbleViews::Hide() { | 575 void StatusBubbleViews::Hide() { |
| 697 status_text_ = std::wstring(); | 576 status_text_ = std::wstring(); |
| 698 url_text_ = std::wstring(); | 577 url_text_ = std::wstring(); |
| 699 if (view_) | 578 if (view_) |
| 700 view_->Hide(); | 579 view_->Hide(); |
| 701 } | 580 } |
| 702 | 581 |
| 703 void StatusBubbleViews::MouseMoved() { | 582 void StatusBubbleViews::MouseMoved() { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 789 const int bubble_bottom_y = top_left.y() + position_.y() + size_.height(); | 668 const int bubble_bottom_y = top_left.y() + position_.y() + size_.height(); |
| 790 | 669 |
| 791 if (bubble_bottom_y + offset > monitor_rect.height() || | 670 if (bubble_bottom_y + offset > monitor_rect.height() || |
| 792 (download_shelf_is_visible_ && | 671 (download_shelf_is_visible_ && |
| 793 view_->GetStyle() == StatusView::STYLE_FLOATING)) { | 672 view_->GetStyle() == StatusView::STYLE_FLOATING)) { |
| 794 // The offset is still too large. Move the bubble to the right and reset | 673 // The offset is still too large. Move the bubble to the right and reset |
| 795 // Y offset_ to zero. | 674 // Y offset_ to zero. |
| 796 view_->SetStyle(StatusView::STYLE_STANDARD_RIGHT); | 675 view_->SetStyle(StatusView::STYLE_STANDARD_RIGHT); |
| 797 offset_ = 0; | 676 offset_ = 0; |
| 798 | 677 |
| 799 // Subtract border width + bubble width. | 678 // Substract border width + bubble width. |
| 800 int right_position_x = window_width - (position_.x() + size_.width()); | 679 int right_position_x = window_width - (position_.x() + size_.width()); |
| 801 popup_->SetBounds(gfx::Rect(top_left.x() + right_position_x, | 680 popup_->SetBounds(gfx::Rect(top_left.x() + right_position_x, |
| 802 top_left.y() + position_.y(), | 681 top_left.y() + position_.y(), |
| 803 size_.width(), size_.height())); | 682 size_.width(), size_.height())); |
| 804 } else { | 683 } else { |
| 805 offset_ = offset; | 684 offset_ = offset; |
| 806 popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), | 685 popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), |
| 807 top_left.y() + position_.y() + offset_, | 686 top_left.y() + position_.y() + offset_, |
| 808 size_.width(), size_.height())); | 687 size_.width(), size_.height())); |
| 809 } | 688 } |
| 810 } else if (offset_ != 0 || | 689 } else if (offset_ != 0 || |
| 811 view_->GetStyle() == StatusView::STYLE_STANDARD_RIGHT) { | 690 view_->GetStyle() == StatusView::STYLE_STANDARD_RIGHT) { |
| 812 offset_ = 0; | 691 offset_ = 0; |
| 813 view_->SetStyle(StatusView::STYLE_STANDARD); | 692 view_->SetStyle(StatusView::STYLE_STANDARD); |
| 814 popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), | 693 popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), |
| 815 top_left.y() + position_.y(), | 694 top_left.y() + position_.y(), |
| 816 size_.width(), size_.height())); | 695 size_.width(), size_.height())); |
| 817 } | 696 } |
| 818 } | 697 } |
| 819 | |
| 820 void StatusBubbleViews::ExpandBubble() { | |
| 821 // Elide url to maximum possible size, then check actual length (it may | |
| 822 // still be too long to fit) before expanding bubble. | |
| 823 gfx::Rect popup_bounds; | |
| 824 popup_->GetBounds(&popup_bounds, true); | |
| 825 int max_status_bubble_width = GetMaxStatusBubbleWidth(); | |
| 826 url_text_ = gfx::ElideUrl(url_, view_->Label::GetFont(), | |
| 827 max_status_bubble_width, languages_); | |
| 828 int expanded_bubble_width = | |
| 829 std::max(GetStandardStatusBubbleWidth(), | |
| 830 std::min(view_->Label::GetFont().GetStringWidth(url_text_) + | |
| 831 (kShadowThickness * 2) + kTextPositionX + kTextHorizPadding + 1, | |
| 832 max_status_bubble_width)); | |
| 833 is_expanded_ = true; | |
| 834 expand_view_->StartExpansion(url_text_, popup_bounds.width(), | |
| 835 expanded_bubble_width); | |
| 836 } | |
| 837 | |
| 838 int StatusBubbleViews::GetStandardStatusBubbleWidth() { | |
| 839 gfx::Rect frame_bounds; | |
| 840 frame_->GetBounds(&frame_bounds, false); | |
| 841 return frame_bounds.width() / 3; | |
| 842 } | |
| 843 | |
| 844 int StatusBubbleViews::GetMaxStatusBubbleWidth() { | |
| 845 gfx::Rect frame_bounds; | |
| 846 frame_->GetBounds(&frame_bounds, false); | |
| 847 return static_cast<int>(frame_bounds.width() - (kShadowThickness * 2) - | |
| 848 kTextPositionX - kTextHorizPadding - 1 - | |
| 849 views::NativeScrollBar::GetVerticalScrollBarWidth()); | |
| 850 } | |
| 851 | |
| 852 void StatusBubbleViews::SetBubbleWidth(int width) { | |
| 853 size_.set_width(width); | |
| 854 SetBounds(position_.x(), position_.y(), size_.width(), size_.height()); | |
| 855 } | |
| 856 | |
| 857 void StatusBubbleViews::CancelExpandTimer() { | |
| 858 if (!expand_timer_factory_.empty()) | |
| 859 expand_timer_factory_.RevokeAll(); | |
| 860 } | |
| 861 | |
| OLD | NEW |