| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/cocoa/tabpose_window.h" | 5 #import "chrome/browser/cocoa/tabpose_window.h" |
| 6 | 6 |
| 7 #import <QuartzCore/QuartzCore.h> | 7 #import <QuartzCore/QuartzCore.h> |
| 8 | 8 |
| 9 #include "app/resource_bundle.h" |
| 10 #include "base/mac_util.h" |
| 11 #include "base/sys_string_conversions.h" |
| 9 #import "chrome/browser/cocoa/browser_window_controller.h" | 12 #import "chrome/browser/cocoa/browser_window_controller.h" |
| 10 #import "chrome/browser/cocoa/tab_strip_controller.h" | 13 #import "chrome/browser/cocoa/tab_strip_controller.h" |
| 14 #include "chrome/browser/tab_contents/tab_contents.h" |
| 15 #include "grit/app_resources.h" |
| 16 #include "skia/ext/skia_utils_mac.h" |
| 11 | 17 |
| 12 const int kTopGradientHeight = 15; | 18 const int kTopGradientHeight = 15; |
| 13 | 19 |
| 14 NSString* const kAnimationIdKey = @"AnimationId"; | 20 NSString* const kAnimationIdKey = @"AnimationId"; |
| 15 NSString* const kAnimationIdFadeIn = @"FadeIn"; | 21 NSString* const kAnimationIdFadeIn = @"FadeIn"; |
| 16 NSString* const kAnimationIdFadeOut = @"FadeOut"; | 22 NSString* const kAnimationIdFadeOut = @"FadeOut"; |
| 17 | 23 |
| 18 const CGFloat kDefaultAnimationDuration = 0.25; // In seconds. | 24 const CGFloat kDefaultAnimationDuration = 0.25; // In seconds. |
| 19 const CGFloat kSlomoFactor = 4; | 25 const CGFloat kSlomoFactor = 4; |
| 20 | 26 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 // title, favicon, thumbnail image, and pre- and postanimation rects. | 108 // title, favicon, thumbnail image, and pre- and postanimation rects. |
| 103 // TODO(thakis): Right now, it only consists of a thumb rect. | 109 // TODO(thakis): Right now, it only consists of a thumb rect. |
| 104 class Tile { | 110 class Tile { |
| 105 public: | 111 public: |
| 106 // Returns the rectangle this thumbnail is at at the beginning of the zoom-in | 112 // Returns the rectangle this thumbnail is at at the beginning of the zoom-in |
| 107 // animation. |tile| is the rectangle that's covering the whole tab area when | 113 // animation. |tile| is the rectangle that's covering the whole tab area when |
| 108 // the animation starts. | 114 // the animation starts. |
| 109 NSRect GetStartRectRelativeTo(const Tile& tile) const; | 115 NSRect GetStartRectRelativeTo(const Tile& tile) const; |
| 110 NSRect thumb_rect() const { return thumb_rect_; } | 116 NSRect thumb_rect() const { return thumb_rect_; } |
| 111 | 117 |
| 118 NSRect favicon_rect() const { return favicon_rect_; } |
| 119 SkBitmap favicon() const; |
| 120 |
| 121 // This changes |title_rect| and |favicon_rect| such that the favicon is on |
| 122 // the font's baseline and that the minimum distance between thumb rect and |
| 123 // favicon and title rects doesn't change. |
| 124 // The view code |
| 125 // 1. queries desired font size by calling |title_font_size()| |
| 126 // 2. loads that font |
| 127 // 3. calls |set_font_metrics()| which updates the title rect |
| 128 // 4. receives the title rect and puts the title on it with the font from 2. |
| 129 void set_font_metrics(CGFloat ascender, CGFloat descender); |
| 130 CGFloat title_font_size() const { return title_font_size_; } |
| 131 |
| 132 NSRect title_rect() const { return title_rect_; } |
| 133 |
| 134 // Returns an unelided title. The view logic is responsible for eliding. |
| 135 const string16& title() const { return contents_->GetTitle(); } |
| 112 private: | 136 private: |
| 113 friend class TileSet; | 137 friend class TileSet; |
| 114 | 138 |
| 115 // The thumb rect includes infobars, detached thumbnail bar, web contents, | 139 // The thumb rect includes infobars, detached thumbnail bar, web contents, |
| 116 // and devtools. | 140 // and devtools. |
| 117 NSRect thumb_rect_; | 141 NSRect thumb_rect_; |
| 118 NSRect start_thumb_rect_; | 142 NSRect start_thumb_rect_; |
| 143 |
| 144 NSRect favicon_rect_; |
| 145 |
| 146 CGFloat title_font_size_; |
| 147 NSRect title_rect_; |
| 148 |
| 149 TabContents* contents_; // weak |
| 119 }; | 150 }; |
| 120 | 151 |
| 121 NSRect Tile::GetStartRectRelativeTo(const Tile& tile) const { | 152 NSRect Tile::GetStartRectRelativeTo(const Tile& tile) const { |
| 122 NSRect rect = start_thumb_rect_; | 153 NSRect rect = start_thumb_rect_; |
| 123 rect.origin.x -= tile.start_thumb_rect_.origin.x; | 154 rect.origin.x -= tile.start_thumb_rect_.origin.x; |
| 124 rect.origin.y -= tile.start_thumb_rect_.origin.y; | 155 rect.origin.y -= tile.start_thumb_rect_.origin.y; |
| 125 return rect; | 156 return rect; |
| 126 } | 157 } |
| 127 | 158 |
| 159 SkBitmap Tile::favicon() const { |
| 160 if (contents_->is_app()) { |
| 161 SkBitmap* icon = contents_->GetExtensionAppIcon(); |
| 162 if (icon) |
| 163 return *icon; |
| 164 } |
| 165 return contents_->GetFavIcon(); |
| 166 } |
| 167 |
| 168 // Changes |title_rect| and |favicon_rect| such that the favicon is on the |
| 169 // font's baseline and that the minimum distance between thumb rect and |
| 170 // favicon and title rects doesn't change. |
| 171 void Tile::set_font_metrics(CGFloat ascender, CGFloat descender) { |
| 172 title_rect_.origin.y -= ascender + descender - NSHeight(title_rect_); |
| 173 title_rect_.size.height = ascender + descender; |
| 174 |
| 175 if (NSHeight(favicon_rect_) < ascender) { |
| 176 // Move favicon down. |
| 177 favicon_rect_.origin.y = title_rect_.origin.y + descender; |
| 178 } else { |
| 179 // Move title down. |
| 180 title_rect_.origin.y = favicon_rect_.origin.y - descender; |
| 181 } |
| 182 } |
| 183 |
| 128 // A tileset is responsible for owning and laying out all |Tile|s shown in a | 184 // A tileset is responsible for owning and laying out all |Tile|s shown in a |
| 129 // tabpose window. | 185 // tabpose window. |
| 130 class TileSet { | 186 class TileSet { |
| 131 public: | 187 public: |
| 132 // Fills in |tiles_|. | 188 // Fills in |tiles_|. |
| 133 void Build(TabStripModel* source_model); | 189 void Build(TabStripModel* source_model); |
| 134 | 190 |
| 135 // Computes coordinates for |tiles_|. | 191 // Computes coordinates for |tiles_|. |
| 136 void Layout(NSRect containing_rect); | 192 void Layout(NSRect containing_rect); |
| 137 | 193 |
| 138 int selected_index() const { return selected_index_; } | 194 int selected_index() const { return selected_index_; } |
| 139 void set_selected_index(int index); | 195 void set_selected_index(int index); |
| 140 void ResetSelectedIndex() { selected_index_ = initial_index_; } | 196 void ResetSelectedIndex() { selected_index_ = initial_index_; } |
| 141 | 197 |
| 142 const Tile& selected_tile() const { return tiles_[selected_index()]; } | 198 const Tile& selected_tile() const { return *tiles_[selected_index()]; } |
| 143 const Tile& tile_at(int index) const { return tiles_[index]; } | 199 Tile& tile_at(int index) { return *tiles_[index]; } |
| 200 const Tile& tile_at(int index) const { return *tiles_[index]; } |
| 144 | 201 |
| 145 private: | 202 private: |
| 146 std::vector<Tile> tiles_; // Doesn't change often, hence values are fine. | 203 std::vector<Tile*> tiles_; |
| 147 | 204 |
| 148 int selected_index_; | 205 int selected_index_; |
| 149 int initial_index_; | 206 int initial_index_; |
| 150 }; | 207 }; |
| 151 | 208 |
| 152 void TileSet::Build(TabStripModel* source_model) { | 209 void TileSet::Build(TabStripModel* source_model) { |
| 153 selected_index_ = initial_index_ = source_model->selected_index(); | 210 selected_index_ = initial_index_ = source_model->selected_index(); |
| 154 tiles_.resize(source_model->count()); | 211 tiles_.resize(source_model->count()); |
| 212 for (size_t i = 0; i < tiles_.size(); ++i) { |
| 213 tiles_[i] = new Tile; |
| 214 tiles_[i]->contents_ = source_model->GetTabContentsAt(i); |
| 215 } |
| 155 } | 216 } |
| 156 | 217 |
| 157 void TileSet::Layout(NSRect containing_rect) { | 218 void TileSet::Layout(NSRect containing_rect) { |
| 158 int tile_count = tiles_.size(); | 219 int tile_count = tiles_.size(); |
| 159 | 220 |
| 160 // Room around the tiles insde of |containing_rect|. | 221 // Room around the tiles insde of |containing_rect|. |
| 161 const int kSmallPaddingTop = 30; | 222 const int kSmallPaddingTop = 30; |
| 162 const int kSmallPaddingLeft = 30; | 223 const int kSmallPaddingLeft = 30; |
| 163 const int kSmallPaddingRight = 30; | 224 const int kSmallPaddingRight = 30; |
| 164 const int kSmallPaddingBottom = 30; | 225 const int kSmallPaddingBottom = 30; |
| 165 | 226 |
| 227 // Favicon / title area. |
| 228 const int kThumbTitlePaddingY = 6; |
| 229 const int kFaviconSize = 16; |
| 230 const int kTitleHeight = 14; // Font size. |
| 231 const int kTitleExtraHeight = kThumbTitlePaddingY + kTitleHeight; |
| 232 const int kFaviconExtraHeight = kThumbTitlePaddingY + kFaviconSize; |
| 233 const int kFaviconTitleDistanceX = 6; |
| 234 const int kFooterExtraHeight = |
| 235 std::max(kFaviconExtraHeight, kTitleExtraHeight); |
| 236 |
| 166 // Room between the tiles. | 237 // Room between the tiles. |
| 167 const int kSmallPaddingX = 15; | 238 const int kSmallPaddingX = 15; |
| 168 const int kSmallPaddingY = 13; | 239 const int kSmallPaddingY = kFooterExtraHeight; |
| 169 | 240 |
| 170 // Aspect ratio of the containing rect. | 241 // Aspect ratio of the containing rect. |
| 171 CGFloat aspect = NSWidth(containing_rect) / NSHeight(containing_rect); | 242 CGFloat aspect = NSWidth(containing_rect) / NSHeight(containing_rect); |
| 172 | 243 |
| 173 // Room left in container after the outer padding is removed. | 244 // Room left in container after the outer padding is removed. |
| 174 double container_width = | 245 double container_width = |
| 175 NSWidth(containing_rect) - kSmallPaddingLeft - kSmallPaddingRight; | 246 NSWidth(containing_rect) - kSmallPaddingLeft - kSmallPaddingRight; |
| 176 double container_height = | 247 double container_height = |
| 177 NSHeight(containing_rect) - kSmallPaddingTop - kSmallPaddingBottom; | 248 NSHeight(containing_rect) - kSmallPaddingTop - kSmallPaddingBottom; |
| 178 | 249 |
| 179 // The tricky part is figuring out the size of a tab thumbnail, or since the | 250 // The tricky part is figuring out the size of a tab thumbnail, or since the |
| 180 // size of the containing rect is known, the number of tiles in x and y | 251 // size of the containing rect is known, the number of tiles in x and y |
| 181 // direction. | 252 // direction. |
| 182 // Given are the size of the containing rect, and the number of thumbnails | 253 // Given are the size of the containing rect, and the number of thumbnails |
| 183 // that need to fit into that rect. The aspect ratio of the thumbnails needs | 254 // that need to fit into that rect. The aspect ratio of the thumbnails needs |
| 184 // to be the same as that of |containing_rect|, else they will look distorted. | 255 // to be the same as that of |containing_rect|, else they will look distorted. |
| 185 // The thumbnails need to be distributed such that | 256 // The thumbnails need to be distributed such that |
| 186 // |count_x * count_y >= tile_count|, and such that wasted space is minimized. | 257 // |count_x * count_y >= tile_count|, and such that wasted space is minimized. |
| 187 // See the comments in | 258 // See the comments in |
| 188 // |FitNRectsWithAspectIntoBoundingSizeWithConstantPadding()| for a more | 259 // |FitNRectsWithAspectIntoBoundingSizeWithConstantPadding()| for a more |
| 189 // detailed discussion. | 260 // detailed discussion. |
| 190 // TODO(thakis): It might be good enough to choose |count_x| and |count_y| | 261 // TODO(thakis): It might be good enough to choose |count_x| and |count_y| |
| 191 // such that count_x / count_y is roughly equal to |aspect|? | 262 // such that count_x / count_y is roughly equal to |aspect|? |
| 192 double fny = FitNRectsWithAspectIntoBoundingSizeWithConstantPadding( | 263 double fny = FitNRectsWithAspectIntoBoundingSizeWithConstantPadding( |
| 193 tile_count, aspect, container_width, container_height, | 264 tile_count, aspect, |
| 194 kSmallPaddingX, kSmallPaddingY); | 265 container_width, container_height - kFooterExtraHeight, |
| 266 kSmallPaddingX, kSmallPaddingY + kFooterExtraHeight); |
| 195 int count_y(roundf(fny)); | 267 int count_y(roundf(fny)); |
| 196 int count_x(ceilf(tile_count / float(count_y))); | 268 int count_x(ceilf(tile_count / float(count_y))); |
| 197 int last_row_count_x = tile_count - count_x * (count_y - 1); | 269 int last_row_count_x = tile_count - count_x * (count_y - 1); |
| 198 | 270 |
| 199 // Now that |count_x| and |count_y| are known, it's straightforward to compute | 271 // Now that |count_x| and |count_y| are known, it's straightforward to compute |
| 200 // thumbnail width/height. See comment in | 272 // thumbnail width/height. See comment in |
| 201 // |FitNRectsWithAspectIntoBoundingSizeWithConstantPadding| for the derivation | 273 // |FitNRectsWithAspectIntoBoundingSizeWithConstantPadding| for the derivation |
| 202 // of these two formulas. | 274 // of these two formulas. |
| 203 int small_width = | 275 int small_width = |
| 204 floor((container_width + kSmallPaddingX) / float(count_x) - | 276 floor((container_width + kSmallPaddingX) / float(count_x) - |
| 205 kSmallPaddingX); | 277 kSmallPaddingX); |
| 206 int small_height = | 278 int small_height = |
| 207 floor((container_height + kSmallPaddingY) / float(count_y) - | 279 floor((container_height + kSmallPaddingY) / float(count_y) - |
| 208 kSmallPaddingY); | 280 (kSmallPaddingY + kFooterExtraHeight)); |
| 209 | 281 |
| 210 // |small_width / small_height| has only roughly an aspect ratio of |aspect|. | 282 // |small_width / small_height| has only roughly an aspect ratio of |aspect|. |
| 211 // Shrink the thumbnail rect to make the aspect ratio fit exactly, and add | 283 // Shrink the thumbnail rect to make the aspect ratio fit exactly, and add |
| 212 // the extra space won by shrinking to the outer padding. | 284 // the extra space won by shrinking to the outer padding. |
| 213 int smallExtraPaddingLeft = 0; | 285 int smallExtraPaddingLeft = 0; |
| 214 int smallExtraPaddingTop = 0; | 286 int smallExtraPaddingTop = 0; |
| 215 if (aspect > small_width/float(small_height)) { | 287 if (aspect > small_width/float(small_height)) { |
| 216 small_height = small_width / aspect; | 288 small_height = small_width / aspect; |
| 217 CGFloat all_tiles_height = | 289 CGFloat all_tiles_height = |
| 218 (small_height + kSmallPaddingY) * count_y - kSmallPaddingY; | 290 (small_height + kSmallPaddingY + kFooterExtraHeight) * count_y - |
| 291 (kSmallPaddingY + kFooterExtraHeight); |
| 219 smallExtraPaddingTop = (container_height - all_tiles_height)/2; | 292 smallExtraPaddingTop = (container_height - all_tiles_height)/2; |
| 220 } else { | 293 } else { |
| 221 small_width = small_height * aspect; | 294 small_width = small_height * aspect; |
| 222 CGFloat all_tiles_width = | 295 CGFloat all_tiles_width = |
| 223 (small_width + kSmallPaddingX) * count_x - kSmallPaddingX; | 296 (small_width + kSmallPaddingX) * count_x - kSmallPaddingX; |
| 224 smallExtraPaddingLeft = (container_width - all_tiles_width)/2; | 297 smallExtraPaddingLeft = (container_width - all_tiles_width)/2; |
| 225 } | 298 } |
| 226 | 299 |
| 227 // Compute inter-tile padding in the zoomed-out view. | 300 // Compute inter-tile padding in the zoomed-out view. |
| 228 CGFloat scale_small_to_big = NSWidth(containing_rect) / float(small_width); | 301 CGFloat scale_small_to_big = NSWidth(containing_rect) / float(small_width); |
| 229 CGFloat big_padding_x = kSmallPaddingX * scale_small_to_big; | 302 CGFloat big_padding_x = kSmallPaddingX * scale_small_to_big; |
| 230 CGFloat big_padding_y = kSmallPaddingY * scale_small_to_big; | 303 CGFloat big_padding_y = |
| 304 (kSmallPaddingY + kFooterExtraHeight) * scale_small_to_big; |
| 231 | 305 |
| 232 // Now all dimensions are known. Lay out all tiles on a regular grid: | 306 // Now all dimensions are known. Lay out all tiles on a regular grid: |
| 233 // X X X X | 307 // X X X X |
| 234 // X X X X | 308 // X X X X |
| 235 // X X | 309 // X X |
| 236 for (int row = 0, i = 0; i < tile_count; ++row) { | 310 for (int row = 0, i = 0; i < tile_count; ++row) { |
| 237 for (int col = 0; col < count_x && i < tile_count; ++col, ++i) { | 311 for (int col = 0; col < count_x && i < tile_count; ++col, ++i) { |
| 238 // Compute the smalled, zoomed-out thumbnail rect. | 312 // Compute the smalled, zoomed-out thumbnail rect. |
| 239 tiles_[i].thumb_rect_.size = NSMakeSize(small_width, small_height); | 313 tiles_[i]->thumb_rect_.size = NSMakeSize(small_width, small_height); |
| 240 | 314 |
| 241 int small_x = col * (small_width + kSmallPaddingX) + | 315 int small_x = col * (small_width + kSmallPaddingX) + |
| 242 kSmallPaddingLeft + smallExtraPaddingLeft; | 316 kSmallPaddingLeft + smallExtraPaddingLeft; |
| 243 int small_y = row * (small_height + kSmallPaddingY) + | 317 int small_y = row * (small_height + kSmallPaddingY + kFooterExtraHeight) + |
| 244 kSmallPaddingTop + smallExtraPaddingTop; | 318 kSmallPaddingTop + smallExtraPaddingTop; |
| 245 | 319 |
| 246 tiles_[i].thumb_rect_.origin = NSMakePoint( | 320 tiles_[i]->thumb_rect_.origin = NSMakePoint( |
| 247 small_x, NSHeight(containing_rect) - small_y - small_height); | 321 small_x, NSHeight(containing_rect) - small_y - small_height); |
| 248 | 322 |
| 323 tiles_[i]->favicon_rect_.size = NSMakeSize(kFaviconSize, kFaviconSize); |
| 324 tiles_[i]->favicon_rect_.origin = NSMakePoint( |
| 325 small_x, |
| 326 NSHeight(containing_rect) - |
| 327 (small_y + small_height + kFaviconExtraHeight)); |
| 328 |
| 329 // Align lower left corner of title rect with lower left corner of favicon |
| 330 // for now. The final position is computed later by |
| 331 // |Tile::set_font_metrics()|. |
| 332 tiles_[i]->title_font_size_ = kTitleHeight; |
| 333 tiles_[i]->title_rect_.origin = NSMakePoint( |
| 334 NSMaxX(tiles_[i]->favicon_rect()) + kFaviconTitleDistanceX, |
| 335 NSMinY(tiles_[i]->favicon_rect())); |
| 336 tiles_[i]->title_rect_.size = NSMakeSize( |
| 337 small_width - |
| 338 NSWidth(tiles_[i]->favicon_rect()) - kFaviconTitleDistanceX, |
| 339 kTitleHeight); |
| 340 |
| 249 // Compute the big, pre-zoom thumbnail rect. | 341 // Compute the big, pre-zoom thumbnail rect. |
| 250 tiles_[i].start_thumb_rect_.size = containing_rect.size; | 342 tiles_[i]->start_thumb_rect_.size = containing_rect.size; |
| 251 | 343 |
| 252 int big_x = col * (NSWidth(containing_rect) + big_padding_x); | 344 int big_x = col * (NSWidth(containing_rect) + big_padding_x); |
| 253 int big_y = row * (NSHeight(containing_rect) + big_padding_y); | 345 int big_y = row * (NSHeight(containing_rect) + big_padding_y); |
| 254 tiles_[i].start_thumb_rect_.origin = NSMakePoint(big_x, -big_y); | 346 tiles_[i]->start_thumb_rect_.origin = NSMakePoint(big_x, -big_y); |
| 255 } | 347 } |
| 256 } | 348 } |
| 257 | 349 |
| 258 // Go through last row and center it: | 350 // Go through last row and center it: |
| 259 // X X X X | 351 // X X X X |
| 260 // X X X X | 352 // X X X X |
| 261 // X X | 353 // X X |
| 262 int last_row_empty_tiles_x = count_x - last_row_count_x; | 354 int last_row_empty_tiles_x = count_x - last_row_count_x; |
| 263 CGFloat small_last_row_shift_x = | 355 CGFloat small_last_row_shift_x = |
| 264 last_row_empty_tiles_x * (small_width + kSmallPaddingX) / 2; | 356 last_row_empty_tiles_x * (small_width + kSmallPaddingX) / 2; |
| 265 CGFloat big_last_row_shift_x = | 357 CGFloat big_last_row_shift_x = |
| 266 last_row_empty_tiles_x * (NSWidth(containing_rect) + big_padding_x) / 2; | 358 last_row_empty_tiles_x * (NSWidth(containing_rect) + big_padding_x) / 2; |
| 267 for (int i = tile_count - last_row_count_x; i < tile_count; ++i) { | 359 for (int i = tile_count - last_row_count_x; i < tile_count; ++i) { |
| 268 tiles_[i].thumb_rect_.origin.x += small_last_row_shift_x; | 360 tiles_[i]->thumb_rect_.origin.x += small_last_row_shift_x; |
| 269 tiles_[i].start_thumb_rect_.origin.x += big_last_row_shift_x; | 361 tiles_[i]->start_thumb_rect_.origin.x += big_last_row_shift_x; |
| 362 tiles_[i]->favicon_rect_.origin.x += small_last_row_shift_x; |
| 363 tiles_[i]->title_rect_.origin.x += small_last_row_shift_x; |
| 270 } | 364 } |
| 271 } | 365 } |
| 272 | 366 |
| 273 void TileSet::set_selected_index(int index) { | 367 void TileSet::set_selected_index(int index) { |
| 274 CHECK_GE(index, 0); | 368 CHECK_GE(index, 0); |
| 275 CHECK_LT(index, static_cast<int>(tiles_.size())); | 369 CHECK_LT(index, static_cast<int>(tiles_.size())); |
| 276 selected_index_ = index; | 370 selected_index_ = index; |
| 277 } | 371 } |
| 278 | 372 |
| 279 } // namespace tabpose | 373 } // namespace tabpose |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 } | 464 } |
| 371 | 465 |
| 372 - (CALayer*)selectedLayer { | 466 - (CALayer*)selectedLayer { |
| 373 return [allThumbnailLayers_ objectAtIndex:tileSet_->selected_index()]; | 467 return [allThumbnailLayers_ objectAtIndex:tileSet_->selected_index()]; |
| 374 } | 468 } |
| 375 | 469 |
| 376 - (void)selectTileAtIndex:(int)newIndex { | 470 - (void)selectTileAtIndex:(int)newIndex { |
| 377 ScopedCAActionDisabler disabler; | 471 ScopedCAActionDisabler disabler; |
| 378 const tabpose::Tile& tile = tileSet_->tile_at(newIndex); | 472 const tabpose::Tile& tile = tileSet_->tile_at(newIndex); |
| 379 selectionHighlight_.frame = | 473 selectionHighlight_.frame = |
| 380 NSRectToCGRect(NSInsetRect(tile.thumb_rect(), -6, -6)); | 474 NSRectToCGRect(NSInsetRect(tile.thumb_rect(), -5, -5)); |
| 381 | 475 |
| 382 tileSet_->set_selected_index(newIndex); | 476 tileSet_->set_selected_index(newIndex); |
| 383 } | 477 } |
| 384 | 478 |
| 385 - (void)setUpLayers:(NSRect)bgLayerRect slomo:(BOOL)slomo { | 479 - (void)setUpLayers:(NSRect)bgLayerRect slomo:(BOOL)slomo { |
| 386 // Root layer -- covers whole window. | 480 // Root layer -- covers whole window. |
| 387 rootLayer_ = [CALayer layer]; | 481 rootLayer_ = [CALayer layer]; |
| 388 [[self contentView] setLayer:rootLayer_]; | 482 [[self contentView] setLayer:rootLayer_]; |
| 389 [[self contentView] setWantsLayer:YES]; | 483 [[self contentView] setWantsLayer:YES]; |
| 390 | 484 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 412 NSHeight(bgLayerRect) - kTopGradientHeight, | 506 NSHeight(bgLayerRect) - kTopGradientHeight, |
| 413 NSWidth(bgLayerRect), | 507 NSWidth(bgLayerRect), |
| 414 kTopGradientHeight); | 508 kTopGradientHeight); |
| 415 [gradientLayer setNeedsDisplay]; // Draw once. | 509 [gradientLayer setNeedsDisplay]; // Draw once. |
| 416 [bgLayer_ addSublayer:gradientLayer]; | 510 [bgLayer_ addSublayer:gradientLayer]; |
| 417 | 511 |
| 418 // Layers for the tab thumbnails. | 512 // Layers for the tab thumbnails. |
| 419 tileSet_->Build(tabStripModel_); | 513 tileSet_->Build(tabStripModel_); |
| 420 tileSet_->Layout(bgLayerRect); | 514 tileSet_->Layout(bgLayerRect); |
| 421 | 515 |
| 516 NSImage* defaultFavIcon = ResourceBundle::GetSharedInstance().GetNSImageNamed( |
| 517 IDR_DEFAULT_FAVICON); |
| 518 |
| 422 allThumbnailLayers_.reset( | 519 allThumbnailLayers_.reset( |
| 423 [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]); | 520 [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]); |
| 521 allFaviconLayers_.reset( |
| 522 [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]); |
| 523 allTitleLayers_.reset( |
| 524 [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]); |
| 424 for (int i = 0; i < tabStripModel_->count(); ++i) { | 525 for (int i = 0; i < tabStripModel_->count(); ++i) { |
| 526 const tabpose::Tile& tile = tileSet_->tile_at(i); |
| 425 CALayer* layer = [CALayer layer]; | 527 CALayer* layer = [CALayer layer]; |
| 426 | 528 |
| 427 // Background color as placeholder for now. | 529 // Background color as placeholder for now. |
| 428 layer.backgroundColor = CGColorGetConstantColor(kCGColorWhite); | 530 layer.backgroundColor = CGColorGetConstantColor(kCGColorWhite); |
| 429 | 531 |
| 430 AnimateCALayerFrameFromTo( | 532 AnimateCALayerFrameFromTo( |
| 431 layer, | 533 layer, |
| 432 tileSet_->tile_at(i).GetStartRectRelativeTo(tileSet_->selected_tile()), | 534 tile.GetStartRectRelativeTo(tileSet_->selected_tile()), |
| 433 tileSet_->tile_at(i).thumb_rect(), | 535 tile.thumb_rect(), |
| 434 kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1), | 536 kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1), |
| 435 i == tileSet_->selected_index() ? self : nil); | 537 i == tileSet_->selected_index() ? self : nil); |
| 436 | 538 |
| 437 // Add a delegate to one of the animations to get a notification once the | 539 // Add a delegate to one of the animations to get a notification once the |
| 438 // animations are done. | 540 // animations are done. |
| 439 if (i == tileSet_->selected_index()) { | 541 if (i == tileSet_->selected_index()) { |
| 440 CAAnimation* animation = [layer animationForKey:@"bounds"]; | 542 CAAnimation* animation = [layer animationForKey:@"bounds"]; |
| 441 DCHECK(animation); | 543 DCHECK(animation); |
| 442 [animation setValue:kAnimationIdFadeIn forKey:kAnimationIdKey]; | 544 [animation setValue:kAnimationIdFadeIn forKey:kAnimationIdKey]; |
| 443 } | 545 } |
| 444 | 546 |
| 445 layer.shadowRadius = 10; | 547 layer.shadowRadius = 10; |
| 446 layer.shadowOffset = CGSizeMake(0, -10); | 548 layer.shadowOffset = CGSizeMake(0, -10); |
| 447 | 549 |
| 448 [bgLayer_ addSublayer:layer]; | 550 [bgLayer_ addSublayer:layer]; |
| 449 [allThumbnailLayers_ addObject:layer]; | 551 [allThumbnailLayers_ addObject:layer]; |
| 552 |
| 553 // Favicon and title. |
| 554 NSFont* font = [NSFont systemFontOfSize:tile.title_font_size()]; |
| 555 tileSet_->tile_at(i).set_font_metrics([font ascender], -[font descender]); |
| 556 |
| 557 NSImage* ns_favicon = gfx::SkBitmapToNSImage(tile.favicon()); |
| 558 // Either we don't have a valid favicon or there was some issue converting |
| 559 // it from an SkBitmap. Either way, just show the default. |
| 560 if (!ns_favicon) |
| 561 ns_favicon = defaultFavIcon; |
| 562 scoped_cftyperef<CGImageRef> favicon( |
| 563 mac_util::CopyNSImageToCGImage(ns_favicon)); |
| 564 |
| 565 CALayer* faviconLayer = [CALayer layer]; |
| 566 faviconLayer.frame = NSRectToCGRect(tile.favicon_rect()); |
| 567 faviconLayer.contents = (id)favicon.get(); |
| 568 faviconLayer.zPosition = 1; // On top of the thumb shadow. |
| 569 faviconLayer.hidden = YES; |
| 570 [bgLayer_ addSublayer:faviconLayer]; |
| 571 [allFaviconLayers_ addObject:faviconLayer]; |
| 572 |
| 573 CATextLayer* titleLayer = [CATextLayer layer]; |
| 574 titleLayer.frame = NSRectToCGRect(tile.title_rect()); |
| 575 titleLayer.string = base::SysUTF16ToNSString(tile.title()); |
| 576 titleLayer.fontSize = [font pointSize]; |
| 577 titleLayer.truncationMode = kCATruncationEnd; |
| 578 titleLayer.font = font; |
| 579 titleLayer.zPosition = 1; // On top of the thumb shadow. |
| 580 titleLayer.hidden = YES; |
| 581 [bgLayer_ addSublayer:titleLayer]; |
| 582 [allTitleLayers_ addObject:titleLayer]; |
| 450 } | 583 } |
| 451 [self selectTileAtIndex:tileSet_->selected_index()]; | 584 [self selectTileAtIndex:tileSet_->selected_index()]; |
| 452 } | 585 } |
| 453 | 586 |
| 454 - (BOOL)canBecomeKeyWindow { | 587 - (BOOL)canBecomeKeyWindow { |
| 455 return YES; | 588 return YES; |
| 456 } | 589 } |
| 457 | 590 |
| 458 - (void)keyDown:(NSEvent*)event { | 591 - (void)keyDown:(NSEvent*)event { |
| 459 // Overridden to prevent beeps. | 592 // Overridden to prevent beeps. |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 tabStripModel_->SelectTabContentsAt(tileSet_->selected_index(), | 664 tabStripModel_->SelectTabContentsAt(tileSet_->selected_index(), |
| 532 /*user_gesture=*/true); | 665 /*user_gesture=*/true); |
| 533 | 666 |
| 534 { | 667 { |
| 535 ScopedCAActionDisabler disableCAActions; | 668 ScopedCAActionDisabler disableCAActions; |
| 536 | 669 |
| 537 // Move the selected layer on top of all other layers. | 670 // Move the selected layer on top of all other layers. |
| 538 [self selectedLayer].zPosition = 1; | 671 [self selectedLayer].zPosition = 1; |
| 539 | 672 |
| 540 selectionHighlight_.hidden = YES; | 673 selectionHighlight_.hidden = YES; |
| 674 for (CALayer* layer in allFaviconLayers_.get()) |
| 675 layer.hidden = YES; |
| 676 for (CALayer* layer in allTitleLayers_.get()) |
| 677 layer.hidden = YES; |
| 541 | 678 |
| 542 // Running animations with shadows is slow, so turn shadows off before | 679 // Running animations with shadows is slow, so turn shadows off before |
| 543 // running the exit animation. | 680 // running the exit animation. |
| 544 for (CALayer* layer in allThumbnailLayers_.get()) | 681 for (CALayer* layer in allThumbnailLayers_.get()) |
| 545 layer.shadowOpacity = 0.0; | 682 layer.shadowOpacity = 0.0; |
| 546 } | 683 } |
| 547 | 684 |
| 548 // Animate layers out, all in one transaction. | 685 // Animate layers out, all in one transaction. |
| 549 CGFloat duration = kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1); | 686 CGFloat duration = kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1); |
| 550 ScopedCAActionSetDuration durationSetter(duration); | 687 ScopedCAActionSetDuration durationSetter(duration); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 572 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished { | 709 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished { |
| 573 NSString* animationId = [animation valueForKey:kAnimationIdKey]; | 710 NSString* animationId = [animation valueForKey:kAnimationIdKey]; |
| 574 if ([animationId isEqualToString:kAnimationIdFadeIn]) { | 711 if ([animationId isEqualToString:kAnimationIdFadeIn]) { |
| 575 if (finished) { | 712 if (finished) { |
| 576 // If the user clicks while the fade in animation is still running, | 713 // If the user clicks while the fade in animation is still running, |
| 577 // |state_| is already kFadingOut. In that case, don't do anything. | 714 // |state_| is already kFadingOut. In that case, don't do anything. |
| 578 DCHECK_EQ(tabpose::kFadingIn, state_); | 715 DCHECK_EQ(tabpose::kFadingIn, state_); |
| 579 state_ = tabpose::kFadedIn; | 716 state_ = tabpose::kFadedIn; |
| 580 | 717 |
| 581 selectionHighlight_.hidden = NO; | 718 selectionHighlight_.hidden = NO; |
| 719 for (CALayer* layer in allFaviconLayers_.get()) |
| 720 layer.hidden = NO; |
| 721 for (CALayer* layer in allTitleLayers_.get()) |
| 722 layer.hidden = NO; |
| 582 | 723 |
| 583 // Running animations with shadows is slow, so turn shadows on only after | 724 // Running animations with shadows is slow, so turn shadows on only after |
| 584 // the animation is done. | 725 // the animation is done. |
| 585 ScopedCAActionDisabler disableCAActions; | 726 ScopedCAActionDisabler disableCAActions; |
| 586 for (CALayer* layer in allThumbnailLayers_.get()) | 727 for (CALayer* layer in allThumbnailLayers_.get()) |
| 587 layer.shadowOpacity = 0.5; | 728 layer.shadowOpacity = 0.5; |
| 588 } | 729 } |
| 589 } else if ([animationId isEqualToString:kAnimationIdFadeOut]) { | 730 } else if ([animationId isEqualToString:kAnimationIdFadeOut]) { |
| 590 DCHECK_EQ(tabpose::kFadingOut, state_); | 731 DCHECK_EQ(tabpose::kFadingOut, state_); |
| 591 [self close]; | 732 [self close]; |
| 592 } | 733 } |
| 593 } | 734 } |
| 594 | 735 |
| 595 @end | 736 @end |
| OLD | NEW |