| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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 "ios/chrome/browser/ui/stack_view/card_stack_layout_manager.h" | 5 #import "ios/chrome/browser/ui/stack_view/card_stack_layout_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "ios/chrome/browser/ui/rtl_geometry.h" | 11 #include "ios/chrome/browser/ui/rtl_geometry.h" |
| 12 #import "ios/chrome/browser/ui/stack_view/card_view.h" | |
| 13 #import "ios/chrome/browser/ui/stack_view/stack_card.h" | 12 #import "ios/chrome/browser/ui/stack_view/stack_card.h" |
| 14 #import "ios/chrome/browser/ui/stack_view/title_label.h" | |
| 15 #import "ios/chrome/browser/ui/ui_util.h" | 13 #import "ios/chrome/browser/ui/ui_util.h" |
| 16 | 14 |
| 17 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
| 18 #error "This file requires ARC support." | |
| 19 #endif | |
| 20 | |
| 21 namespace { | 15 namespace { |
| 22 | 16 |
| 23 // The maximum number of cards that should be staggered at a collapse point. | 17 // The maximum number of cards that should be staggered at a collapse point. |
| 24 const NSInteger kMaxVisibleStaggerCount = 4; | 18 const NSInteger kMaxVisibleStaggerCount = 4; |
| 25 // The amount that each of the staggered cards in a stack should be staggered | 19 // The amount that each of the staggered cards in a stack should be staggered |
| 26 // when fully collapsed. | 20 // when fully collapsed. |
| 27 const CGFloat kMinStackStaggerAmount = 4.0; | 21 const CGFloat kMinStackStaggerAmount = 4.0; |
| 28 // The amount that a card should overlap with a previous/subsequent card when | 22 // The amount that a card should overlap with a previous/subsequent card when |
| 29 // it is extended the maximum distance away (e.g., after a multitouch event). | 23 // it is extended the maximum distance away (e.g., after a multitouch event). |
| 30 const CGFloat kFullyExtendedCardOverlap = 8.0; | 24 const CGFloat kFullyExtendedCardOverlap = 8.0; |
| 31 // The amount that a card's position is allowed to drift toward overextension | 25 // The amount that a card's position is allowed to drift toward overextension |
| 32 // before the card is considered to be overextended (i.e., an epsilon to allow | 26 // before the card is considered to be overextended (i.e., an epsilon to allow |
| 33 // for floating-point imprecision). | 27 // for floating-point imprecision). |
| 34 const CGFloat kDistanceBeforeOverextension = 0.0001; | 28 const CGFloat kDistanceBeforeOverextension = 0.0001; |
| 35 // The factor by which scroll is decayed on overscroll. | 29 // The factor by which scroll is decayed on overscroll. |
| 36 const CGFloat kOverextensionDecayFactor = 2.0; | 30 const CGFloat kOverextensionDecayFactor = 2.0; |
| 37 // The amount by which a card is scrolled when asked to scroll it away from its | 31 // The amount by which a card is scrolled when asked to scroll it away from its |
| 38 // preceding neighbor. | 32 // preceding neighbor. |
| 39 const CGFloat kScrollAwayFromNeighborAmount = 200; | 33 const CGFloat kScrollAwayFromNeighborAmount = 200; |
| 40 | 34 |
| 41 } // namespace | 35 } // namespace |
| 42 | 36 |
| 43 @interface CardStackLayoutManager () { | 37 @interface CardStackLayoutManager () |
| 44 NSMutableArray* cards_; | |
| 45 // YES if the previous call to one of {|scrollCardAtIndex|, | |
| 46 // |handleMultitouchWithFirstDelta|} was to the former method; NO otherwise. | |
| 47 BOOL treatOverExtensionAsScroll_; | |
| 48 NSUInteger previousFirstPinchCardIndex_; | |
| 49 NSUInteger previousSecondPinchCardIndex_; | |
| 50 } | |
| 51 | 38 |
| 52 // Exposes |kMinStackStaggerAmount| for tests. | 39 // Exposes |kMinStackStaggerAmount| for tests. |
| 53 - (CGFloat)minStackStaggerAmount; | 40 - (CGFloat)minStackStaggerAmount; |
| 54 // Exposes |kScrollAwayFromNeighborAmount| for tests. | 41 // Exposes |kScrollAwayFromNeighborAmount| for tests. |
| 55 - (CGFloat)scrollCardAwayFromNeighborAmount; | 42 - (CGFloat)scrollCardAwayFromNeighborAmount; |
| 56 // Returns the current start stack limit allowing for overextension as follows: | 43 // Returns the current start stack limit allowing for overextension as follows: |
| 57 // - If the card at |index| is not overextended toward the start, returns | 44 // - If the card at |index| is not overextended toward the start, returns |
| 58 // |startLimit_|. | 45 // |startLimit_|. |
| 59 // - Otherwise, returns the value of the start limit such that the position of | 46 // - Otherwise, returns the value of the start limit such that the position of |
| 60 // the card at |index| in the start stack is its current position (with the | 47 // the card at |index| in the start stack is its current position (with the |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 @synthesize maximumOverextensionAmount = maximumOverextensionAmount_; | 187 @synthesize maximumOverextensionAmount = maximumOverextensionAmount_; |
| 201 @synthesize endLimit = endLimit_; | 188 @synthesize endLimit = endLimit_; |
| 202 @synthesize layoutAxisPosition = layoutAxisPosition_; | 189 @synthesize layoutAxisPosition = layoutAxisPosition_; |
| 203 @synthesize startLimit = startLimit_; | 190 @synthesize startLimit = startLimit_; |
| 204 @synthesize layoutIsVertical = layoutIsVertical_; | 191 @synthesize layoutIsVertical = layoutIsVertical_; |
| 205 @synthesize lastStartStackCardIndex = lastStartStackCardIndex_; | 192 @synthesize lastStartStackCardIndex = lastStartStackCardIndex_; |
| 206 @synthesize firstEndStackCardIndex = firstEndStackCardIndex_; | 193 @synthesize firstEndStackCardIndex = firstEndStackCardIndex_; |
| 207 | 194 |
| 208 - (id)init { | 195 - (id)init { |
| 209 if ((self = [super init])) { | 196 if ((self = [super init])) { |
| 210 cards_ = [[NSMutableArray alloc] init]; | 197 cards_.reset([[NSMutableArray alloc] init]); |
| 211 layoutIsVertical_ = YES; | 198 layoutIsVertical_ = YES; |
| 212 lastStartStackCardIndex_ = -1; | 199 lastStartStackCardIndex_ = -1; |
| 213 firstEndStackCardIndex_ = -1; | 200 firstEndStackCardIndex_ = -1; |
| 214 } | 201 } |
| 215 return self; | 202 return self; |
| 216 } | 203 } |
| 217 | 204 |
| 218 - (CGFloat)minStackStaggerAmount { | 205 - (CGFloat)minStackStaggerAmount { |
| 219 return kMinStackStaggerAmount; | 206 return kMinStackStaggerAmount; |
| 220 } | 207 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 lastStartStackCardIndex_ = -1; | 240 lastStartStackCardIndex_ = -1; |
| 254 firstEndStackCardIndex_ = -1; | 241 firstEndStackCardIndex_ = -1; |
| 255 [cards_ removeAllObjects]; | 242 [cards_ removeAllObjects]; |
| 256 } | 243 } |
| 257 | 244 |
| 258 - (void)setCardSize:(CGSize)size { | 245 - (void)setCardSize:(CGSize)size { |
| 259 cardSize_ = size; | 246 cardSize_ = size; |
| 260 NSUInteger i = 0; | 247 NSUInteger i = 0; |
| 261 CGFloat previousFirstCardOffset = 0; | 248 CGFloat previousFirstCardOffset = 0; |
| 262 CGFloat newFirstCardOffset = 0; | 249 CGFloat newFirstCardOffset = 0; |
| 263 for (StackCard* card in cards_) { | 250 for (StackCard* card in cards_.get()) { |
| 264 CGFloat offset = [self cardOffsetOnLayoutAxis:card]; | 251 CGFloat offset = [self cardOffsetOnLayoutAxis:card]; |
| 265 card.size = cardSize_; | 252 card.size = cardSize_; |
| 266 CGFloat newOffset = offset; | 253 CGFloat newOffset = offset; |
| 267 | 254 |
| 268 // Attempt to preserve card positions, but ensure that the deck starts | 255 // Attempt to preserve card positions, but ensure that the deck starts |
| 269 // within overextension limits and that all cards not in the start stack are | 256 // within overextension limits and that all cards not in the start stack are |
| 270 // within minimum/maximum separation limits of their preceding neighbors. | 257 // within minimum/maximum separation limits of their preceding neighbors. |
| 271 if (i == 0) { | 258 if (i == 0) { |
| 272 newOffset = std::max(newOffset, [self limitOfOverextensionTowardStart]); | 259 newOffset = std::max(newOffset, [self limitOfOverextensionTowardStart]); |
| 273 newOffset = std::min(newOffset, [self limitOfOverscrollTowardEnd]); | 260 newOffset = std::min(newOffset, [self limitOfOverscrollTowardEnd]); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 295 for (NSUInteger i = 0; i < [cards_ count]; i++) { | 282 for (NSUInteger i = 0; i < [cards_ count]; i++) { |
| 296 LayoutRectPosition position = [[cards_ objectAtIndex:i] layout].position; | 283 LayoutRectPosition position = [[cards_ objectAtIndex:i] layout].position; |
| 297 CGFloat prevLayoutAxisOffset = | 284 CGFloat prevLayoutAxisOffset = |
| 298 layoutIsVertical_ ? position.leading : position.originY; | 285 layoutIsVertical_ ? position.leading : position.originY; |
| 299 [self moveOriginOfCardAtIndex:i toOffset:prevLayoutAxisOffset]; | 286 [self moveOriginOfCardAtIndex:i toOffset:prevLayoutAxisOffset]; |
| 300 } | 287 } |
| 301 } | 288 } |
| 302 | 289 |
| 303 - (void)setLayoutAxisPosition:(CGFloat)position { | 290 - (void)setLayoutAxisPosition:(CGFloat)position { |
| 304 layoutAxisPosition_ = position; | 291 layoutAxisPosition_ = position; |
| 305 for (StackCard* card in cards_) { | 292 for (StackCard* card in cards_.get()) { |
| 306 LayoutRect layout = card.layout; | 293 LayoutRect layout = card.layout; |
| 307 if (layoutIsVertical_) | 294 if (layoutIsVertical_) |
| 308 layout.position.leading = position - 0.5 * layout.size.width; | 295 layout.position.leading = position - 0.5 * layout.size.width; |
| 309 else | 296 else |
| 310 layout.position.originY = position - 0.5 * layout.size.height; | 297 layout.position.originY = position - 0.5 * layout.size.height; |
| 311 card.layout = layout; | 298 card.layout = layout; |
| 312 } | 299 } |
| 313 } | 300 } |
| 314 | 301 |
| 315 - (NSArray*)cards { | 302 - (NSArray*)cards { |
| (...skipping 818 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1134 CGFloat edgeOffset = endLimit_ - labelOffset; | 1121 CGFloat edgeOffset = endLimit_ - labelOffset; |
| 1135 return cardOffset >= edgeOffset; | 1122 return cardOffset >= edgeOffset; |
| 1136 } else { | 1123 } else { |
| 1137 CGFloat separation = | 1124 CGFloat separation = |
| 1138 [self distanceBetweenCardAtIndex:index andCardAtIndex:(index + 1)]; | 1125 [self distanceBetweenCardAtIndex:index andCardAtIndex:(index + 1)]; |
| 1139 return separation <= labelOffset; | 1126 return separation <= labelOffset; |
| 1140 } | 1127 } |
| 1141 } | 1128 } |
| 1142 | 1129 |
| 1143 - (void)setSynchronizeCardViews:(BOOL)synchronizeViews { | 1130 - (void)setSynchronizeCardViews:(BOOL)synchronizeViews { |
| 1144 for (StackCard* card in cards_) { | 1131 for (StackCard* card in cards_.get()) { |
| 1145 card.synchronizeView = synchronizeViews; | 1132 card.synchronizeView = synchronizeViews; |
| 1146 } | 1133 } |
| 1147 } | 1134 } |
| 1148 | 1135 |
| 1149 - (BOOL)isInStartStack:(NSUInteger)index { | 1136 - (BOOL)isInStartStack:(NSUInteger)index { |
| 1150 DCHECK(index < [cards_ count]); | 1137 DCHECK(index < [cards_ count]); |
| 1151 return ((NSInteger)index <= lastStartStackCardIndex_); | 1138 return ((NSInteger)index <= lastStartStackCardIndex_); |
| 1152 } | 1139 } |
| 1153 | 1140 |
| 1154 - (BOOL)isInEndStack:(NSUInteger)index { | 1141 - (BOOL)isInEndStack:(NSUInteger)index { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1201 return 0; | 1188 return 0; |
| 1202 return std::abs([self cardOffsetOnLayoutAxis:[cards_ firstObject]] - | 1189 return std::abs([self cardOffsetOnLayoutAxis:[cards_ firstObject]] - |
| 1203 startLimit_); | 1190 startLimit_); |
| 1204 } | 1191 } |
| 1205 | 1192 |
| 1206 - (NSUInteger)fannedStackCount { | 1193 - (NSUInteger)fannedStackCount { |
| 1207 return floor((endLimit_ - startLimit_) / maxStagger_); | 1194 return floor((endLimit_ - startLimit_) / maxStagger_); |
| 1208 } | 1195 } |
| 1209 | 1196 |
| 1210 @end | 1197 @end |
| OLD | NEW |