summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-08 23:23:05 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-08 23:23:05 +0000
commit37cd3a96b55aac1dad9016c05e78b5983972f985 (patch)
tree1159bb8897fa21faeadde942163412736889ead9 /chrome
parent4d4c0b94960366979943dbe4e3c8880ce80dbdef (diff)
downloadchromium_src-37cd3a96b55aac1dad9016c05e78b5983972f985.zip
chromium_src-37cd3a96b55aac1dad9016c05e78b5983972f985.tar.gz
chromium_src-37cd3a96b55aac1dad9016c05e78b5983972f985.tar.bz2
First part of tab overview. It isn't wired up, nor is it complete, but
it's a good enough stage that I want to check it in. BUG=none TEST=none Review URL: http://codereview.chromium.org/119329 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17906 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/views/tabs/grid.cc213
-rw-r--r--chrome/browser/views/tabs/grid.h120
-rw-r--r--chrome/browser/views/tabs/tab_overview_cell.cc88
-rw-r--r--chrome/browser/views/tabs/tab_overview_cell.h42
-rw-r--r--chrome/browser/views/tabs/tab_overview_container.cc99
-rw-r--r--chrome/browser/views/tabs/tab_overview_container.h40
-rw-r--r--chrome/browser/views/tabs/tab_overview_controller.cc76
-rw-r--r--chrome/browser/views/tabs/tab_overview_controller.h60
-rw-r--r--chrome/browser/views/tabs/tab_overview_grid.cc200
-rw-r--r--chrome/browser/views/tabs/tab_overview_grid.h116
-rw-r--r--chrome/chrome.gyp34
11 files changed, 1088 insertions, 0 deletions
diff --git a/chrome/browser/views/tabs/grid.cc b/chrome/browser/views/tabs/grid.cc
new file mode 100644
index 0000000..ef2654c
--- /dev/null
+++ b/chrome/browser/views/tabs/grid.cc
@@ -0,0 +1,213 @@
+// Copyright (c) 2009 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/grid.h"
+
+#include "base/compiler_specific.h"
+
+using views::View;
+
+//static
+const int Grid::kCellXPadding = 15;
+// static
+const int Grid::kCellYPadding = 15;
+
+Grid::Grid()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)),
+ modifying_children_(false),
+ needs_layout_(false),
+ pref_width_(0),
+ pref_height_(0),
+ cell_width_(0),
+ cell_height_(0),
+ columns_(0),
+ rows_(0) {
+}
+
+void Grid::MoveCell(int old_index, int new_index) {
+ View* cell = GetChildViewAt(old_index);
+ modifying_children_ = true;
+ RemoveChildView(cell);
+ AddChildView(new_index, cell);
+ modifying_children_ = false;
+
+ CalculateTargetBoundsAndStartAnimation();
+}
+
+void Grid::InsertCell(int index, View* cell) {
+ modifying_children_ = true;
+ AddChildView(index, cell);
+ modifying_children_ = false;
+
+ CalculateTargetBoundsAndStartAnimation();
+
+ // Set the bounds of the cell to it's target bounds. This way it won't appear
+ // to animate.
+ start_bounds_[index] = target_bounds_[index];
+ cell->SetBounds(target_bounds_[index]);
+}
+
+void Grid::RemoveCell(int index) {
+ modifying_children_ = true;
+ RemoveChildView(GetChildViewAt(index));
+ modifying_children_ = false;
+
+ CalculateTargetBoundsAndStartAnimation();
+}
+
+void Grid::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
+ if (modifying_children_ || parent != this)
+ return;
+
+ // Our child views changed without us knowing it. Stop the animation and mark
+ // us as dirty (needs_layout_ = true).
+ animation_.Stop();
+ needs_layout_ = true;
+}
+
+gfx::Size Grid::GetPreferredSize() {
+ if (needs_layout_)
+ Layout();
+
+ return gfx::Size(pref_width_, pref_height_);
+}
+
+void Grid::Layout() {
+ if (!needs_layout_)
+ return;
+
+ needs_layout_ = false;
+ animation_.Stop();
+ target_bounds_.clear();
+ CalculateCellBounds(&target_bounds_);
+ for (size_t i = 0; i < target_bounds_.size(); ++i)
+ GetChildViewAt(i)->SetBounds(target_bounds_[i]);
+}
+
+void Grid::AnimationEnded(const Animation* animation) {
+ SetViewBoundsToTarget();
+}
+
+void Grid::AnimationProgressed(const Animation* animation) {
+ DCHECK(GetChildViewCount() == static_cast<int>(target_bounds_.size()));
+ for (size_t i = 0; i < target_bounds_.size(); ++i) {
+ View* view = GetChildViewAt(i);
+ gfx::Rect start_bounds = start_bounds_[i];
+ gfx::Rect target_bounds = target_bounds_[i];
+ view->SetBounds(
+ gfx::Rect(AnimationPosition(start_bounds.x(), target_bounds.x()),
+ AnimationPosition(start_bounds.y(), target_bounds.y()),
+ AnimationPosition(start_bounds.width(),
+ target_bounds.width()),
+ AnimationPosition(start_bounds.height(),
+ target_bounds.height())));
+ }
+ SchedulePaint();
+}
+
+void Grid::AnimationCanceled(const Animation* animation) {
+ // Don't do anything when the animation is canceled. Presumably Layout will
+ // be invoked, and all children will get set to their appropriate position.
+}
+
+void Grid::CalculateCellBounds(std::vector<gfx::Rect>* bounds) {
+ DCHECK(max_size_.width() > 0 && max_size_.height() > 0);
+ int cell_count = GetChildViewCount();
+ if (cell_count == 0) {
+ pref_width_ = pref_height_ = 0;
+ return;
+ }
+
+ gfx::Size cell_pref = GetChildViewAt(0)->GetPreferredSize();
+ int col_count, row_count;
+ // Assume we get the ideal cell size.
+ int cell_width = cell_pref.width();
+ int cell_height = cell_pref.height();
+ int max_columns = std::max(1, (max_size_.width() + kCellXPadding) /
+ (cell_width + kCellXPadding));
+ if (cell_count <= max_columns) {
+ // All the cells fit in a single row.
+ row_count = 1;
+ col_count = cell_count;
+ } else {
+ // Need more than one row to display all.
+ int max_rows = std::max(1, (max_size_.height() + kCellYPadding) /
+ (cell_height + kCellYPadding));
+ col_count = max_columns;
+ row_count = cell_count / max_columns;
+ if (cell_count % col_count != 0)
+ row_count++;
+ if (cell_count > max_columns * max_rows) {
+ // We don't have enough space for the cells at their ideal size. Keep
+ // adding columns (and shrinking down cell sizes) until we fit
+ // everything.
+ float ratio = static_cast<float>(cell_width) /
+ static_cast<float>(cell_height);
+ do {
+ col_count++;
+ cell_width =
+ static_cast<float>(max_size_.width() -
+ ((col_count - 1) * kCellXPadding)) /
+ static_cast<float>(col_count);
+ cell_height = static_cast<float>(cell_width) / ratio;
+ row_count = std::max(1, (max_size_.height() + kCellYPadding) /
+ (cell_height + kCellYPadding));
+ } while (row_count * col_count < cell_count);
+ row_count = cell_count / col_count;
+ if (cell_count % col_count != 0)
+ row_count++;
+ }
+ }
+
+ cell_width_ = cell_width;
+ cell_height_ = cell_height;
+ columns_ = col_count;
+ rows_ = row_count;
+
+ pref_width_ =
+ std::max(0, col_count * (cell_width + kCellXPadding) - kCellXPadding);
+ pref_height_ =
+ std::max(0, row_count * (cell_height + kCellYPadding) - kCellYPadding);
+
+ for (int i = 0; i < cell_count; ++i) {
+ int row = i / columns_;
+ int col = i % columns_;
+ bounds->push_back(
+ gfx::Rect(col * cell_width_ + std::max(0, col * kCellXPadding),
+ row * cell_height_ + std::max(0, row * kCellYPadding),
+ cell_width_, cell_height_));
+ }
+}
+
+void Grid::CalculateTargetBoundsAndStartAnimation() {
+ if (needs_layout_)
+ Layout();
+
+ // Determine the current bounds.
+ start_bounds_.clear();
+ start_bounds_.resize(GetChildViewCount());
+ for (int i = 0; i < GetChildViewCount(); ++i)
+ start_bounds_[i] = GetChildViewAt(i)->bounds();
+
+ // Then the target bounds.
+ target_bounds_.clear();
+ CalculateCellBounds(&target_bounds_);
+
+ // And make sure the animation is running.
+ if (!animation_.IsAnimating()) {
+ animation_.Reset();
+ animation_.Show();
+ }
+}
+
+void Grid::SetViewBoundsToTarget() {
+ DCHECK(GetChildViewCount() == static_cast<int>(target_bounds_.size()));
+ for (size_t i = 0; i < target_bounds_.size(); ++i)
+ GetChildViewAt(i)->SetBounds(target_bounds_[i]);
+}
+
+int Grid::AnimationPosition(int start, int target) {
+ return start + static_cast<int>(
+ static_cast<double>(target - start) * animation_.GetCurrentValue());
+}
diff --git a/chrome/browser/views/tabs/grid.h b/chrome/browser/views/tabs/grid.h
new file mode 100644
index 0000000..491c1f3
--- /dev/null
+++ b/chrome/browser/views/tabs/grid.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_VIEWS_TABS_GRID_H_
+#define CHROME_BROWSER_VIEWS_TABS_GRID_H_
+
+#include <vector>
+
+#include "app/slide_animation.h"
+#include "base/gfx/rect.h"
+#include "views/view.h"
+
+// Grid is a view that positions its children (cells) in a grid. Grid
+// attempts to layout the children at their preferred size (assuming
+// all cells have the same preferred size) in a single row. If the sum
+// of the widths is greater than the max width, then a new row is
+// added. Once the max number of rows and columns are reached, the
+// cells are shrunk to fit.
+//
+// Grid offers methods to move, insert and remove cells. These end up changing
+// the child views, and animating the transition.
+class Grid : public views::View, public AnimationDelegate {
+ public:
+ Grid();
+
+ // Sets the max size for the Grid. See description above class for details.
+ void set_max_size(const gfx::Size& size) { max_size_ = size; }
+ const gfx::Size& max_size() const { return max_size_; }
+
+ // Moves the child view to the specified index, animating the move.
+ void MoveCell(int old_index, int new_index);
+
+ // Inserts a cell at the specified index, animating the insertion.
+ void InsertCell(int index, views::View* cell);
+
+ // Removes the cell at the specified index, animating the removal.
+ // WARNING: this does NOT delete the view, it's up to the caller to do that.
+ void RemoveCell(int index);
+
+ // Returns the number of columns.
+ int columns() const { return columns_; }
+
+ // Returns the number of rows.
+ int rows() const { return rows_; }
+
+ // Returns the width of a cell.
+ int cell_width() const { return cell_width_; }
+
+ // Returns the height of a cell.
+ int cell_height() const { return cell_height_; }
+
+ // View overrides.
+ virtual void ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child);
+ virtual gfx::Size GetPreferredSize();
+ virtual void Layout();
+
+ // AnimationDelegate overrides.
+ virtual void AnimationEnded(const Animation* animation);
+ virtual void AnimationProgressed(const Animation* animation);
+ virtual void AnimationCanceled(const Animation* animation);
+
+ // Padding between cells.
+ static const int kCellXPadding;
+ static const int kCellYPadding;
+
+ private:
+ // Calculates the bounds of each of the cells, adding the result to |bounds|.
+ void CalculateCellBounds(std::vector<gfx::Rect>* bounds);
+
+ // Resets start_bounds_ to the bounds of the current cells, and invokes
+ // CalculateCellBounds to determine the target bounds. Then starts the
+ // animation if it isn't already running.
+ void CalculateTargetBoundsAndStartAnimation();
+
+ // Resets the bounds of each cell to that of target_bounds_.
+ void SetViewBoundsToTarget();
+
+ // Returns the value based on the current animation. |start| gives the
+ // starting coordinate and |target| the target coordinate. The resulting
+ // value is between |start| and |target| based on the current animation.
+ int AnimationPosition(int start, int target);
+
+ // The animation.
+ SlideAnimation animation_;
+
+ // If true, we're adding/removing a child and can ignore the change in
+ // ViewHierarchyChanged.
+ bool modifying_children_;
+
+ // Do we need a layout? This is set to true any time a child is added/removed.
+ bool needs_layout_;
+
+ // Max size we layout to.
+ gfx::Size max_size_;
+
+ // Preferred size.
+ int pref_width_;
+ int pref_height_;
+
+ // Current cell size.
+ int cell_width_;
+ int cell_height_;
+
+ // Number of rows/columns.
+ int columns_;
+ int rows_;
+
+ // Used during animation, gives the initial bounds of the views.
+ std::vector<gfx::Rect> start_bounds_;
+
+ // Used during animation, gives the target bounds of the views.
+ std::vector<gfx::Rect> target_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(Grid);
+};
+
+#endif // CHROME_BROWSER_VIEWS_TABS_GRID_H_
diff --git a/chrome/browser/views/tabs/tab_overview_cell.cc b/chrome/browser/views/tabs/tab_overview_cell.cc
new file mode 100644
index 0000000..5d2b47f
--- /dev/null
+++ b/chrome/browser/views/tabs/tab_overview_cell.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2009 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/tab_overview_cell.h"
+
+#include "app/gfx/favicon_size.h"
+#include "base/string_util.h"
+#include "views/border.h"
+#include "views/controls/image_view.h"
+#include "views/controls/label.h"
+#include "views/grid_layout.h"
+
+using views::ColumnSet;
+using views::GridLayout;
+
+// Padding between the favicon and label.
+static const int kFavIconPadding = 4;
+
+// Height of the thumbnail.
+static const int kThumbnailHeight = 140;
+static const int kThumbnailWidth = 220;
+
+// Padding between favicon/title and thumbnail.
+static const int kVerticalPadding = 10;
+
+TabOverviewCell::TabOverviewCell() {
+ title_label_ = new views::Label();
+ title_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+
+ thumbnail_view_ = new views::ImageView();
+ thumbnail_view_->SetImageSize(gfx::Size(kThumbnailWidth, kThumbnailHeight));
+
+ fav_icon_view_ = new views::ImageView();
+ fav_icon_view_->SetImageSize(gfx::Size(kFavIconSize, kFavIconSize));
+
+ int title_cs_id = 0;
+ int thumbnail_cs_id = 1;
+ GridLayout* layout = new GridLayout(this);
+ SetLayoutManager(layout);
+ ColumnSet* columns = layout->AddColumnSet(title_cs_id);
+ columns->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
+ columns->AddPaddingColumn(0, kFavIconPadding);
+ columns->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
+ GridLayout::USE_PREF, 0, 0);
+
+ columns = layout->AddColumnSet(thumbnail_cs_id);
+ columns->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::USE_PREF, 0, 0);
+
+ layout->StartRow(0, title_cs_id);
+ layout->AddView(fav_icon_view_);
+ layout->AddView(title_label_);
+
+ layout->StartRowWithPadding(1, thumbnail_cs_id, 0, kVerticalPadding);
+ layout->AddView(thumbnail_view_);
+
+ thumbnail_view_->set_background(
+ views::Background::CreateSolidBackground(SK_ColorWHITE));
+
+ thumbnail_view_->set_border(
+ views::Border::CreateSolidBorder(1, SkColorSetRGB(176, 176, 176)));
+}
+
+void TabOverviewCell::SetThumbnail(const SkBitmap& thumbnail) {
+ thumbnail_view_->SetImage(thumbnail);
+}
+
+void TabOverviewCell::SetTitle(const string16& title) {
+ title_label_->SetText(UTF16ToWide(title));
+}
+
+void TabOverviewCell::SetFavIcon(const SkBitmap& favicon) {
+ fav_icon_view_->SetImage(favicon);
+}
+
+bool TabOverviewCell::IsPointInThumbnail(const gfx::Point& point) {
+ return thumbnail_view_->bounds().Contains(point);
+}
+
+gfx::Size TabOverviewCell::GetPreferredSize() {
+ // Force the preferred width to that of the thumbnail.
+ gfx::Size thumbnail_pref = thumbnail_view_->GetPreferredSize();
+ gfx::Size pref = View::GetPreferredSize();
+ pref.set_width(thumbnail_pref.width());
+ return pref;
+}
diff --git a/chrome/browser/views/tabs/tab_overview_cell.h b/chrome/browser/views/tabs/tab_overview_cell.h
new file mode 100644
index 0000000..b492972
--- /dev/null
+++ b/chrome/browser/views/tabs/tab_overview_cell.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_CELL_H_
+#define CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_CELL_H_
+
+#include "base/string16.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "views/view.h"
+
+namespace views {
+class ImageView;
+class Label;
+}
+
+// A single cell displayed by TabOverviewGrid. TabOverviewCell contains a
+// label, favicon and thumnbail.
+class TabOverviewCell : public views::View {
+ public:
+ TabOverviewCell();
+
+ void SetThumbnail(const SkBitmap& thumbnail);
+ void SetTitle(const string16& title);
+ void SetFavIcon(const SkBitmap& favicon);
+
+ // Returns true if the specified point, in the bounds of the cell, is over
+ // the thumbnail.
+ bool IsPointInThumbnail(const gfx::Point& point);
+
+ // View overrides.
+ virtual gfx::Size GetPreferredSize();
+
+ private:
+ views::Label* title_label_;
+ views::ImageView* thumbnail_view_;
+ views::ImageView* fav_icon_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabOverviewCell);
+};
+
+#endif // CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_CELL_H_
diff --git a/chrome/browser/views/tabs/tab_overview_container.cc b/chrome/browser/views/tabs/tab_overview_container.cc
new file mode 100644
index 0000000..d565261
--- /dev/null
+++ b/chrome/browser/views/tabs/tab_overview_container.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2009 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/tab_overview_container.h"
+
+#include <gtk/gtk.h>
+
+#include "app/gfx/canvas.h"
+#include "app/gfx/path.h"
+#include "chrome/browser/views/tabs/tab_overview_grid.h"
+#include "third_party/skia/include/effects/SkGradientShader.h"
+#include "views/widget/widget_gtk.h"
+
+// Padding between the edges of us and the grid.
+static const int kVerticalPadding = 43;
+static const int kHorizontalPadding = 30;
+
+// Height of the arrow.
+static const int kArrowHeight = 28;
+
+// Inset of the slight rounding on the corners.
+static const int kEdgeInset = 5;
+
+TabOverviewContainer::TabOverviewContainer() {
+}
+
+TabOverviewContainer::~TabOverviewContainer() {
+}
+
+void TabOverviewContainer::SetMaxSize(const gfx::Size& max_size) {
+ GetTabOverviewGrid()->set_max_size(
+ gfx::Size(max_size.width() - kHorizontalPadding * 2,
+ max_size.height() - kVerticalPadding * 2 - kArrowHeight));
+}
+
+void TabOverviewContainer::UpdateWidgetShape(int width, int height) {
+ int bottom_y = height - kArrowHeight;
+ int right_edge = width - 1;
+ int center = width / 2;
+ // The points in alternating x,y pairs.
+ int points[] = {
+ kEdgeInset, 0,
+ right_edge - kEdgeInset, 0,
+ right_edge, kEdgeInset,
+ right_edge, bottom_y - kEdgeInset - 1,
+ right_edge - kEdgeInset, bottom_y - 1,
+ center + kArrowHeight / 2, bottom_y - 1,
+ center, bottom_y - 1 + kArrowHeight,
+ center - kArrowHeight / 2, bottom_y - 1,
+ kEdgeInset, bottom_y - 1,
+ 0, bottom_y - 1 - kEdgeInset,
+ 0, kEdgeInset,
+ };
+ gfx::Path path;
+ path.moveTo(SkIntToScalar(points[0]), SkIntToScalar(points[1]));
+ for (size_t i = 2; i < arraysize(points); i += 2)
+ path.lineTo(SkIntToScalar(points[i]), SkIntToScalar(points[i + 1]));
+
+ GetWidget()->SetShape(path);
+}
+
+gfx::Size TabOverviewContainer::GetPreferredSize() {
+ gfx::Size tab_overview_pref = GetTabOverviewGrid()->GetPreferredSize();
+ return gfx::Size(kHorizontalPadding * 2 + tab_overview_pref.width(),
+ kVerticalPadding * 2 + tab_overview_pref.height() +
+ kArrowHeight);
+}
+
+void TabOverviewContainer::Layout() {
+ GetTabOverviewGrid()->SetBounds(kHorizontalPadding, kVerticalPadding,
+ width() - kHorizontalPadding * 2,
+ height() - kVerticalPadding * 2 -
+ kArrowHeight);
+}
+
+void TabOverviewContainer::Paint(gfx::Canvas* canvas) {
+ SkPoint points[] = { { SkIntToScalar(0), SkIntToScalar(0) },
+ { SkIntToScalar(0), SkIntToScalar(height()) } };
+ SkColor colors[] = { SkColorSetARGB(242, 255, 255, 255),
+ SkColorSetARGB(212, 255, 255, 255), };
+ SkShader* shader = SkGradientShader::CreateLinear(
+ points, colors, NULL, 2, SkShader::kRepeat_TileMode);
+ SkPaint paint;
+ paint.setShader(shader);
+ shader = NULL;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setPorterDuffXfermode(SkPorterDuff::kSrcOver_Mode);
+ canvas->drawPaint(paint);
+}
+
+void TabOverviewContainer::DidChangeBounds(const gfx::Rect& previous,
+ const gfx::Rect& current) {
+ Layout();
+}
+
+TabOverviewGrid* TabOverviewContainer::GetTabOverviewGrid() {
+ return static_cast<TabOverviewGrid*>(GetChildViewAt(0));
+}
diff --git a/chrome/browser/views/tabs/tab_overview_container.h b/chrome/browser/views/tabs/tab_overview_container.h
new file mode 100644
index 0000000..119fde4
--- /dev/null
+++ b/chrome/browser/views/tabs/tab_overview_container.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_CONTAINER_H_
+#define CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_CONTAINER_H_
+
+#include "views/view.h"
+
+class TabOverviewGrid;
+
+// TabOverviewContainer contains TabOverviewGrid. TabOverviewContainer provides
+// padding around the grid as well as maintaining a shape on the containing
+// widget.
+class TabOverviewContainer : public views::View {
+ public:
+ TabOverviewContainer();
+ virtual ~TabOverviewContainer();
+
+ // Sets the max size. This ends up being passed down to the grid after
+ // adjusting for our borders.
+ void SetMaxSize(const gfx::Size& max_size);
+
+ // Updates the shape on the containing widget.
+ void UpdateWidgetShape(int width, int height);
+
+ // View overrides.
+ virtual gfx::Size GetPreferredSize();
+ virtual void Layout();
+ virtual void Paint(gfx::Canvas* canvas);
+ virtual void DidChangeBounds(const gfx::Rect& previous,
+ const gfx::Rect& current);
+
+ private:
+ TabOverviewGrid* GetTabOverviewGrid();
+
+ DISALLOW_COPY_AND_ASSIGN(TabOverviewContainer);
+};
+
+#endif // CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_CONTAINER_H_
diff --git a/chrome/browser/views/tabs/tab_overview_controller.cc b/chrome/browser/views/tabs/tab_overview_controller.cc
new file mode 100644
index 0000000..1d35fb3
--- /dev/null
+++ b/chrome/browser/views/tabs/tab_overview_controller.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2009 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/tab_overview_controller.h"
+
+#include "chrome/browser/views/tabs/tab_overview_container.h"
+#include "chrome/browser/window_sizer.h"
+#include "views/fill_layout.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget_gtk.h"
+
+static int kMonitorPadding = 20;
+static int kInteriorPadding = 20;
+
+TabOverviewController::TabOverviewController(
+ const gfx::Point& monitor_origin)
+ : model_(NULL) {
+ view_ = new TabOverviewGrid();
+ view_->set_host(this);
+
+ // Create the host.
+ views::WidgetGtk* host = new views::WidgetGtk(views::WidgetGtk::TYPE_POPUP);
+ host->set_delete_on_destroy(false);
+ host->MakeTransparent();
+ host->Init(NULL, gfx::Rect(), true);
+ host_.reset(host);
+
+ container_ = new TabOverviewContainer();
+ container_->AddChildView(view_);
+ host->GetRootView()->SetLayoutManager(new views::FillLayout());
+ host->GetRootView()->AddChildView(container_);
+
+ // Determine the bounds we're going to show at.
+ scoped_ptr<WindowSizer::MonitorInfoProvider> provider(
+ WindowSizer::CreateDefaultMonitorInfoProvider());
+ monitor_bounds_ = provider->GetMonitorWorkAreaMatching(
+ gfx::Rect(monitor_origin.x(), monitor_origin.y(), 1, 1));
+ int max_width = monitor_bounds_.width() - kMonitorPadding * 2 -
+ kInteriorPadding * 2;
+ int max_height = monitor_bounds_.height() / 2;
+ container_->SetMaxSize(gfx::Size(max_width, max_height));
+}
+
+TabOverviewController::~TabOverviewController() {
+}
+
+void TabOverviewController::SetTabStripModel(TabStripModel* tab_strip_model) {
+ model_ = tab_strip_model;
+ view_->SetTabStripModel(tab_strip_model);
+}
+
+void TabOverviewController::Show() {
+ if (host_->IsVisible())
+ return;
+
+ DCHECK(view_->model()); // The model needs to be set before showing.
+ host_->Show();
+}
+
+void TabOverviewController::Hide() {
+ host_->Hide();
+}
+
+void TabOverviewController::TabOverviewGridPreferredSizeChanged() {
+ gfx::Size pref = container_->GetPreferredSize();
+ int x = monitor_bounds_.x() + (monitor_bounds_.width() - pref.width()) / 2;
+ int y = monitor_bounds_.y() + monitor_bounds_.height() / 2 - pref.height();
+ host_->SetBounds(gfx::Rect(x, y, pref.width(), pref.height()));
+
+ container_->UpdateWidgetShape(pref.width(), pref.height());
+}
+
+void TabOverviewController::SelectTabContents(TabContents* contents) {
+ NOTIMPLEMENTED();
+}
diff --git a/chrome/browser/views/tabs/tab_overview_controller.h b/chrome/browser/views/tabs/tab_overview_controller.h
new file mode 100644
index 0000000..911b5cf
--- /dev/null
+++ b/chrome/browser/views/tabs/tab_overview_controller.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_CONTROLLER_H_
+#define CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_CONTROLLER_H_
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/views/tabs/tab_overview_grid.h"
+
+class TabOverviewContainer;
+class TabStripModel;
+
+namespace views {
+class Widget;
+}
+namespace gfx {
+class Point;
+}
+
+// TabOverviewController is responsible for showing a TabOverviewGrid.
+class TabOverviewController : public TabOverviewGrid::Host {
+ public:
+ // Creates a TabOverviewController that will be shown on the monitor
+ // containing |monitor_origin|.
+ explicit TabOverviewController(const gfx::Point& monitor_origin);
+ ~TabOverviewController();
+
+ // Sets the tarb strip to show.
+ void SetTabStripModel(TabStripModel* tab_strip_model);
+
+ // Shows/hides the grid.
+ void Show();
+ void Hide();
+
+ // TabOverviewGrid::Host overrides.
+ virtual void TabOverviewGridPreferredSizeChanged();
+ virtual void SelectTabContents(TabContents* contents);
+
+ private:
+ // The widget showing the view.
+ scoped_ptr<views::Widget> host_;
+
+ // Bounds of the monitor we're being displayed on. This is used to position
+ // the widget.
+ gfx::Rect monitor_bounds_;
+
+ // View containing the grid, owned by host.
+ TabOverviewContainer* container_;
+
+ // The view. This is owned by host.
+ TabOverviewGrid* view_;
+
+ // The model, not owned by us.
+ TabStripModel* model_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabOverviewController);
+};
+
+#endif // CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_CONTROLLER_H_
diff --git a/chrome/browser/views/tabs/tab_overview_grid.cc b/chrome/browser/views/tabs/tab_overview_grid.cc
new file mode 100644
index 0000000..e04f1a7
--- /dev/null
+++ b/chrome/browser/views/tabs/tab_overview_grid.cc
@@ -0,0 +1,200 @@
+// Copyright (c) 2009 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/tab_overview_grid.h"
+
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/views/tabs/tab_overview_cell.h"
+#include "views/widget/root_view.h"
+
+TabOverviewGrid::TabOverviewGrid()
+ : model_(NULL),
+ host_(NULL) {
+}
+
+TabOverviewGrid::~TabOverviewGrid() {
+ RemoveListeners();
+ model_ = NULL;
+}
+
+void TabOverviewGrid::SetTabStripModel(TabStripModel* tab_strip_model) {
+ if (tab_strip_model == model_)
+ return;
+
+ RemoveListeners();
+ model_ = tab_strip_model;
+ AddListeners();
+ Recreate();
+}
+
+void TabOverviewGrid::TabInsertedAt(TabContents* contents,
+ int index,
+ bool foreground) {
+ drag_info_ = DragInfo();
+
+ TabOverviewCell* child = new TabOverviewCell();
+ ConfigureChild(child, index);
+ InsertCell(index, child);
+
+ TabCountChanged();
+}
+
+void TabOverviewGrid::TabClosingAt(TabContents* contents, int index) {
+ // Nothing to do, we only care when the tab is actually detached.
+}
+
+void TabOverviewGrid::TabDetachedAt(TabContents* contents, int index) {
+ drag_info_ = DragInfo();
+
+ scoped_ptr<TabOverviewCell> child(GetTabOverviewCellAt(index));
+ RemoveCell(index);
+
+ TabCountChanged();
+}
+
+void TabOverviewGrid::TabMoved(TabContents* contents,
+ int from_index,
+ int to_index) {
+ if (!drag_info_.moving_tab)
+ drag_info_ = DragInfo();
+
+ MoveCell(from_index, to_index);
+}
+
+void TabOverviewGrid::TabChangedAt(TabContents* contents, int index,
+ bool loading_only) {
+ ConfigureChild(GetTabOverviewCellAt(index), index);
+}
+
+void TabOverviewGrid::TabStripEmpty() {
+ SetTabStripModel(NULL);
+}
+
+bool TabOverviewGrid::OnMousePressed(const views::MouseEvent& event) {
+ drag_info_ = DragInfo();
+ TabOverviewCell* cell = NULL;
+ for (int i = 0; i < GetChildViewCount(); ++i) {
+ View* child = GetChildViewAt(i);
+ if (child->bounds().Contains(event.location())) {
+ drag_info_.index = i;
+ cell = static_cast<TabOverviewCell*>(child);
+ break;
+ }
+ }
+ if (!cell)
+ return false;
+ gfx::Point cell_point(event.location());
+ ConvertPointToView(this, cell, &cell_point);
+ if (!cell->IsPointInThumbnail(cell_point))
+ return false;
+
+ drag_info_.origin = event.location();
+ return true;
+}
+
+bool TabOverviewGrid::OnMouseDragged(const views::MouseEvent& event) {
+ if (drag_info_.index >= 0 && !drag_info_.dragging &&
+ ExceededDragThreshold(event.location().x() - drag_info_.origin.x(),
+ event.location().y() - drag_info_.origin.y())) {
+ // Start dragging.
+ drag_info_.dragging = true;
+ }
+ if (drag_info_.dragging)
+ UpdateDrag(event.location());
+ return true;
+}
+
+void TabOverviewGrid::OnMouseReleased(const views::MouseEvent& event,
+ bool canceled) {
+ if (host_ && !drag_info_.dragging && drag_info_.index != -1)
+ host_->SelectTabContents(model_->GetTabContentsAt(drag_info_.index));
+}
+
+void TabOverviewGrid::AddListeners() {
+ if (model_)
+ model_->AddObserver(this);
+}
+
+void TabOverviewGrid::RemoveListeners() {
+ if (model_)
+ model_->RemoveObserver(this);
+}
+
+void TabOverviewGrid::Recreate() {
+ RemoveAllChildViews(true);
+
+ if (model_) {
+ for (int i = 0; i < model_->count(); ++i) {
+ TabOverviewCell* child = new TabOverviewCell();
+ ConfigureChild(child, i);
+ AddChildView(child);
+ }
+ }
+ TabCountChanged();
+}
+
+TabOverviewCell* TabOverviewGrid::GetTabOverviewCellAt(int index) {
+ return static_cast<TabOverviewCell*>(GetChildViewAt(index));
+}
+
+void TabOverviewGrid::ConfigureChild(TabOverviewCell* child, int index) {
+ // TODO: need to set thumbnail here.
+ TabContents* tab_contents = model_->GetTabContentsAt(index);
+ if (tab_contents) {
+ child->SetTitle(tab_contents->GetTitle());
+ child->SetFavIcon(tab_contents->GetFavIcon());
+ child->SchedulePaint();
+ } else {
+ // Need to figure out under what circumstances this is null and deal.
+ NOTIMPLEMENTED();
+ }
+}
+
+void TabOverviewGrid::TabCountChanged() {
+ if (host_)
+ host_->TabOverviewGridPreferredSizeChanged();
+}
+
+void TabOverviewGrid::UpdateDrag(const gfx::Point& location) {
+ int row = 0;
+ int col = 0;
+ gfx::Rect local_bounds = GetLocalBounds(true);
+ if (!local_bounds.Contains(location)) {
+ // Local bounds doesn't contain the point, allow dragging to the left/right
+ // of us to equal to before/after last cell.
+ views::RootView* root = GetRootView();
+ gfx::Point root_point = location;
+ views::View::ConvertPointToView(this, root, &root_point);
+ gfx::Rect root_bounds = root->GetLocalBounds(true);
+ if (!root->bounds().Contains(root_point)) {
+ // The user dragged outside the grid, remove the cell.
+ return;
+ }
+ if (location.x() < 0)
+ col = 0;
+ else if (location.x() >= width())
+ col = columns();
+ else
+ col = (location.x() + cell_width() / 2) / (cell_width() + kCellXPadding);
+ if (location.y() < 0)
+ row = 0;
+ else if (location.y() >= height())
+ row = rows();
+ else
+ row = location.y() / (cell_height() + kCellYPadding);
+ } else {
+ // We contain the point in our bounds.
+ col = (location.x() + cell_width() / 2) / (cell_width() + kCellXPadding);
+ row = location.y() / (cell_height() + kCellYPadding);
+ }
+ int new_index = std::min(model_->count() - 1, row * columns() + col);
+ if (new_index == drag_info_.index)
+ return;
+ drag_info_.moving_tab = true;
+ model_->MoveTabContentsAt(drag_info_.index, new_index, false);
+ drag_info_.moving_tab = false;
+ drag_info_.index = new_index;
+
+ // TODO: need to handle dragging outside of window.
+}
diff --git a/chrome/browser/views/tabs/tab_overview_grid.h b/chrome/browser/views/tabs/tab_overview_grid.h
new file mode 100644
index 0000000..a7a8ec6
--- /dev/null
+++ b/chrome/browser/views/tabs/tab_overview_grid.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_GRID_H_
+#define CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_GRID_H_
+
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/views/tabs/grid.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "views/view.h"
+
+class TabOverviewCell;
+
+// TabOverviewGrid is used to provide a grid view of the contents of a tab
+// strip model. Each cell of the grid is a TabOverviewCell.
+class TabOverviewGrid : public Grid, public TabStripModelObserver {
+ public:
+
+ class Host {
+ public:
+ // Invoked when the preferred size of the TabOverviewGrid changes. The
+ // preferred size changes any the contents of the tab strip changes.
+ virtual void TabOverviewGridPreferredSizeChanged() = 0;
+
+ // Invoked when the user selects a cell in the grid.
+ virtual void SelectTabContents(TabContents* contents) = 0;
+
+ protected:
+ ~Host() {}
+ };
+
+ TabOverviewGrid();
+ virtual ~TabOverviewGrid();
+
+ // Sets the host.
+ void set_host(Host* host) { host_ = host; }
+
+ // The contents of the TabOverviewGrid are driven by that of the model.
+ void SetTabStripModel(TabStripModel* tab_strip_model);
+ TabStripModel* model() const { return model_; }
+
+ // TabStripModelObserver overrides.
+ virtual void TabInsertedAt(TabContents* contents,
+ int index,
+ bool foreground);
+ virtual void TabClosingAt(TabContents* contents, int index);
+ virtual void TabDetachedAt(TabContents* contents, int index);
+ virtual void TabMoved(TabContents* contents,
+ int from_index,
+ int to_index);
+ virtual void TabChangedAt(TabContents* contents, int index,
+ bool loading_only);
+ virtual void TabStripEmpty();
+ // Currently don't care about these as we're not rendering the selection.
+ virtual void TabDeselectedAt(TabContents* contents, int index) { }
+ virtual void TabSelectedAt(TabContents* old_contents,
+ TabContents* new_contents,
+ int index,
+ bool user_gesture) { }
+
+ // View overrides.
+ virtual bool OnMousePressed(const views::MouseEvent& event);
+ virtual bool OnMouseDragged(const views::MouseEvent& event);
+ virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled);
+
+ private:
+ // DragInfo is used when the user presses the mouse on the grid. It indicates
+ // where the press occurred and whether the user is dragging the mouse.
+ struct DragInfo {
+ DragInfo() : index(-1), dragging(false) {}
+
+ // The index the user pressed that mouse at. If -1, the user didn't press
+ // on a valid location.
+ int index;
+
+ // Has the user started dragging?
+ bool dragging;
+
+ // The origin of the click.
+ gfx::Point origin;
+
+ // If true, we're moving the tab in the model. This is used to avoid
+ // resetting DragInfo when the model changes.
+ bool moving_tab;
+ };
+
+ void AddListeners();
+ void RemoveListeners();
+
+ // Recreates the contents of the grid from that of the model.
+ void Recreate();
+
+ // Returns the TabOverviewCell at the specified index.
+ TabOverviewCell* GetTabOverviewCellAt(int index);
+
+ // Configures a cell from the model.
+ void ConfigureChild(TabOverviewCell* child, int index);
+
+ // Invoked when the count of the model changes. Notifies the host the pref
+ // size changed.
+ void TabCountChanged();
+
+ // Updates |drag_info_| based on |location|.
+ void UpdateDrag(const gfx::Point& location);
+
+ TabStripModel* model_;
+
+ Host* host_;
+
+ DragInfo drag_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabOverviewGrid);
+};
+
+#endif // CHROME_BROWSER_VIEWS_TABS_TAB_OVERVIEW_GRID_H_
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index a0b24c4..02e1860 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1545,6 +1545,8 @@
'browser/views/tabs/dragged_tab_controller.h',
'browser/views/tabs/dragged_tab_view.cc',
'browser/views/tabs/dragged_tab_view.h',
+ 'browser/views/tabs/grid.cc',
+ 'browser/views/tabs/grid.h',
'browser/views/tabs/native_view_photobooth.h',
'browser/views/tabs/native_view_photobooth_gtk.cc',
'browser/views/tabs/native_view_photobooth_gtk.h',
@@ -1552,6 +1554,14 @@
'browser/views/tabs/native_view_photobooth_win.h',
'browser/views/tabs/tab.cc',
'browser/views/tabs/tab.h',
+ 'browser/views/tabs/tab_overview_cell.cc',
+ 'browser/views/tabs/tab_overview_cell.h',
+ 'browser/views/tabs/tab_overview_container.cc',
+ 'browser/views/tabs/tab_overview_container.h',
+ 'browser/views/tabs/tab_overview_grid.cc',
+ 'browser/views/tabs/tab_overview_grid.h',
+ 'browser/views/tabs/tab_overview_controller.cc',
+ 'browser/views/tabs/tab_overview_controller.h',
'browser/views/tabs/tab_renderer.cc',
'browser/views/tabs/tab_renderer.h',
'browser/views/tabs/tab_strip.cc',
@@ -1716,6 +1726,16 @@
'browser/password_manager/password_store_gnome.cc',
'browser/password_manager/password_store_kwallet.h',
'browser/password_manager/password_store_kwallet.cc',
+ 'browser/views/tabs/grid.cc',
+ 'browser/views/tabs/grid.h',
+ 'browser/views/tabs/tab_overview_child.cc',
+ 'browser/views/tabs/tab_overview_child.h',
+ 'browser/views/tabs/tab_overview_container.cc',
+ 'browser/views/tabs/tab_overview_container.h',
+ 'browser/views/tabs/tab_overview_controller.cc',
+ 'browser/views/tabs/tab_overview_controller.h',
+ 'browser/views/tabs/tab_overview_grid.cc',
+ 'browser/views/tabs/tab_overview_grid.h',
],
'configurations': {
'Debug': {
@@ -1837,6 +1857,20 @@
['exclude', '^browser/bookmarks/bookmark_context_menu_gtk.cc'],
],
}],
+ ['linux2==1',{
+ 'sources/': [
+ ['include', 'browser/views/tabs/grid.cc'],
+ ['include', 'browser/views/tabs/grid.h'],
+ ['include', 'browser/views/tabs/tab_overview_cell.cc'],
+ ['include', 'browser/views/tabs/tab_overview_cell.h'],
+ ['include', 'browser/views/tabs/tab_overview_container.cc'],
+ ['include', 'browser/views/tabs/tab_overview_container.h'],
+ ['include', 'browser/views/tabs/tab_overview_controller.cc'],
+ ['include', 'browser/views/tabs/tab_overview_controller.h'],
+ ['include', 'browser/views/tabs/tab_overview_grid.cc'],
+ ['include', 'browser/views/tabs/tab_overview_grid.h'],
+ ],
+ }],
],
# Exclude files that should be excluded for all non-Windows platforms.
'sources!': [