OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/ui/views/tabs/tab_strip.h" | 5 #include "chrome/browser/ui/views/tabs/tab_strip.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <iterator> | 8 #include <iterator> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
12 #include "base/stl_util-inl.h" | 12 #include "base/stl_util-inl.h" |
13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
14 #include "chrome/browser/defaults.h" | 14 #include "chrome/browser/defaults.h" |
15 #include "chrome/browser/tabs/tab_strip_selection_model.h" | 15 #include "chrome/browser/tabs/tab_strip_selection_model.h" |
16 #include "chrome/browser/themes/theme_service.h" | 16 #include "chrome/browser/themes/theme_service.h" |
| 17 #include "chrome/browser/ui/browser.h" |
| 18 #include "chrome/browser/ui/browser_window.h" |
17 #include "chrome/browser/ui/view_ids.h" | 19 #include "chrome/browser/ui/view_ids.h" |
18 #include "chrome/browser/ui/views/tabs/tab.h" | 20 #include "chrome/browser/ui/views/tabs/tab.h" |
19 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h" | 21 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h" |
20 #include "grit/generated_resources.h" | 22 #include "grit/generated_resources.h" |
21 #include "grit/theme_resources.h" | 23 #include "grit/theme_resources.h" |
22 #include "grit/theme_resources_standard.h" | 24 #include "grit/theme_resources_standard.h" |
23 #include "ui/base/accessibility/accessible_view_state.h" | 25 #include "ui/base/accessibility/accessible_view_state.h" |
24 #include "ui/base/animation/animation_container.h" | 26 #include "ui/base/animation/animation_container.h" |
25 #include "ui/base/dragdrop/drag_drop_types.h" | 27 #include "ui/base/dragdrop/drag_drop_types.h" |
26 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 | 72 |
71 namespace { | 73 namespace { |
72 | 74 |
73 /////////////////////////////////////////////////////////////////////////////// | 75 /////////////////////////////////////////////////////////////////////////////// |
74 // NewTabButton | 76 // NewTabButton |
75 // | 77 // |
76 // A subclass of button that hit-tests to the shape of the new tab button. | 78 // A subclass of button that hit-tests to the shape of the new tab button. |
77 | 79 |
78 class NewTabButton : public views::ImageButton { | 80 class NewTabButton : public views::ImageButton { |
79 public: | 81 public: |
80 explicit NewTabButton(views::ButtonListener* listener) | 82 explicit NewTabButton(TabStrip* tab_strip, views::ButtonListener* listener) |
81 : views::ImageButton(listener) { | 83 : views::ImageButton(listener), tab_strip_(tab_strip) { |
82 } | 84 } |
83 virtual ~NewTabButton() {} | 85 virtual ~NewTabButton() {} |
84 | 86 |
85 protected: | 87 protected: |
86 // Overridden from views::View: | 88 // Overridden from views::View: |
87 virtual bool HasHitTestMask() const { | 89 virtual bool HasHitTestMask() const { |
88 // When the button is sized to the top of the tab strip we want the user to | 90 // When the button is sized to the top of the tab strip we want the user to |
89 // be able to click on complete bounds, and so don't return a custom hit | 91 // be able to click on complete bounds, and so don't return a custom hit |
90 // mask. | 92 // mask. |
91 return !browser_defaults::kSizeTabButtonToTopOfTabStrip; | 93 return !tab_strip_->SizeTabButtonToTopOfTabStrip(); |
92 } | 94 } |
93 virtual void GetHitTestMask(gfx::Path* path) const { | 95 virtual void GetHitTestMask(gfx::Path* path) const { |
94 DCHECK(path); | 96 DCHECK(path); |
95 | 97 |
96 SkScalar w = SkIntToScalar(width()); | 98 SkScalar w = SkIntToScalar(width()); |
97 | 99 |
98 // These values are defined by the shape of the new tab bitmap. Should that | 100 // These values are defined by the shape of the new tab bitmap. Should that |
99 // bitmap ever change, these values will need to be updated. They're so | 101 // bitmap ever change, these values will need to be updated. They're so |
100 // custom it's not really worth defining constants for. | 102 // custom it's not really worth defining constants for. |
101 path->moveTo(0, 1); | 103 path->moveTo(0, 1); |
102 path->lineTo(w - 7, 1); | 104 path->lineTo(w - 7, 1); |
103 path->lineTo(w - 4, 4); | 105 path->lineTo(w - 4, 4); |
104 path->lineTo(w, 16); | 106 path->lineTo(w, 16); |
105 path->lineTo(w - 1, 17); | 107 path->lineTo(w - 1, 17); |
106 path->lineTo(7, 17); | 108 path->lineTo(7, 17); |
107 path->lineTo(4, 13); | 109 path->lineTo(4, 13); |
108 path->lineTo(0, 1); | 110 path->lineTo(0, 1); |
109 path->close(); | 111 path->close(); |
110 } | 112 } |
111 | 113 |
112 private: | 114 private: |
| 115 // Tab strip that contains this button. |
| 116 TabStrip* tab_strip_; |
| 117 |
113 DISALLOW_COPY_AND_ASSIGN(NewTabButton); | 118 DISALLOW_COPY_AND_ASSIGN(NewTabButton); |
114 }; | 119 }; |
115 | 120 |
116 } // namespace | 121 } // namespace |
117 | 122 |
118 /////////////////////////////////////////////////////////////////////////////// | 123 /////////////////////////////////////////////////////////////////////////////// |
119 // TabStrip, public: | 124 // TabStrip, public: |
120 | 125 |
121 // static | 126 // static |
122 const int TabStrip::mini_to_non_mini_gap_ = 3; | 127 const int TabStrip::mini_to_non_mini_gap_ = 3; |
123 | 128 |
124 TabStrip::TabStrip(TabStripController* controller) | 129 TabStrip::TabStrip(Browser* browser, TabStripController* controller) |
125 : BaseTabStrip(controller, BaseTabStrip::HORIZONTAL_TAB_STRIP), | 130 : BaseTabStrip(controller, BaseTabStrip::HORIZONTAL_TAB_STRIP), |
126 newtab_button_(NULL), | 131 newtab_button_(NULL), |
127 current_unselected_width_(Tab::GetStandardSize().width()), | 132 current_unselected_width_(Tab::GetStandardSize().width()), |
128 current_selected_width_(Tab::GetStandardSize().width()), | 133 current_selected_width_(Tab::GetStandardSize().width()), |
129 available_width_for_tabs_(-1), | 134 available_width_for_tabs_(-1), |
130 in_tab_close_(false), | 135 in_tab_close_(false), |
131 animation_container_(new ui::AnimationContainer()) { | 136 animation_container_(new ui::AnimationContainer()), |
| 137 browser_(browser) { |
132 Init(); | 138 Init(); |
133 } | 139 } |
134 | 140 |
135 TabStrip::~TabStrip() { | 141 TabStrip::~TabStrip() { |
136 // The animations may reference the tabs. Shut down the animation before we | 142 // The animations may reference the tabs. Shut down the animation before we |
137 // delete the tabs. | 143 // delete the tabs. |
138 StopAnimating(false); | 144 StopAnimating(false); |
139 | 145 |
140 DestroyDragController(); | 146 DestroyDragController(); |
141 | 147 |
142 // Make sure we unhook ourselves as a message loop observer so that we don't | 148 // Make sure we unhook ourselves as a message loop observer so that we don't |
143 // crash in the case where the user closes the window after closing a tab | 149 // crash in the case where the user closes the window after closing a tab |
144 // but before moving the mouse. | 150 // but before moving the mouse. |
145 RemoveMessageLoopObserver(); | 151 RemoveMessageLoopObserver(); |
146 | 152 |
147 // The children (tabs) may callback to us from their destructor. Delete them | 153 // The children (tabs) may callback to us from their destructor. Delete them |
148 // so that if they call back we aren't in a weird state. | 154 // so that if they call back we aren't in a weird state. |
149 RemoveAllChildViews(true); | 155 RemoveAllChildViews(true); |
150 } | 156 } |
151 | 157 |
152 void TabStrip::InitTabStripButtons() { | 158 void TabStrip::InitTabStripButtons() { |
153 newtab_button_ = new NewTabButton(this); | 159 newtab_button_ = new NewTabButton(this, this); |
154 if (browser_defaults::kSizeTabButtonToTopOfTabStrip) { | |
155 newtab_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT, | |
156 views::ImageButton::ALIGN_BOTTOM); | |
157 } | |
158 LoadNewTabButtonImage(); | 160 LoadNewTabButtonImage(); |
159 newtab_button_->SetAccessibleName( | 161 newtab_button_->SetAccessibleName( |
160 l10n_util::GetStringUTF16(IDS_ACCNAME_NEWTAB)); | 162 l10n_util::GetStringUTF16(IDS_ACCNAME_NEWTAB)); |
161 AddChildView(newtab_button_); | 163 AddChildView(newtab_button_); |
162 } | 164 } |
163 | 165 |
164 gfx::Rect TabStrip::GetNewTabButtonBounds() { | 166 gfx::Rect TabStrip::GetNewTabButtonBounds() { |
165 return newtab_button_->bounds(); | 167 return newtab_button_->bounds(); |
166 } | 168 } |
167 | 169 |
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 } | 476 } |
475 | 477 |
476 bool TabStrip::ShouldHighlightCloseButtonAfterRemove() { | 478 bool TabStrip::ShouldHighlightCloseButtonAfterRemove() { |
477 return in_tab_close_; | 479 return in_tab_close_; |
478 } | 480 } |
479 | 481 |
480 void TabStrip::DoLayout() { | 482 void TabStrip::DoLayout() { |
481 BaseTabStrip::DoLayout(); | 483 BaseTabStrip::DoLayout(); |
482 | 484 |
483 // It is possible we don't have a new tab button yet. | 485 // It is possible we don't have a new tab button yet. |
484 if (newtab_button_) | 486 if (newtab_button_) { |
| 487 if (SizeTabButtonToTopOfTabStrip()) { |
| 488 newtab_button_bounds_.set_height( |
| 489 kNewTabButtonHeight + kNewTabButtonVOffset); |
| 490 newtab_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT, |
| 491 views::ImageButton::ALIGN_BOTTOM); |
| 492 } else { |
| 493 newtab_button_bounds_.set_height(kNewTabButtonHeight); |
| 494 newtab_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT, |
| 495 views::ImageButton::ALIGN_TOP); |
| 496 } |
485 newtab_button_->SetBoundsRect(newtab_button_bounds_); | 497 newtab_button_->SetBoundsRect(newtab_button_bounds_); |
| 498 } |
486 } | 499 } |
487 | 500 |
488 void TabStrip::LayoutDraggedTabsAt(const std::vector<BaseTab*>& tabs, | 501 void TabStrip::LayoutDraggedTabsAt(const std::vector<BaseTab*>& tabs, |
489 BaseTab* active_tab, | 502 BaseTab* active_tab, |
490 const gfx::Point& location, | 503 const gfx::Point& location, |
491 bool initial_drag) { | 504 bool initial_drag) { |
492 std::vector<gfx::Rect> bounds; | 505 std::vector<gfx::Rect> bounds; |
493 CalculateBoundsForDraggedTabs(tabs, &bounds); | 506 CalculateBoundsForDraggedTabs(tabs, &bounds); |
494 DCHECK_EQ(tabs.size(), bounds.size()); | 507 DCHECK_EQ(tabs.size(), bounds.size()); |
495 int active_tab_model_index = GetModelIndexOfBaseTab(active_tab); | 508 int active_tab_model_index = GetModelIndexOfBaseTab(active_tab); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 if (sender == newtab_button_) | 568 if (sender == newtab_button_) |
556 controller()->CreateNewTab(); | 569 controller()->CreateNewTab(); |
557 } | 570 } |
558 | 571 |
559 /////////////////////////////////////////////////////////////////////////////// | 572 /////////////////////////////////////////////////////////////////////////////// |
560 // TabStrip, private: | 573 // TabStrip, private: |
561 | 574 |
562 void TabStrip::Init() { | 575 void TabStrip::Init() { |
563 set_id(VIEW_ID_TAB_STRIP); | 576 set_id(VIEW_ID_TAB_STRIP); |
564 newtab_button_bounds_.SetRect(0, 0, kNewTabButtonWidth, kNewTabButtonHeight); | 577 newtab_button_bounds_.SetRect(0, 0, kNewTabButtonWidth, kNewTabButtonHeight); |
565 if (browser_defaults::kSizeTabButtonToTopOfTabStrip) { | |
566 newtab_button_bounds_.set_height( | |
567 kNewTabButtonHeight + kNewTabButtonVOffset); | |
568 } | |
569 if (drop_indicator_width == 0) { | 578 if (drop_indicator_width == 0) { |
570 // Direction doesn't matter, both images are the same size. | 579 // Direction doesn't matter, both images are the same size. |
571 SkBitmap* drop_image = GetDropArrowImage(true); | 580 SkBitmap* drop_image = GetDropArrowImage(true); |
572 drop_indicator_width = drop_image->width(); | 581 drop_indicator_width = drop_image->width(); |
573 drop_indicator_height = drop_image->height(); | 582 drop_indicator_height = drop_image->height(); |
574 } | 583 } |
575 } | 584 } |
576 | 585 |
| 586 bool TabStrip::SizeTabButtonToTopOfTabStrip() { |
| 587 if (browser_defaults::kSizeTabButtonToTopOfTabStrip) |
| 588 return true; |
| 589 |
| 590 if (browser_ && browser_->window()) |
| 591 return browser_->window()->IsMaximized(); |
| 592 |
| 593 return false; |
| 594 } |
| 595 |
577 void TabStrip::LoadNewTabButtonImage() { | 596 void TabStrip::LoadNewTabButtonImage() { |
578 ui::ThemeProvider* tp = GetThemeProvider(); | 597 ui::ThemeProvider* tp = GetThemeProvider(); |
579 | 598 |
580 // If we don't have a theme provider yet, it means we do not have a | 599 // If we don't have a theme provider yet, it means we do not have a |
581 // root view, and are therefore in a test. | 600 // root view, and are therefore in a test. |
582 bool in_test = false; | 601 bool in_test = false; |
583 if (tp == NULL) { | 602 if (tp == NULL) { |
584 tp = new views::DefaultThemeProvider(); | 603 tp = new views::DefaultThemeProvider(); |
585 in_test = true; | 604 in_test = true; |
586 } | 605 } |
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
931 set_ideal_bounds(i, | 950 set_ideal_bounds(i, |
932 gfx::Rect(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, | 951 gfx::Rect(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, |
933 tab_height)); | 952 tab_height)); |
934 tab_x = end_of_tab + kTabHOffset; | 953 tab_x = end_of_tab + kTabHOffset; |
935 last_was_mini = tab->data().mini; | 954 last_was_mini = tab->data().mini; |
936 } | 955 } |
937 } | 956 } |
938 | 957 |
939 // Update bounds of new tab button. | 958 // Update bounds of new tab button. |
940 int new_tab_x; | 959 int new_tab_x; |
941 int new_tab_y = browser_defaults::kSizeTabButtonToTopOfTabStrip ? | 960 int new_tab_y = SizeTabButtonToTopOfTabStrip() ? 0 : kNewTabButtonVOffset; |
942 0 : kNewTabButtonVOffset; | |
943 if (abs(Round(unselected) - Tab::GetStandardSize().width()) > 1 && | 961 if (abs(Round(unselected) - Tab::GetStandardSize().width()) > 1 && |
944 !in_tab_close_) { | 962 !in_tab_close_) { |
945 // We're shrinking tabs, so we need to anchor the New Tab button to the | 963 // We're shrinking tabs, so we need to anchor the New Tab button to the |
946 // right edge of the TabStrip's bounds, rather than the right edge of the | 964 // right edge of the TabStrip's bounds, rather than the right edge of the |
947 // right-most Tab, otherwise it'll bounce when animating. | 965 // right-most Tab, otherwise it'll bounce when animating. |
948 new_tab_x = width() - newtab_button_bounds_.width(); | 966 new_tab_x = width() - newtab_button_bounds_.width(); |
949 } else { | 967 } else { |
950 new_tab_x = Round(tab_x - kTabHOffset) + kNewTabButtonHOffset; | 968 new_tab_x = Round(tab_x - kTabHOffset) + kNewTabButtonHOffset; |
951 } | 969 } |
952 newtab_button_bounds_.set_origin(gfx::Point(new_tab_x, new_tab_y)); | 970 newtab_button_bounds_.set_origin(gfx::Point(new_tab_x, new_tab_y)); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1026 } | 1044 } |
1027 return mini_count; | 1045 return mini_count; |
1028 } | 1046 } |
1029 | 1047 |
1030 bool TabStrip::IsPointInTab(Tab* tab, | 1048 bool TabStrip::IsPointInTab(Tab* tab, |
1031 const gfx::Point& point_in_tabstrip_coords) { | 1049 const gfx::Point& point_in_tabstrip_coords) { |
1032 gfx::Point point_in_tab_coords(point_in_tabstrip_coords); | 1050 gfx::Point point_in_tab_coords(point_in_tabstrip_coords); |
1033 View::ConvertPointToView(this, tab, &point_in_tab_coords); | 1051 View::ConvertPointToView(this, tab, &point_in_tab_coords); |
1034 return tab->HitTest(point_in_tab_coords); | 1052 return tab->HitTest(point_in_tab_coords); |
1035 } | 1053 } |
OLD | NEW |