summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/views/tabs/side_tab_strip.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/ui/views/tabs/side_tab_strip.cc')
-rw-r--r--chrome/browser/ui/views/tabs/side_tab_strip.cc260
1 files changed, 260 insertions, 0 deletions
diff --git a/chrome/browser/ui/views/tabs/side_tab_strip.cc b/chrome/browser/ui/views/tabs/side_tab_strip.cc
new file mode 100644
index 0000000..84e8082
--- /dev/null
+++ b/chrome/browser/ui/views/tabs/side_tab_strip.cc
@@ -0,0 +1,260 @@
+// 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/views/tabs/side_tab_strip.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "chrome/browser/views/tabs/side_tab.h"
+#include "chrome/browser/views/tabs/tab_strip_controller.h"
+#include "chrome/browser/view_ids.h"
+#include "gfx/canvas.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "views/background.h"
+#include "views/controls/button/image_button.h"
+
+namespace {
+const int kVerticalTabSpacing = 2;
+const int kTabStripWidth = 140;
+const SkColor kBackgroundColor = SkColorSetARGB(255, 209, 220, 248);
+const SkColor kSeparatorColor = SkColorSetARGB(255, 151, 159, 179);
+
+// Height of the separator.
+const int kSeparatorHeight = 1;
+
+// The new tab button is rendered using a SideTab.
+class SideTabNewTabButton : public SideTab {
+ public:
+ explicit SideTabNewTabButton(TabStripController* controller);
+
+ virtual bool ShouldPaintHighlight() const { return false; }
+ virtual bool IsSelected() const { return false; }
+ bool OnMousePressed(const views::MouseEvent& event);
+ void OnMouseReleased(const views::MouseEvent& event, bool canceled);
+
+ private:
+ TabStripController* controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(SideTabNewTabButton);
+};
+
+SideTabNewTabButton::SideTabNewTabButton(TabStripController* controller)
+ : SideTab(NULL),
+ controller_(controller) {
+ // Never show a close button for the new tab button.
+ close_button()->SetVisible(false);
+ TabRendererData data;
+ data.favicon = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_SIDETABS_NEW_TAB);
+ data.title = l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
+ SetData(data);
+}
+
+bool SideTabNewTabButton::OnMousePressed(const views::MouseEvent& event) {
+ return true;
+}
+
+void SideTabNewTabButton::OnMouseReleased(const views::MouseEvent& event,
+ bool canceled) {
+ if (!canceled && event.IsOnlyLeftMouseButton() && HitTest(event.location()))
+ controller_->CreateNewTab();
+}
+
+} // namespace
+
+// static
+const int SideTabStrip::kTabStripInset = 3;
+
+////////////////////////////////////////////////////////////////////////////////
+// SideTabStrip, public:
+
+SideTabStrip::SideTabStrip(TabStripController* controller)
+ : BaseTabStrip(controller, BaseTabStrip::VERTICAL_TAB_STRIP),
+ newtab_button_(new SideTabNewTabButton(controller)),
+ separator_(new views::View()) {
+ SetID(VIEW_ID_TAB_STRIP);
+ set_background(views::Background::CreateSolidBackground(kBackgroundColor));
+ AddChildView(newtab_button_);
+ separator_->set_background(
+ views::Background::CreateSolidBackground(kSeparatorColor));
+ AddChildView(separator_);
+}
+
+SideTabStrip::~SideTabStrip() {
+ DestroyDragController();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SideTabStrip, BaseTabStrip implementation:
+
+int SideTabStrip::GetPreferredHeight() {
+ return 0;
+}
+
+void SideTabStrip::SetBackgroundOffset(const gfx::Point& offset) {
+}
+
+bool SideTabStrip::IsPositionInWindowCaption(const gfx::Point& point) {
+ return GetViewForPoint(point) == this;
+}
+
+void SideTabStrip::SetDraggedTabBounds(int tab_index,
+ const gfx::Rect& tab_bounds) {
+}
+
+TabStrip* SideTabStrip::AsTabStrip() {
+ return NULL;
+}
+
+void SideTabStrip::StartHighlight(int model_index) {
+}
+
+void SideTabStrip::StopAllHighlighting() {
+}
+
+BaseTab* SideTabStrip::CreateTabForDragging() {
+ SideTab* tab = new SideTab(NULL);
+ // Make sure the dragged tab shares our theme provider. We need to explicitly
+ // do this as during dragging there isn't a theme provider.
+ tab->set_theme_provider(GetThemeProvider());
+ return tab;
+}
+
+void SideTabStrip::RemoveTabAt(int model_index) {
+ StartRemoveTabAnimation(model_index);
+}
+
+void SideTabStrip::SelectTabAt(int old_model_index, int new_model_index) {
+ GetBaseTabAtModelIndex(new_model_index)->SchedulePaint();
+}
+
+void SideTabStrip::TabTitleChangedNotLoading(int model_index) {
+}
+
+gfx::Size SideTabStrip::GetPreferredSize() {
+ return gfx::Size(kTabStripWidth, 0);
+}
+
+void SideTabStrip::PaintChildren(gfx::Canvas* canvas) {
+ // Make sure the dragged tab appears on top of all others by paint it last.
+ BaseTab* dragging_tab = NULL;
+
+ // Paint the new tab and separator first so that any tabs animating appear on
+ // top.
+ separator_->ProcessPaint(canvas);
+ newtab_button_->ProcessPaint(canvas);
+
+ for (int i = tab_count() - 1; i >= 0; --i) {
+ BaseTab* tab = base_tab_at_tab_index(i);
+ if (tab->dragging())
+ dragging_tab = tab;
+ else
+ tab->ProcessPaint(canvas);
+ }
+
+ if (dragging_tab)
+ dragging_tab->ProcessPaint(canvas);
+}
+
+BaseTab* SideTabStrip::CreateTab() {
+ return new SideTab(this);
+}
+
+void SideTabStrip::GenerateIdealBounds() {
+ gfx::Rect layout_rect = GetLocalBounds(false);
+ layout_rect.Inset(kTabStripInset, kTabStripInset);
+
+ int y = layout_rect.y();
+ bool last_was_mini = true;
+ bool has_non_closing_tab = false;
+ separator_bounds_.SetRect(0, -kSeparatorHeight, width(), kSeparatorHeight);
+ for (int i = 0; i < tab_count(); ++i) {
+ BaseTab* tab = base_tab_at_tab_index(i);
+ if (!tab->closing()) {
+ if (last_was_mini != tab->data().mini) {
+ if (has_non_closing_tab) {
+ separator_bounds_.SetRect(0, y, width(), kSeparatorHeight);
+ y += kSeparatorHeight + kVerticalTabSpacing;
+ }
+ newtab_button_bounds_.SetRect(
+ layout_rect.x(), y, layout_rect.width(),
+ newtab_button_->GetPreferredSize().height());
+ y = newtab_button_bounds_.bottom() + kVerticalTabSpacing;
+ last_was_mini = tab->data().mini;
+ }
+ gfx::Rect bounds = gfx::Rect(layout_rect.x(), y, layout_rect.width(),
+ tab->GetPreferredSize().height());
+ set_ideal_bounds(i, bounds);
+ y = bounds.bottom() + kVerticalTabSpacing;
+ has_non_closing_tab = true;
+ }
+ }
+
+ if (last_was_mini) {
+ if (has_non_closing_tab) {
+ separator_bounds_.SetRect(0, y, width(), kSeparatorHeight);
+ y += kSeparatorHeight + kVerticalTabSpacing;
+ }
+ newtab_button_bounds_ =
+ gfx::Rect(layout_rect.x(), y, layout_rect.width(),
+ newtab_button_->GetPreferredSize().height());
+ }
+}
+
+void SideTabStrip::StartInsertTabAnimation(int model_index, bool foreground) {
+ PrepareForAnimation();
+
+ GenerateIdealBounds();
+
+ int tab_data_index = ModelIndexToTabIndex(model_index);
+ BaseTab* tab = base_tab_at_tab_index(tab_data_index);
+ if (model_index == 0) {
+ tab->SetBounds(ideal_bounds(tab_data_index).x(), 0,
+ ideal_bounds(tab_data_index).width(), 0);
+ } else {
+ BaseTab* last_tab = base_tab_at_tab_index(tab_data_index - 1);
+ tab->SetBounds(last_tab->x(), last_tab->bounds().bottom(),
+ ideal_bounds(tab_data_index).width(), 0);
+ }
+
+ AnimateToIdealBounds();
+}
+
+void SideTabStrip::StartMoveTabAnimation() {
+ PrepareForAnimation();
+
+ GenerateIdealBounds();
+ AnimateToIdealBounds();
+}
+
+void SideTabStrip::StopAnimating(bool layout) {
+ if (!IsAnimating())
+ return;
+
+ bounds_animator().Cancel();
+
+ if (layout)
+ DoLayout();
+}
+
+void SideTabStrip::AnimateToIdealBounds() {
+ for (int i = 0; i < tab_count(); ++i) {
+ BaseTab* tab = base_tab_at_tab_index(i);
+ if (!tab->closing() && !tab->dragging())
+ bounds_animator().AnimateViewTo(tab, ideal_bounds(i));
+ }
+
+ bounds_animator().AnimateViewTo(newtab_button_, newtab_button_bounds_);
+
+ bounds_animator().AnimateViewTo(separator_, separator_bounds_);
+}
+
+void SideTabStrip::DoLayout() {
+ BaseTabStrip::DoLayout();
+
+ newtab_button_->SetBounds(newtab_button_bounds_);
+
+ separator_->SetBounds(separator_bounds_);
+}