Index: chrome/browser/ui/views/sidebar/sidebar_tab_strip.cc |
=================================================================== |
--- chrome/browser/ui/views/sidebar/sidebar_tab_strip.cc (revision 0) |
+++ chrome/browser/ui/views/sidebar/sidebar_tab_strip.cc (revision 0) |
@@ -0,0 +1,223 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/ui/views/sidebar/sidebar_tab_strip.h" |
+ |
+#include "base/compiler_specific.h" |
+#include "base/stl_util-inl.h" |
+#include "chrome/browser/defaults.h" |
+#include "chrome/browser/themes/browser_theme_provider.h" |
+#include "chrome/browser/ui/browser.h" |
+#include "chrome/browser/ui/view_ids.h" |
+#include "chrome/browser/ui/views/sidebar/sidebar_tab.h" |
+#include "chrome/browser/ui/views/sidebar/sidebar_tab_strip_controller.h" |
+#include "chrome/common/pref_names.h" |
+#include "gfx/canvas_skia.h" |
+#include "gfx/path.h" |
+#include "gfx/point.h" |
+#include "gfx/rect.h" |
+#include "gfx/size.h" |
+#include "grit/generated_resources.h" |
+#include "grit/theme_resources.h" |
+#include "ui/base/l10n/l10n_util.h" |
+#include "ui/base/resource/resource_bundle.h" |
+#include "views/controls/image_view.h" |
+#include "views/widget/default_theme_provider.h" |
+#include "views/window/non_client_view.h" |
+#include "views/window/window.h" |
+ |
+#undef min |
+#undef max |
+ |
+namespace { |
+const int kTabOffset = -1; |
+const int kFisrtTabInitalHeight = 6; |
+} // namespace |
+ |
+// SidebarTabStrip, public: |
+ |
+SidebarTabStrip::SidebarTabStrip(SidebarTabStripController* controller) |
+ : SidebarBaseTabStrip(controller), |
+ animation_container_(new ui::AnimationContainer()) { |
+} |
+ |
+SidebarTabStrip::~SidebarTabStrip() { |
+ // The animations may reference the tabs. Shut down the animation before we |
+ // delete the tabs. |
+ StopAnimating(); |
+ |
+ // The children (tabs) may callback to us from their destructor. Delete them |
+ // so that if they call back we aren't in a weird state. |
+ RemoveAllChildViews(true); |
+} |
+ |
+// SidebarTabStrip, views::View overrides: |
+ |
+void SidebarTabStrip::Layout() { |
+ UpdateViewBounds(); |
+ |
+ SchedulePaint(); |
+} |
+ |
+views::View* SidebarTabStrip::GetViewForPoint(const gfx::Point& point) { |
+ // Return any view that isn't a SidebarTab or this SidebarTabStrip |
+ // immediately. We don't want to interfere. |
+ views::View* v = View::GetViewForPoint(point); |
+ if (v && v != this && v->GetClassName() != SidebarTab::kViewClassName) |
+ return v; |
+ |
+ // The display order doesn't necessarily match the child list order, so we |
+ // walk the display list hit-testing Tabs. Since the selected tab always |
+ // renders on top of adjacent tabs, it needs to be hit-tested before any |
+ // left-adjacent SidebarTab, so we look ahead for it as we walk. |
+ for (int i = 0; i < tab_count(); ++i) { |
+ SidebarBaseTab* next_tab = |
+ i < (tab_count() - 1) ? base_tab_at_tab_index(i + 1) : NULL; |
+ if (next_tab && next_tab->IsSelected() && IsPointInTab(next_tab, point)) |
+ return next_tab; |
+ SidebarBaseTab* tab = base_tab_at_tab_index(i); |
+ if (IsPointInTab(tab, point)) |
+ return tab; |
+ } |
+ |
+ // No need to do any floating view stuff, we don't use them |
+ // in the SidebarTabStrip. |
+ return this; |
+} |
+ |
+// Overridden to support automation. See automation_proxy_uitest.cc. |
+views::View* SidebarTabStrip::GetViewByID(int view_id) const { |
+ if (tab_count() > 0) { |
+ if (view_id == VIEW_ID_TAB_LAST) |
+ return base_tab_at_tab_index(tab_count() - 1); |
+ if ((view_id >= VIEW_ID_TAB_0) && (view_id < VIEW_ID_TAB_LAST)) { |
+ int index = view_id - VIEW_ID_TAB_0; |
+ if (index >= 0 && index < tab_count()) |
+ return base_tab_at_tab_index(index); |
+ return NULL; |
+ } |
+ } |
+ |
+ return View::GetViewByID(view_id); |
+} |
+ |
+AccessibilityTypes::Role SidebarTabStrip::GetAccessibleRole() { |
+ return AccessibilityTypes::ROLE_PAGETABLIST; |
+} |
+ |
+void SidebarTabStrip::PaintChildren(gfx::Canvas* canvas) { |
+ // Painting closing tabs first, so they appear behind the regular ones. |
+ for (int i = tab_count() - 1; i >= 0; --i) { |
+ SidebarBaseTab* tab = base_tab_at_tab_index(i); |
+ // We must ask the _Tab's_ model, not ourselves, because in some situations |
+ // the model will be different to this object, e.g. when a SidebarTab |
+ // is being removed after its TabContents has been destroyed. |
+ if (tab->closing()) |
+ tab->ProcessPaint(canvas); |
+ } |
+ |
+ // Tabs are painted in reverse order, so they stack to the bottom. |
+ SidebarBaseTab* selected_tab = NULL; |
+ |
+ // Paint all non-closing tabs, except the selected one. |
+ for (int i = tab_count() - 1; i >= 0; --i) { |
+ SidebarBaseTab* tab = base_tab_at_tab_index(i); |
+ if (!tab->closing()) { |
+ if (!tab->IsSelected()) |
+ tab->ProcessPaint(canvas); |
+ else |
+ selected_tab = tab; |
+ } |
+ } |
+ |
+ // Paint the selected tab last, so it overlaps all the others. |
+ if (selected_tab) |
+ selected_tab->ProcessPaint(canvas); |
+} |
+ |
+// SidebarBaseTabStrip overrides: |
+ |
+SidebarBaseTab* SidebarTabStrip::CreateTab() { |
+ SidebarTab* tab = new SidebarTab(this); |
+ tab->set_animation_container(animation_container_.get()); |
+ return tab; |
+} |
+ |
+void SidebarTabStrip::StartInsertTabAnimation(int model_index) { |
+ // The only tab should not be animated, it looks wierd. |
+ DCHECK_GT(tab_count(), 1); |
+ |
+ GenerateIdealBounds(); |
+ |
+ // Override inserted tab bounds to achieve a desired animation effect. |
+ int tab_data_index = ModelIndexToTabIndex(model_index); |
+ SidebarBaseTab* tab = base_tab_at_tab_index(tab_data_index); |
+ if (tab_data_index == 0) { |
+ // First tab is animated from its own ideal bounds().y(), so in combination |
+ // with tab strip position update it looks like this new tab grows and |
+ // pushes all other tabs up. |
+ tab->SetBounds(0, ideal_bounds(tab_data_index).y(), |
+ ideal_bounds(tab_data_index).width(), kFisrtTabInitalHeight); |
+ } else { |
+ // Non-first tabs are animated from the previous tab position, so they |
+ // slide up from underneath the previous tab and pushes the rest of the tabs |
+ // up. |
+ SidebarBaseTab* previous_tab = base_tab_at_tab_index(tab_data_index - 1); |
+ tab->SetBoundsRect(previous_tab->bounds()); |
+ } |
+ |
+ AnimateToIdealBounds(); |
+} |
+ |
+void SidebarTabStrip::StartRemoveTabAnimation(int model_index) { |
+ // Mark the tab as closing. |
+ SidebarBaseTab* tab = GetBaseTabAtModelIndex(model_index); |
+ tab->set_closing(true); |
+ |
+ // Start an animation for the tabs. |
+ GenerateIdealBounds(); |
+ AnimateToIdealBounds(); |
+} |
+ |
+void SidebarTabStrip::GenerateIdealBounds() { |
+ if (tab_count() == 0) |
+ return; |
+ |
+ int non_closing_tab_count = 0; |
+ for (int i = 0; i < tab_count(); ++i) { |
+ if (!base_tab_at_tab_index(i)->closing()) |
+ ++non_closing_tab_count; |
+ } |
+ |
+ int tab_width = SidebarTab::GetStandardSize().width(); |
+ int tab_height = SidebarTab::GetStandardSize().height(); |
+ int tab_y = non_closing_tab_count == 0 ? 0 : |
+ (non_closing_tab_count - 1) * (tab_height + kTabOffset); |
+ |
+ bool first_non_closing_tab = true; |
+ gfx::Rect current_tab_bounds(0, tab_y, tab_width, tab_height); |
+ |
+ for (int i = 0; i < tab_count(); ++i) { |
+ if (!base_tab_at_tab_index(i)->closing()) { |
+ if (!first_non_closing_tab) { |
+ tab_y -= tab_height + kTabOffset; |
+ current_tab_bounds.set_y(tab_y); |
+ } else { |
+ first_non_closing_tab = false; |
+ } |
+ } |
+ set_ideal_bounds(i, current_tab_bounds); |
+ } |
+} |
+ |
+// SidebarTabStrip, private: |
+ |
+bool SidebarTabStrip::IsPointInTab( |
+ SidebarBaseTab* tab, |
+ const gfx::Point& point_in_tab_strip_coords) { |
+ gfx::Point point_in_tab_coords(point_in_tab_strip_coords); |
+ View::ConvertPointToView(this, tab, &point_in_tab_coords); |
+ return tab->HitTest(point_in_tab_coords); |
+} |
+ |
Property changes on: chrome\browser\ui\views\sidebar\sidebar_tab_strip.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |