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 |