diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-08 23:23:05 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-08 23:23:05 +0000 |
commit | 37cd3a96b55aac1dad9016c05e78b5983972f985 (patch) | |
tree | 1159bb8897fa21faeadde942163412736889ead9 /chrome | |
parent | 4d4c0b94960366979943dbe4e3c8880ce80dbdef (diff) | |
download | chromium_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.cc | 213 | ||||
-rw-r--r-- | chrome/browser/views/tabs/grid.h | 120 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_overview_cell.cc | 88 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_overview_cell.h | 42 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_overview_container.cc | 99 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_overview_container.h | 40 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_overview_controller.cc | 76 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_overview_controller.h | 60 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_overview_grid.cc | 200 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_overview_grid.h | 116 | ||||
-rw-r--r-- | chrome/chrome.gyp | 34 |
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!': [ |