OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/ui/views/sidebar/sidebar_tab_strip.h" |
| 6 |
| 7 #include "base/compiler_specific.h" |
| 8 #include "base/stl_util-inl.h" |
| 9 #include "chrome/browser/defaults.h" |
| 10 #include "chrome/browser/themes/browser_theme_provider.h" |
| 11 #include "chrome/browser/ui/browser.h" |
| 12 #include "chrome/browser/ui/view_ids.h" |
| 13 #include "chrome/browser/ui/views/sidebar/sidebar_tab.h" |
| 14 #include "chrome/browser/ui/views/sidebar/sidebar_tab_strip_controller.h" |
| 15 #include "chrome/common/pref_names.h" |
| 16 #include "gfx/canvas_skia.h" |
| 17 #include "gfx/path.h" |
| 18 #include "gfx/point.h" |
| 19 #include "gfx/rect.h" |
| 20 #include "gfx/size.h" |
| 21 #include "grit/generated_resources.h" |
| 22 #include "grit/theme_resources.h" |
| 23 #include "ui/base/l10n/l10n_util.h" |
| 24 #include "ui/base/resource/resource_bundle.h" |
| 25 #include "views/controls/image_view.h" |
| 26 #include "views/widget/default_theme_provider.h" |
| 27 #include "views/window/non_client_view.h" |
| 28 #include "views/window/window.h" |
| 29 |
| 30 #undef min |
| 31 #undef max |
| 32 |
| 33 namespace { |
| 34 const int kTabOffset = -1; |
| 35 const int kFisrtTabInitalHeight = 6; |
| 36 } // namespace |
| 37 |
| 38 // SidebarTabStrip, public: |
| 39 |
| 40 SidebarTabStrip::SidebarTabStrip(SidebarTabStripController* controller) |
| 41 : SidebarBaseTabStrip(controller), |
| 42 animation_container_(new ui::AnimationContainer()) { |
| 43 } |
| 44 |
| 45 SidebarTabStrip::~SidebarTabStrip() { |
| 46 // The animations may reference the tabs. Shut down the animation before we |
| 47 // delete the tabs. |
| 48 StopAnimating(); |
| 49 |
| 50 // The children (tabs) may callback to us from their destructor. Delete them |
| 51 // so that if they call back we aren't in a weird state. |
| 52 RemoveAllChildViews(true); |
| 53 } |
| 54 |
| 55 // SidebarTabStrip, views::View overrides: |
| 56 |
| 57 void SidebarTabStrip::Layout() { |
| 58 UpdateViewBounds(); |
| 59 |
| 60 SchedulePaint(); |
| 61 } |
| 62 |
| 63 views::View* SidebarTabStrip::GetViewForPoint(const gfx::Point& point) { |
| 64 // Return any view that isn't a SidebarTab or this SidebarTabStrip |
| 65 // immediately. We don't want to interfere. |
| 66 views::View* v = View::GetViewForPoint(point); |
| 67 if (v && v != this && v->GetClassName() != SidebarTab::kViewClassName) |
| 68 return v; |
| 69 |
| 70 // The display order doesn't necessarily match the child list order, so we |
| 71 // walk the display list hit-testing Tabs. Since the selected tab always |
| 72 // renders on top of adjacent tabs, it needs to be hit-tested before any |
| 73 // left-adjacent SidebarTab, so we look ahead for it as we walk. |
| 74 for (int i = 0; i < tab_count(); ++i) { |
| 75 SidebarBaseTab* next_tab = |
| 76 i < (tab_count() - 1) ? base_tab_at_tab_index(i + 1) : NULL; |
| 77 if (next_tab && next_tab->IsSelected() && IsPointInTab(next_tab, point)) |
| 78 return next_tab; |
| 79 SidebarBaseTab* tab = base_tab_at_tab_index(i); |
| 80 if (IsPointInTab(tab, point)) |
| 81 return tab; |
| 82 } |
| 83 |
| 84 // No need to do any floating view stuff, we don't use them |
| 85 // in the SidebarTabStrip. |
| 86 return this; |
| 87 } |
| 88 |
| 89 // Overridden to support automation. See automation_proxy_uitest.cc. |
| 90 views::View* SidebarTabStrip::GetViewByID(int view_id) const { |
| 91 if (tab_count() > 0) { |
| 92 if (view_id == VIEW_ID_TAB_LAST) |
| 93 return base_tab_at_tab_index(tab_count() - 1); |
| 94 if ((view_id >= VIEW_ID_TAB_0) && (view_id < VIEW_ID_TAB_LAST)) { |
| 95 int index = view_id - VIEW_ID_TAB_0; |
| 96 if (index >= 0 && index < tab_count()) |
| 97 return base_tab_at_tab_index(index); |
| 98 return NULL; |
| 99 } |
| 100 } |
| 101 |
| 102 return View::GetViewByID(view_id); |
| 103 } |
| 104 |
| 105 AccessibilityTypes::Role SidebarTabStrip::GetAccessibleRole() { |
| 106 return AccessibilityTypes::ROLE_PAGETABLIST; |
| 107 } |
| 108 |
| 109 void SidebarTabStrip::PaintChildren(gfx::Canvas* canvas) { |
| 110 // Painting closing tabs first, so they appear behind the regular ones. |
| 111 for (int i = tab_count() - 1; i >= 0; --i) { |
| 112 SidebarBaseTab* tab = base_tab_at_tab_index(i); |
| 113 // We must ask the _Tab's_ model, not ourselves, because in some situations |
| 114 // the model will be different to this object, e.g. when a SidebarTab |
| 115 // is being removed after its TabContents has been destroyed. |
| 116 if (tab->closing()) |
| 117 tab->ProcessPaint(canvas); |
| 118 } |
| 119 |
| 120 // Tabs are painted in reverse order, so they stack to the bottom. |
| 121 SidebarBaseTab* selected_tab = NULL; |
| 122 |
| 123 // Paint all non-closing tabs, except the selected one. |
| 124 for (int i = tab_count() - 1; i >= 0; --i) { |
| 125 SidebarBaseTab* tab = base_tab_at_tab_index(i); |
| 126 if (!tab->closing()) { |
| 127 if (!tab->IsSelected()) |
| 128 tab->ProcessPaint(canvas); |
| 129 else |
| 130 selected_tab = tab; |
| 131 } |
| 132 } |
| 133 |
| 134 // Paint the selected tab last, so it overlaps all the others. |
| 135 if (selected_tab) |
| 136 selected_tab->ProcessPaint(canvas); |
| 137 } |
| 138 |
| 139 // SidebarBaseTabStrip overrides: |
| 140 |
| 141 SidebarBaseTab* SidebarTabStrip::CreateTab() { |
| 142 SidebarTab* tab = new SidebarTab(this); |
| 143 tab->set_animation_container(animation_container_.get()); |
| 144 return tab; |
| 145 } |
| 146 |
| 147 void SidebarTabStrip::StartInsertTabAnimation(int model_index) { |
| 148 // The only tab should not be animated, it looks wierd. |
| 149 DCHECK_GT(tab_count(), 1); |
| 150 |
| 151 GenerateIdealBounds(); |
| 152 |
| 153 // Override inserted tab bounds to achieve a desired animation effect. |
| 154 int tab_data_index = ModelIndexToTabIndex(model_index); |
| 155 SidebarBaseTab* tab = base_tab_at_tab_index(tab_data_index); |
| 156 if (tab_data_index == 0) { |
| 157 // First tab is animated from its own ideal bounds().y(), so in combination |
| 158 // with tab strip position update it looks like this new tab grows and |
| 159 // pushes all other tabs up. |
| 160 tab->SetBounds(0, ideal_bounds(tab_data_index).y(), |
| 161 ideal_bounds(tab_data_index).width(), kFisrtTabInitalHeight); |
| 162 } else { |
| 163 // Non-first tabs are animated from the previous tab position, so they |
| 164 // slide up from underneath the previous tab and pushes the rest of the tabs |
| 165 // up. |
| 166 SidebarBaseTab* previous_tab = base_tab_at_tab_index(tab_data_index - 1); |
| 167 tab->SetBoundsRect(previous_tab->bounds()); |
| 168 } |
| 169 |
| 170 AnimateToIdealBounds(); |
| 171 } |
| 172 |
| 173 void SidebarTabStrip::StartRemoveTabAnimation(int model_index) { |
| 174 // Mark the tab as closing. |
| 175 SidebarBaseTab* tab = GetBaseTabAtModelIndex(model_index); |
| 176 tab->set_closing(true); |
| 177 |
| 178 // Start an animation for the tabs. |
| 179 GenerateIdealBounds(); |
| 180 AnimateToIdealBounds(); |
| 181 } |
| 182 |
| 183 void SidebarTabStrip::GenerateIdealBounds() { |
| 184 if (tab_count() == 0) |
| 185 return; |
| 186 |
| 187 int non_closing_tab_count = 0; |
| 188 for (int i = 0; i < tab_count(); ++i) { |
| 189 if (!base_tab_at_tab_index(i)->closing()) |
| 190 ++non_closing_tab_count; |
| 191 } |
| 192 |
| 193 int tab_width = SidebarTab::GetStandardSize().width(); |
| 194 int tab_height = SidebarTab::GetStandardSize().height(); |
| 195 int tab_y = non_closing_tab_count == 0 ? 0 : |
| 196 (non_closing_tab_count - 1) * (tab_height + kTabOffset); |
| 197 |
| 198 bool first_non_closing_tab = true; |
| 199 gfx::Rect current_tab_bounds(0, tab_y, tab_width, tab_height); |
| 200 |
| 201 for (int i = 0; i < tab_count(); ++i) { |
| 202 if (!base_tab_at_tab_index(i)->closing()) { |
| 203 if (!first_non_closing_tab) { |
| 204 tab_y -= tab_height + kTabOffset; |
| 205 current_tab_bounds.set_y(tab_y); |
| 206 } else { |
| 207 first_non_closing_tab = false; |
| 208 } |
| 209 } |
| 210 set_ideal_bounds(i, current_tab_bounds); |
| 211 } |
| 212 } |
| 213 |
| 214 // SidebarTabStrip, private: |
| 215 |
| 216 bool SidebarTabStrip::IsPointInTab( |
| 217 SidebarBaseTab* tab, |
| 218 const gfx::Point& point_in_tab_strip_coords) { |
| 219 gfx::Point point_in_tab_coords(point_in_tab_strip_coords); |
| 220 View::ConvertPointToView(this, tab, &point_in_tab_coords); |
| 221 return tab->HitTest(point_in_tab_coords); |
| 222 } |
| 223 |
OLD | NEW |