| 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" |
| 31 #include "views/widget/widget_win.h" | 32 #include "views/widget/widget_win.h" |
| 32 #endif | 33 #endif |
| 33 | 34 |
| 34 // The alpha and color of the bubble's shadow. | 35 // The alpha and color of the bubble's shadow. |
| 35 static const SkColor kShadowColor = SkColorSetARGB(30, 0, 0, 0); | 36 static const SkColor kShadowColor = SkColorSetARGB(30, 0, 0, 0); |
| 36 | 37 |
| 37 // The roundedness of the edges of our bubble. | 38 // The roundedness of the edges of our bubble. |
| 38 static const int kBubbleCornerRadius = 4; | 39 static const int kBubbleCornerRadius = 4; |
| 39 | 40 |
| 40 // How close the mouse can get to the infobubble before it starts sliding | 41 // How close the mouse can get to the infobubble before it starts sliding |
| 41 // off-screen. | 42 // off-screen. |
| 42 static const int kMousePadding = 20; | 43 static const int kMousePadding = 20; |
| 43 | 44 |
| 44 // The color of the text | 45 // The color of the text |
| 45 static const SkColor kTextColor = SkColorSetRGB(100, 100, 100); | 46 static const SkColor kTextColor = SkColorSetRGB(100, 100, 100); |
| 46 | 47 |
| 47 // The color of the highlight text | 48 // The color of the highlight text |
| 48 static const SkColor kTextHighlightColor = SkColorSetRGB(242, 250, 255); | 49 static const SkColor kTextHighlightColor = SkColorSetRGB(242, 250, 255); |
| 49 | 50 |
| 50 // The horizontal offset of the text within the status bubble, not including the | 51 // The horizontal offset of the text within the status bubble, not including the |
| 51 // outer shadow ring. | 52 // outer shadow ring. |
| 52 static const int kTextPositionX = 3; | 53 static const int kTextPositionX = 3; |
| 53 | 54 |
| 54 // The minimum horizontal space between the (right) end of the text and the edge | 55 // The minimum horizontal space between the (right) end of the text and the edge |
| 55 // of the status bubble, not including the outer shadow ring, or a 1 px gap we | 56 // of the status bubble, not including the outer shadow ring, or a 1 px gap we |
| 56 // leave so we can shit all the text by 1 px to produce a "highlight" effect. | 57 // leave so we can shift all the text by 1 px to produce a "highlight" effect. |
| 57 static const int kTextHorizPadding = 1; | 58 static const int kTextHorizPadding = 1; |
| 58 | 59 |
| 59 // Delays before we start hiding or showing the bubble after we receive a | 60 // Delays before we start hiding or showing the bubble after we receive a |
| 60 // show or hide request. | 61 // show or hide request. |
| 61 static const int kShowDelay = 80; | 62 static const int kShowDelay = 80; |
| 62 static const int kHideDelay = 250; | 63 static const int kHideDelay = 250; |
| 63 | 64 |
| 64 // How long each fade should last for. | 65 // How long each fade should last for. |
| 65 static const int kShowFadeDurationMS = 120; | 66 static const int kShowFadeDurationMS = 120; |
| 66 static const int kHideFadeDurationMS = 200; | 67 static const int kHideFadeDurationMS = 200; |
| 67 static const int kFramerate = 25; | 68 static const int kFramerate = 25; |
| 68 | 69 |
| 70 // How long each expansion step should take. |
| 71 static const int kExpansionStepDurationMS = 150; |
| 72 |
| 69 // View ----------------------------------------------------------------------- | 73 // View ----------------------------------------------------------------------- |
| 70 // StatusView manages the display of the bubble, applying text changes and | 74 // StatusView manages the display of the bubble, applying text changes and |
| 71 // fading in or out the bubble as required. | 75 // fading in or out the bubble as required. |
| 72 class StatusBubbleViews::StatusView : public views::Label, | 76 class StatusBubbleViews::StatusView : public views::Label, |
| 73 public Animation, | 77 public Animation, |
| 74 public AnimationDelegate { | 78 public AnimationDelegate { |
| 75 public: | 79 public: |
| 76 StatusView(StatusBubble* status_bubble, views::Widget* popup, | 80 StatusView(StatusBubble* status_bubble, views::Widget* popup, |
| 77 ThemeProvider* theme_provider) | 81 ThemeProvider* theme_provider) |
| 78 : Animation(kFramerate, this), | 82 : Animation(kFramerate, this), |
| (...skipping 27 matching lines...) Expand all Loading... |
| 106 | 110 |
| 107 enum BubbleStyle { | 111 enum BubbleStyle { |
| 108 STYLE_BOTTOM, | 112 STYLE_BOTTOM, |
| 109 STYLE_FLOATING, | 113 STYLE_FLOATING, |
| 110 STYLE_STANDARD, | 114 STYLE_STANDARD, |
| 111 STYLE_STANDARD_RIGHT | 115 STYLE_STANDARD_RIGHT |
| 112 }; | 116 }; |
| 113 | 117 |
| 114 // Set the bubble text to a certain value, hides the bubble if text is | 118 // Set the bubble text to a certain value, hides the bubble if text is |
| 115 // an empty string. | 119 // 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. |
| 116 void SetText(const std::wstring& text); | 125 void SetText(const std::wstring& text); |
| 117 | 126 |
| 118 BubbleStage GetState() const { return stage_; } | 127 BubbleStage GetState() const { return stage_; } |
| 119 | 128 |
| 120 void SetStyle(BubbleStyle style); | 129 void SetStyle(BubbleStyle style); |
| 121 | 130 |
| 122 BubbleStyle GetStyle() const { return style_; } | 131 BubbleStyle GetStyle() const { return style_; } |
| 123 | 132 |
| 124 // Show the bubble instantly. | 133 // Show the bubble instantly. |
| 125 void Show(); | 134 void Show(); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 // fade-in can easily turn into a fade out, opacity_start_ is sometimes | 180 // fade-in can easily turn into a fade out, opacity_start_ is sometimes |
| 172 // a value between 0 and 1. | 181 // a value between 0 and 1. |
| 173 double opacity_start_; | 182 double opacity_start_; |
| 174 double opacity_end_; | 183 double opacity_end_; |
| 175 | 184 |
| 176 // Holds the theme provider of the frame that created us. | 185 // Holds the theme provider of the frame that created us. |
| 177 ThemeProvider* theme_provider_; | 186 ThemeProvider* theme_provider_; |
| 178 }; | 187 }; |
| 179 | 188 |
| 180 void StatusBubbleViews::StatusView::SetText(const std::wstring& text) { | 189 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) { |
| 181 if (text.empty()) { | 196 if (text.empty()) { |
| 182 // The string was empty. | 197 // The string was empty. |
| 183 StartHiding(); | 198 StartHiding(); |
| 184 } else { | 199 } else { |
| 185 // We want to show the string. | 200 // We want to show the string. |
| 186 text_ = text; | 201 text_ = text; |
| 187 StartShowing(); | 202 StartShowing(); |
| 188 } | 203 } |
| 189 | 204 |
| 190 SchedulePaint(); | 205 SchedulePaint(); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 SchedulePaint(); | 325 SchedulePaint(); |
| 311 } | 326 } |
| 312 | 327 |
| 313 void StatusBubbleViews::StatusView::AnimateToState(double state) { | 328 void StatusBubbleViews::StatusView::AnimateToState(double state) { |
| 314 SetOpacity(GetCurrentOpacity()); | 329 SetOpacity(GetCurrentOpacity()); |
| 315 } | 330 } |
| 316 | 331 |
| 317 void StatusBubbleViews::StatusView::AnimationEnded( | 332 void StatusBubbleViews::StatusView::AnimationEnded( |
| 318 const Animation* animation) { | 333 const Animation* animation) { |
| 319 SetOpacity(opacity_end_); | 334 SetOpacity(opacity_end_); |
| 320 | |
| 321 if (stage_ == BUBBLE_HIDING_FADE) { | 335 if (stage_ == BUBBLE_HIDING_FADE) { |
| 322 stage_ = BUBBLE_HIDDEN; | 336 stage_ = BUBBLE_HIDDEN; |
| 323 popup_->Hide(); | 337 popup_->Hide(); |
| 324 } else if (stage_ == BUBBLE_SHOWING_FADE) { | 338 } else if (stage_ == BUBBLE_SHOWING_FADE) { |
| 325 stage_ = BUBBLE_SHOWN; | 339 stage_ = BUBBLE_SHOWN; |
| 326 } | 340 } |
| 327 } | 341 } |
| 328 | 342 |
| 329 void StatusBubbleViews::StatusView::SetStyle(BubbleStyle style) { | 343 void StatusBubbleViews::StatusView::SetStyle(BubbleStyle style) { |
| 330 if (style_ != style) { | 344 if (style_ != style) { |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 446 | 460 |
| 447 canvas->DrawStringInt(text_, | 461 canvas->DrawStringInt(text_, |
| 448 views::Label::GetFont(), | 462 views::Label::GetFont(), |
| 449 kTextColor, | 463 kTextColor, |
| 450 body_bounds.x(), | 464 body_bounds.x(), |
| 451 body_bounds.y(), | 465 body_bounds.y(), |
| 452 body_bounds.width(), | 466 body_bounds.width(), |
| 453 body_bounds.height()); | 467 body_bounds.height()); |
| 454 } | 468 } |
| 455 | 469 |
| 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 |
| 456 // StatusBubble --------------------------------------------------------------- | 547 // StatusBubble --------------------------------------------------------------- |
| 457 | 548 |
| 458 const int StatusBubbleViews::kShadowThickness = 1; | 549 const int StatusBubbleViews::kShadowThickness = 1; |
| 459 | 550 |
| 460 StatusBubbleViews::StatusBubbleViews(views::Widget* frame) | 551 StatusBubbleViews::StatusBubbleViews(views::Widget* frame) |
| 461 : offset_(0), | 552 : offset_(0), |
| 462 popup_(NULL), | 553 popup_(NULL), |
| 463 opacity_(0), | 554 opacity_(0), |
| 464 frame_(frame), | 555 frame_(frame), |
| 465 view_(NULL), | 556 view_(NULL), |
| 466 download_shelf_is_visible_(false) { | 557 download_shelf_is_visible_(false), |
| 558 is_expanded_(false), |
| 559 expand_timer_factory_(this) { |
| 467 } | 560 } |
| 468 | 561 |
| 469 StatusBubbleViews::~StatusBubbleViews() { | 562 StatusBubbleViews::~StatusBubbleViews() { |
| 563 CancelExpandTimer(); |
| 470 if (popup_.get()) | 564 if (popup_.get()) |
| 471 popup_->CloseNow(); | 565 popup_->CloseNow(); |
| 472 } | 566 } |
| 473 | 567 |
| 474 void StatusBubbleViews::Init() { | 568 void StatusBubbleViews::Init() { |
| 475 if (!popup_.get()) { | 569 if (!popup_.get()) { |
| 476 #if defined(OS_WIN) | 570 #if defined(OS_WIN) |
| 477 views::WidgetWin* popup = new views::WidgetWin; | 571 views::WidgetWin* popup = new views::WidgetWin; |
| 478 popup->set_delete_on_destroy(false); | 572 popup->set_delete_on_destroy(false); |
| 479 | 573 |
| 480 if (!view_) | 574 if (!view_) |
| 481 view_ = new StatusView(this, popup, frame_->GetThemeProvider()); | 575 view_ = new StatusView(this, popup, frame_->GetThemeProvider()); |
| 576 if (!expand_view_) |
| 577 expand_view_ = new StatusViewExpander(this, view_); |
| 482 | 578 |
| 483 popup->set_window_style(WS_POPUP); | 579 popup->set_window_style(WS_POPUP); |
| 484 popup->set_window_ex_style(WS_EX_LAYERED | WS_EX_TOOLWINDOW | | 580 popup->set_window_ex_style(WS_EX_LAYERED | WS_EX_TOOLWINDOW | |
| 485 WS_EX_TRANSPARENT | | 581 WS_EX_TRANSPARENT | |
| 486 l10n_util::GetExtendedTooltipStyles()); | 582 l10n_util::GetExtendedTooltipStyles()); |
| 487 popup->SetOpacity(0x00); | 583 popup->SetOpacity(0x00); |
| 488 popup->Init(frame_->GetNativeView(), gfx::Rect(), false); | 584 popup->Init(frame_->GetNativeView(), gfx::Rect(), false); |
| 489 popup->SetContentsView(view_); | 585 popup->SetContentsView(view_); |
| 490 Reposition(); | 586 Reposition(); |
| 491 popup->Show(); | 587 popup->Show(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 Reposition(); | 624 Reposition(); |
| 529 } | 625 } |
| 530 | 626 |
| 531 void StatusBubbleViews::SetStatus(const std::wstring& status_text) { | 627 void StatusBubbleViews::SetStatus(const std::wstring& status_text) { |
| 532 if (status_text_ == status_text) | 628 if (status_text_ == status_text) |
| 533 return; | 629 return; |
| 534 | 630 |
| 535 Init(); | 631 Init(); |
| 536 status_text_ = status_text; | 632 status_text_ = status_text; |
| 537 if (!status_text_.empty()) { | 633 if (!status_text_.empty()) { |
| 538 view_->SetText(status_text); | 634 view_->SetTextAndAnimate(status_text); |
| 539 view_->Show(); | 635 view_->Show(); |
| 540 } else if (!url_text_.empty()) { | 636 } else if (!url_text_.empty()) { |
| 541 view_->SetText(url_text_); | 637 view_->SetTextAndAnimate(url_text_); |
| 542 } else { | 638 } else { |
| 543 view_->SetText(std::wstring()); | 639 view_->SetTextAndAnimate(std::wstring()); |
| 544 } | 640 } |
| 545 } | 641 } |
| 546 | 642 |
| 547 void StatusBubbleViews::SetURL(const GURL& url, const std::wstring& languages) { | 643 void StatusBubbleViews::SetURL(const GURL& url, const std::wstring& languages) { |
| 644 languages_ = languages; |
| 645 url_ = url; |
| 548 Init(); | 646 Init(); |
| 549 | 647 |
| 550 // If we want to clear a displayed URL but there is a status still to | 648 // If we want to clear a displayed URL but there is a status still to |
| 551 // display, display that status instead. | 649 // display, display that status instead. |
| 552 if (url.is_empty() && !status_text_.empty()) { | 650 if (url.is_empty() && !status_text_.empty()) { |
| 553 url_text_ = std::wstring(); | 651 url_text_ = std::wstring(); |
| 554 view_->SetText(status_text_); | 652 view_->SetTextAndAnimate(status_text_); |
| 555 return; | 653 return; |
| 556 } | 654 } |
| 557 | 655 |
| 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 |
| 558 // Set Elided Text corresponding to the GURL object. | 662 // Set Elided Text corresponding to the GURL object. |
| 559 gfx::Rect popup_bounds; | 663 gfx::Rect popup_bounds; |
| 560 popup_->GetBounds(&popup_bounds, true); | 664 popup_->GetBounds(&popup_bounds, true); |
| 561 int text_width = static_cast<int>(popup_bounds.width() - | 665 int text_width = static_cast<int>(popup_bounds.width() - |
| 562 (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1); | 666 (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1); |
| 563 url_text_ = gfx::ElideUrl(url, view_->Label::GetFont(), text_width, | 667 url_text_ = gfx::ElideUrl(url, view_->Label::GetFont(), text_width, |
| 564 languages); | 668 languages); |
| 565 | 669 |
| 670 url_parse::Parsed parsed; |
| 671 std::wstring original_url_text_ = |
| 672 net::FormatUrl(url, languages, true, true, &parsed, NULL); |
| 673 |
| 566 // An URL is always treated as a left-to-right string. On right-to-left UIs | 674 // An URL is always treated as a left-to-right string. On right-to-left UIs |
| 567 // we need to explicitly mark the URL as LTR to make sure it is displayed | 675 // we need to explicitly mark the URL as LTR to make sure it is displayed |
| 568 // correctly. | 676 // correctly. |
| 569 if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT && | 677 if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT && |
| 570 !url_text_.empty()) | 678 !url_text_.empty()) |
| 571 l10n_util::WrapStringWithLTRFormatting(&url_text_); | 679 l10n_util::WrapStringWithLTRFormatting(&url_text_); |
| 572 view_->SetText(url_text_); | 680 |
| 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); |
| 573 } | 694 } |
| 574 | 695 |
| 575 void StatusBubbleViews::Hide() { | 696 void StatusBubbleViews::Hide() { |
| 576 status_text_ = std::wstring(); | 697 status_text_ = std::wstring(); |
| 577 url_text_ = std::wstring(); | 698 url_text_ = std::wstring(); |
| 578 if (view_) | 699 if (view_) |
| 579 view_->Hide(); | 700 view_->Hide(); |
| 580 } | 701 } |
| 581 | 702 |
| 582 void StatusBubbleViews::MouseMoved() { | 703 void StatusBubbleViews::MouseMoved() { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 668 const int bubble_bottom_y = top_left.y() + position_.y() + size_.height(); | 789 const int bubble_bottom_y = top_left.y() + position_.y() + size_.height(); |
| 669 | 790 |
| 670 if (bubble_bottom_y + offset > monitor_rect.height() || | 791 if (bubble_bottom_y + offset > monitor_rect.height() || |
| 671 (download_shelf_is_visible_ && | 792 (download_shelf_is_visible_ && |
| 672 view_->GetStyle() == StatusView::STYLE_FLOATING)) { | 793 view_->GetStyle() == StatusView::STYLE_FLOATING)) { |
| 673 // The offset is still too large. Move the bubble to the right and reset | 794 // The offset is still too large. Move the bubble to the right and reset |
| 674 // Y offset_ to zero. | 795 // Y offset_ to zero. |
| 675 view_->SetStyle(StatusView::STYLE_STANDARD_RIGHT); | 796 view_->SetStyle(StatusView::STYLE_STANDARD_RIGHT); |
| 676 offset_ = 0; | 797 offset_ = 0; |
| 677 | 798 |
| 678 // Substract border width + bubble width. | 799 // Subtract border width + bubble width. |
| 679 int right_position_x = window_width - (position_.x() + size_.width()); | 800 int right_position_x = window_width - (position_.x() + size_.width()); |
| 680 popup_->SetBounds(gfx::Rect(top_left.x() + right_position_x, | 801 popup_->SetBounds(gfx::Rect(top_left.x() + right_position_x, |
| 681 top_left.y() + position_.y(), | 802 top_left.y() + position_.y(), |
| 682 size_.width(), size_.height())); | 803 size_.width(), size_.height())); |
| 683 } else { | 804 } else { |
| 684 offset_ = offset; | 805 offset_ = offset; |
| 685 popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), | 806 popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), |
| 686 top_left.y() + position_.y() + offset_, | 807 top_left.y() + position_.y() + offset_, |
| 687 size_.width(), size_.height())); | 808 size_.width(), size_.height())); |
| 688 } | 809 } |
| 689 } else if (offset_ != 0 || | 810 } else if (offset_ != 0 || |
| 690 view_->GetStyle() == StatusView::STYLE_STANDARD_RIGHT) { | 811 view_->GetStyle() == StatusView::STYLE_STANDARD_RIGHT) { |
| 691 offset_ = 0; | 812 offset_ = 0; |
| 692 view_->SetStyle(StatusView::STYLE_STANDARD); | 813 view_->SetStyle(StatusView::STYLE_STANDARD); |
| 693 popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), | 814 popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), |
| 694 top_left.y() + position_.y(), | 815 top_left.y() + position_.y(), |
| 695 size_.width(), size_.height())); | 816 size_.width(), size_.height())); |
| 696 } | 817 } |
| 697 } | 818 } |
| 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 |