Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Side by Side Diff: samples-dev/swarm/Views.dart

Issue 2828603002: Format samples and samples-dev directories. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of swarmlib; 5 part of swarmlib;
6 6
7 // This file contains View framework classes. 7 // This file contains View framework classes.
8 // As it grows, it may need to be split into multiple files. 8 // As it grows, it may need to be split into multiple files.
9 9
10 /** A factory that creates a view from a data model. */ 10 /** A factory that creates a view from a data model. */
(...skipping 13 matching lines...) Expand all
24 /** The width of the created view for a specific data model. */ 24 /** The width of the created view for a specific data model. */
25 int getWidth(D item); 25 int getWidth(D item);
26 26
27 /** The height of the created view for a specific data model. */ 27 /** The height of the created view for a specific data model. */
28 int getHeight(D item); 28 int getHeight(D item);
29 } 29 }
30 30
31 /** A collection of event listeners. */ 31 /** A collection of event listeners. */
32 class EventListeners { 32 class EventListeners {
33 var listeners; 33 var listeners;
34 EventListeners() { 34 EventListeners() {
35 listeners = new List(); 35 listeners = new List();
36 } 36 }
37 37
38 void addListener(listener) { 38 void addListener(listener) {
39 listeners.add(listener); 39 listeners.add(listener);
40 } 40 }
41 41
42 void fire(var event) { 42 void fire(var event) {
43 for (final listener in listeners) { 43 for (final listener in listeners) {
44 listener(event); 44 listener(event);
45 } 45 }
46 } 46 }
47 } 47 }
48 48
49
50 /** 49 /**
51 * Private view class used to store placeholder views for detatched ListView 50 * Private view class used to store placeholder views for detatched ListView
52 * elements. 51 * elements.
53 */ 52 */
54 class _PlaceholderView extends View { 53 class _PlaceholderView extends View {
55 _PlaceholderView() : super() {} 54 _PlaceholderView() : super() {}
56 55
57 Element render() => new Element.tag('div'); 56 Element render() => new Element.tag('div');
58 } 57 }
59 58
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 90
92 int getEstimatedLength(int viewLength); 91 int getEstimatedLength(int viewLength);
93 /** 92 /**
94 * Snap a specified index to the nearest visible view given the [viewLength]. 93 * Snap a specified index to the nearest visible view given the [viewLength].
95 */ 94 */
96 int getSnapIndex(num offset, num viewLength); 95 int getSnapIndex(num offset, num viewLength);
97 /** 96 /**
98 * Returns an interval specifying what views are currently visible given a 97 * Returns an interval specifying what views are currently visible given a
99 * particular [:offset:]. 98 * particular [:offset:].
100 */ 99 */
101 Interval computeVisibleInterval(num offset, num viewLength, 100 Interval computeVisibleInterval(num offset, num viewLength, num bufferLength);
102 num bufferLength);
103 } 101 }
104 102
105 /** 103 /**
106 * Base class used for the simple fixed size item [:ListView:] classes and more 104 * Base class used for the simple fixed size item [:ListView:] classes and more
107 * complex list view classes such as [:VariableSizeListView:] using a 105 * complex list view classes such as [:VariableSizeListView:] using a
108 * [:ListViewLayout:] class to drive the actual layout. 106 * [:ListViewLayout:] class to drive the actual layout.
109 */ 107 */
110 class GenericListView<D> extends View { 108 class GenericListView<D> extends View {
111 /** Minimum throw distance in pixels to trigger snapping to the next item. */ 109 /** Minimum throw distance in pixels to trigger snapping to the next item. */
112 static const SNAP_TO_NEXT_THROW_THRESHOLD = 15; 110 static const SNAP_TO_NEXT_THROW_THRESHOLD = 15;
(...skipping 18 matching lines...) Expand all
131 ListViewLayout<D> _layout; 129 ListViewLayout<D> _layout;
132 D _lastSelectedItem; 130 D _lastSelectedItem;
133 PageState _pages; 131 PageState _pages;
134 132
135 /** 133 /**
136 * Creates a new GenericListView with the given layout and data. If [:_data:] 134 * Creates a new GenericListView with the given layout and data. If [:_data:]
137 * is an [:ObservableList<T>:] then it will listen to changes to the list 135 * is an [:ObservableList<T>:] then it will listen to changes to the list
138 * and update the view appropriately. 136 * and update the view appropriately.
139 */ 137 */
140 GenericListView( 138 GenericListView(
141 this._layout, 139 this._layout,
142 this._data, 140 this._data,
143 this._scrollable, 141 this._scrollable,
144 this._vertical, 142 this._vertical,
145 this._selectedItem, 143 this._selectedItem,
146 this._snapToItems, 144 this._snapToItems,
147 this._paginate, 145 this._paginate,
148 this._removeClippedViews, 146 this._removeClippedViews,
149 this._showScrollbar, 147 this._showScrollbar,
150 this._pages) 148 this._pages)
151 : super(), 149 : super(),
152 _activeInterval = new Interval(0, 0), 150 _activeInterval = new Interval(0, 0),
153 _itemViews = new Map<int, View>() { 151 _itemViews = new Map<int, View>() {
154 // TODO(rnystrom): Move this into enterDocument once we have an exitDocument 152 // TODO(rnystrom): Move this into enterDocument once we have an exitDocument
155 // that we can use to unregister it. 153 // that we can use to unregister it.
156 if (_scrollable) { 154 if (_scrollable) {
157 window.onResize.listen((Event event) { 155 window.onResize.listen((Event event) {
158 if (isInDocument) { 156 if (isInDocument) {
159 onResize(); 157 onResize();
160 } 158 }
161 }); 159 });
162 } 160 }
163 } 161 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 node.nodes.add(_containerElem); 207 node.nodes.add(_containerElem);
210 } else { 208 } else {
211 _containerElem = node; 209 _containerElem = node;
212 } 210 }
213 211
214 if (_scrollable) { 212 if (_scrollable) {
215 scroller = new Scroller( 213 scroller = new Scroller(
216 _containerElem, 214 _containerElem,
217 _vertical /* verticalScrollEnabled */, 215 _vertical /* verticalScrollEnabled */,
218 !_vertical /* horizontalScrollEnabled */, 216 !_vertical /* horizontalScrollEnabled */,
219 true /* momentumEnabled */, 217 true /* momentumEnabled */, () {
220 () { 218 num width = _layout.getWidth(_viewLength);
221 num width = _layout.getWidth(_viewLength); 219 num height = _layout.getHeight(_viewLength);
222 num height = _layout.getHeight(_viewLength); 220 width = width != null ? width : 0;
223 width = width != null ? width : 0; 221 height = height != null ? height : 0;
224 height = height != null ? height : 0; 222 return new Size(width, height);
225 return new Size(width, height); 223 },
226 }, 224 _paginate && _snapToItems
227 _paginate && _snapToItems ? 225 ? Scroller.FAST_SNAP_DECELERATION_FACTOR
228 Scroller.FAST_SNAP_DECELERATION_FACTOR : 1); 226 : 1);
229 scroller.onContentMoved.listen((e) => renderVisibleItems(false)); 227 scroller.onContentMoved.listen((e) => renderVisibleItems(false));
230 if (_pages != null) { 228 if (_pages != null) {
231 watch(_pages.target, (s) => _onPageSelected()); 229 watch(_pages.target, (s) => _onPageSelected());
232 } 230 }
233 231
234 if (_snapToItems) { 232 if (_snapToItems) {
235 scroller.onDecelStart.listen((e) => _decelStart()); 233 scroller.onDecelStart.listen((e) => _decelStart());
236 scroller.onScrollerDragEnd.listen((e) => _decelStart()); 234 scroller.onScrollerDragEnd.listen((e) => _decelStart());
237 } 235 }
238 if (_showScrollbar) { 236 if (_showScrollbar) {
239 _scrollbar = new Scrollbar(scroller, true); 237 _scrollbar = new Scrollbar(scroller, true);
240 } 238 }
241 } else { 239 } else {
242 _reserveArea(); 240 _reserveArea();
243 renderVisibleItems(true); 241 renderVisibleItems(true);
244 } 242 }
245 243
246 return node; 244 return node;
247 } 245 }
248 246
249 void afterRender(Element node) { 247 void afterRender(Element node) {
250 // If our data source is observable, observe it. 248 // If our data source is observable, observe it.
251 if (_data is ObservableList<D>) { 249 if (_data is ObservableList<D>) {
252 ObservableList<D> observable = _data; 250 ObservableList<D> observable = _data;
253 attachWatch(observable, (EventSummary e) { 251 attachWatch(observable, (EventSummary e) {
254 if (e.target == observable) { 252 if (e.target == observable) {
255 onDataChange(); 253 onDataChange();
256 } 254 }
257 }); 255 });
258 } 256 }
259 257
260 if (_selectedItem != null) { 258 if (_selectedItem != null) {
261 addOnClick((Event e) { _onClick(e); }); 259 addOnClick((Event e) {
260 _onClick(e);
261 });
262 } 262 }
263 263
264 if (_selectedItem != null) { 264 if (_selectedItem != null) {
265 watch(_selectedItem, (EventSummary summary) => onSelectedItemChange()); 265 watch(_selectedItem, (EventSummary summary) => onSelectedItemChange());
266 } 266 }
267 } 267 }
268 268
269 void onDataChange() { 269 void onDataChange() {
270 _layout.onDataChange(); 270 _layout.onDataChange();
271 _renderItems(); 271 _renderItems();
272 } 272 }
273 273
274 void _reserveArea() { 274 void _reserveArea() {
275 final style = _containerElem.style; 275 final style = _containerElem.style;
276 int width = _layout.getWidth(_viewLength); 276 int width = _layout.getWidth(_viewLength);
277 int height = _layout.getHeight(_viewLength); 277 int height = _layout.getHeight(_viewLength);
278 if (width != null) { 278 if (width != null) {
279 style.width = '${width}px'; 279 style.width = '${width}px';
280 } 280 }
281 if (height != null) { 281 if (height != null) {
282 style.height = '${height}px'; 282 style.height = '${height}px';
283 } 283 }
284 // TODO(jacobr): this should be specified by the default CSS for a 284 // TODO(jacobr): this should be specified by the default CSS for a
285 // GenericListView. 285 // GenericListView.
286 style.overflow = 'hidden'; 286 style.overflow = 'hidden';
287 } 287 }
288 288
289
290 void onResize() { 289 void onResize() {
291 int lastViewLength = _viewLength; 290 int lastViewLength = _viewLength;
292 scheduleMicrotask(() { 291 scheduleMicrotask(() {
293 _viewLength = _vertical ? node.offset.height : node.offset.width; 292 _viewLength = _vertical ? node.offset.height : node.offset.width;
294 if (_viewLength != lastViewLength) { 293 if (_viewLength != lastViewLength) {
295 if (_scrollbar != null) { 294 if (_scrollbar != null) {
296 _scrollbar.refresh(); 295 _scrollbar.refresh();
297 } 296 }
298 renderVisibleItems(true); 297 renderVisibleItems(true);
299 } 298 }
(...skipping 15 matching lines...) Expand all
315 if (_paginate) { 314 if (_paginate) {
316 int newPage = Math.max(0, _layout.getPage(index, _viewLength) + delta); 315 int newPage = Math.max(0, _layout.getPage(index, _viewLength) + delta);
317 index = _layout.getPageStartIndex(newPage, _viewLength); 316 index = _layout.getPageStartIndex(newPage, _viewLength);
318 } else { 317 } else {
319 index += delta; 318 index += delta;
320 } 319 }
321 return GoogleMath.clamp(index, 0, _data.length - 1); 320 return GoogleMath.clamp(index, 0, _data.length - 1);
322 } 321 }
323 322
324 void _decelStart() { 323 void _decelStart() {
325 num currentTarget = scroller.verticalEnabled ? 324 num currentTarget = scroller.verticalEnabled
326 scroller.currentTarget.y : scroller.currentTarget.x; 325 ? scroller.currentTarget.y
327 num current = scroller.verticalEnabled ? 326 : scroller.currentTarget.x;
328 scroller.contentOffset.y : scroller.contentOffset.x; 327 num current = scroller.verticalEnabled
328 ? scroller.contentOffset.y
329 : scroller.contentOffset.x;
329 num targetIndex = _layout.getSnapIndex(currentTarget, _viewLength); 330 num targetIndex = _layout.getSnapIndex(currentTarget, _viewLength);
330 if (current != currentTarget) { 331 if (current != currentTarget) {
331 // The user is throwing rather than statically releasing. 332 // The user is throwing rather than statically releasing.
332 // For this case, we want to move them to the next snap interval 333 // For this case, we want to move them to the next snap interval
333 // as long as they made at least a minimal throw gesture. 334 // as long as they made at least a minimal throw gesture.
334 num currentIndex = _layout.getSnapIndex(current, _viewLength); 335 num currentIndex = _layout.getSnapIndex(current, _viewLength);
335 if (currentIndex == targetIndex && 336 if (currentIndex == targetIndex &&
336 (currentTarget - current).abs() > SNAP_TO_NEXT_THROW_THRESHOLD && 337 (currentTarget - current).abs() > SNAP_TO_NEXT_THROW_THRESHOLD &&
337 -_layout.getOffset(targetIndex) != currentTarget) { 338 -_layout.getOffset(targetIndex) != currentTarget) {
338 num snappedCurrentPosition = -_layout.getOffset(targetIndex); 339 num snappedCurrentPosition = -_layout.getOffset(targetIndex);
339 targetIndex = getNextIndex(targetIndex, currentTarget < current); 340 targetIndex = getNextIndex(targetIndex, currentTarget < current);
340 } 341 }
341 } 342 }
342 num targetPosition = -_layout.getOffset(targetIndex); 343 num targetPosition = -_layout.getOffset(targetIndex);
343 if (currentTarget != targetPosition) { 344 if (currentTarget != targetPosition) {
344 if (scroller.verticalEnabled) { 345 if (scroller.verticalEnabled) {
345 scroller.throwTo(scroller.contentOffset.x, targetPosition); 346 scroller.throwTo(scroller.contentOffset.x, targetPosition);
346 } else { 347 } else {
347 scroller.throwTo(targetPosition, scroller.contentOffset.y); 348 scroller.throwTo(targetPosition, scroller.contentOffset.y);
348 } 349 }
349 } else { 350 } else {
350 // Update the target page only after we are all done animating. 351 // Update the target page only after we are all done animating.
351 if (_pages != null) { 352 if (_pages != null) {
352 _pages.target.value =_layout.getPage(targetIndex, _viewLength); 353 _pages.target.value = _layout.getPage(targetIndex, _viewLength);
353 } 354 }
354 } 355 }
355 } 356 }
356 357
357 void _renderItems() { 358 void _renderItems() {
358 for (int i = _activeInterval.start; i < _activeInterval.end; i++) { 359 for (int i = _activeInterval.start; i < _activeInterval.end; i++) {
359 _removeView(i); 360 _removeView(i);
360 } 361 }
361 _itemViews.clear(); 362 _itemViews.clear();
362 _activeInterval = new Interval(0, 0); 363 _activeInterval = new Interval(0, 0);
363 if (scroller == null) { 364 if (scroller == null) {
364 _reserveArea(); 365 _reserveArea();
365 } 366 }
366 renderVisibleItems(false); 367 renderVisibleItems(false);
367 } 368 }
368 369
369 void _onPageSelected() { 370 void _onPageSelected() {
370 if (_pages.target != 371 if (_pages.target != _layout.getPage(_activeInterval.start, _viewLength)) {
371 _layout.getPage(_activeInterval.start, _viewLength)) {
372 _throwTo(_layout.getOffset( 372 _throwTo(_layout.getOffset(
373 _layout.getPageStartIndex(_pages.target.value, _viewLength))); 373 _layout.getPageStartIndex(_pages.target.value, _viewLength)));
374 } 374 }
375 } 375 }
376 376
377 num get _offset { 377 num get _offset {
378 return scroller.verticalEnabled ? 378 return scroller.verticalEnabled
379 scroller.getVerticalOffset() : scroller.getHorizontalOffset(); 379 ? scroller.getVerticalOffset()
380 : scroller.getHorizontalOffset();
380 } 381 }
381 382
382 /** 383 /**
383 * Calculates visible interval, based on the scroller position. 384 * Calculates visible interval, based on the scroller position.
384 */ 385 */
385 Interval getVisibleInterval() { 386 Interval getVisibleInterval() {
386 return _layout.computeVisibleInterval(_offset, _viewLength, 0); 387 return _layout.computeVisibleInterval(_offset, _viewLength, 0);
387 } 388 }
388 389
389 void renderVisibleItems(bool lengthChanged) { 390 void renderVisibleItems(bool lengthChanged) {
390 Interval targetInterval; 391 Interval targetInterval;
391 if (scroller != null) { 392 if (scroller != null) {
392 targetInterval = getVisibleInterval(); 393 targetInterval = getVisibleInterval();
393 } else { 394 } else {
394 // If the view is not scrollable, render all elements. 395 // If the view is not scrollable, render all elements.
395 targetInterval = new Interval(0, _data.length); 396 targetInterval = new Interval(0, _data.length);
396 } 397 }
397 398
398 if (_pages != null) { 399 if (_pages != null) {
399 _pages.current.value = 400 _pages.current.value = _layout.getPage(targetInterval.start, _viewLength);
400 _layout.getPage(targetInterval.start, _viewLength);
401 } 401 }
402 if (_pages != null) { 402 if (_pages != null) {
403 _pages.length.value = _data.length > 0 ? 403 _pages.length.value = _data.length > 0
404 _layout.getPage(_data.length - 1, _viewLength) + 1 : 0; 404 ? _layout.getPage(_data.length - 1, _viewLength) + 1
405 : 0;
405 } 406 }
406 407
407 if (!_removeClippedViews) { 408 if (!_removeClippedViews) {
408 // Avoid removing clipped views by extending the target interval to 409 // Avoid removing clipped views by extending the target interval to
409 // include the existing interval of rendered views. 410 // include the existing interval of rendered views.
410 targetInterval = targetInterval.union(_activeInterval); 411 targetInterval = targetInterval.union(_activeInterval);
411 } 412 }
412 413
413 if (lengthChanged == false && targetInterval == _activeInterval) { 414 if (lengthChanged == false && targetInterval == _activeInterval) {
414 return; 415 return;
415 } 416 }
416 417
417 // TODO(jacobr): add unittests that this code behaves correctly. 418 // TODO(jacobr): add unittests that this code behaves correctly.
418 419
419 // Remove views that are not needed anymore 420 // Remove views that are not needed anymore
420 for (int i = _activeInterval.start, 421 for (int i = _activeInterval.start,
421 end = Math.min(targetInterval.start, _activeInterval.end); 422 end = Math.min(targetInterval.start, _activeInterval.end);
422 i < end; i++) { 423 i < end;
424 i++) {
423 _removeView(i); 425 _removeView(i);
424 } 426 }
425 for (int i = Math.max(targetInterval.end, _activeInterval.start); 427 for (int i = Math.max(targetInterval.end, _activeInterval.start);
426 i < _activeInterval.end; i++) { 428 i < _activeInterval.end;
429 i++) {
427 _removeView(i); 430 _removeView(i);
428 } 431 }
429 432
430 // Add new views 433 // Add new views
431 for (int i = targetInterval.start, 434 for (int i = targetInterval.start,
432 end = Math.min(_activeInterval.start, targetInterval.end); 435 end = Math.min(_activeInterval.start, targetInterval.end);
433 i < end; i++) { 436 i < end;
437 i++) {
434 _addView(i); 438 _addView(i);
435 } 439 }
436 for (int i = Math.max(_activeInterval.end, targetInterval.start); 440 for (int i = Math.max(_activeInterval.end, targetInterval.start);
437 i < targetInterval.end; i++) { 441 i < targetInterval.end;
442 i++) {
438 _addView(i); 443 _addView(i);
439 } 444 }
440 445
441 _activeInterval = targetInterval; 446 _activeInterval = targetInterval;
442 } 447 }
443 448
444 void _removeView(int index) { 449 void _removeView(int index) {
445 // Do not remove placeholder views as they need to stay present in case 450 // Do not remove placeholder views as they need to stay present in case
446 // they scroll out of view and then back into view. 451 // they scroll out of view and then back into view.
447 if (!(_itemViews[index] is _PlaceholderView)) { 452 if (!(_itemViews[index] is _PlaceholderView)) {
448 // Remove from the active DOM but don't destroy. 453 // Remove from the active DOM but don't destroy.
449 _itemViews[index].node.remove(); 454 _itemViews[index].node.remove();
450 childViewRemoved(_itemViews[index]); 455 childViewRemoved(_itemViews[index]);
451 } 456 }
452 } 457 }
453 458
454 View _newView(int index) { 459 View _newView(int index) {
455 final view = _layout.newView(index); 460 final view = _layout.newView(index);
456 view.node.attributes[INDEX_DATA_ATTRIBUTE] = index.toString(); 461 view.node.attributes[INDEX_DATA_ATTRIBUTE] = index.toString();
457 return view; 462 return view;
458 } 463 }
459 464
460 View _addView(int index) { 465 View _addView(int index) {
461 if (_itemViews.containsKey(index)) { 466 if (_itemViews.containsKey(index)) {
462 final view = _itemViews[index]; 467 final view = _itemViews[index];
463 _addViewHelper(view, index); 468 _addViewHelper(view, index);
464 childViewAdded(view); 469 childViewAdded(view);
465 return view; 470 return view;
466 } 471 }
467 472
468 final view = _newView(index); 473 final view = _newView(index);
469 _itemViews[index] = view; 474 _itemViews[index] = view;
470 // TODO(jacobr): its ugly to put this here... but its needed 475 // TODO(jacobr): its ugly to put this here... but its needed
471 // as typical even-odd css queries won't work as we only display some 476 // as typical even-odd css queries won't work as we only display some
472 // children at a time. 477 // children at a time.
473 if (index == 0) { 478 if (index == 0) {
474 view.addClass('first-child'); 479 view.addClass('first-child');
475 } 480 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 */ 521 */
517 void reattachSubview(D data, View view, bool animate) { 522 void reattachSubview(D data, View view, bool animate) {
518 int index = findIndex(data); 523 int index = findIndex(data);
519 // TODO(jacobr): perform some validation that the view is 524 // TODO(jacobr): perform some validation that the view is
520 // really detached. 525 // really detached.
521 var currentPosition; 526 var currentPosition;
522 if (animate) { 527 if (animate) {
523 currentPosition = 528 currentPosition =
524 FxUtil.computeRelativePosition(view.node, _containerElem); 529 FxUtil.computeRelativePosition(view.node, _containerElem);
525 } 530 }
526 assert (_itemViews[index] is _PlaceholderView); 531 assert(_itemViews[index] is _PlaceholderView);
527 view.enterDocument(); 532 view.enterDocument();
528 _itemViews[index].node.replaceWith(view.node); 533 _itemViews[index].node.replaceWith(view.node);
529 _itemViews[index] = view; 534 _itemViews[index] = view;
530 if (animate) { 535 if (animate) {
531 FxUtil.setTranslate(view.node, currentPosition.x, currentPosition.y, 0); 536 FxUtil.setTranslate(view.node, currentPosition.x, currentPosition.y, 0);
532 // The view's position is unchanged except now re-parented to 537 // The view's position is unchanged except now re-parented to
533 // the list view. 538 // the list view.
534 Timer.run(() { _positionSubview(view.node, index); }); 539 Timer.run(() {
540 _positionSubview(view.node, index);
541 });
535 } else { 542 } else {
536 _positionSubview(view.node, index); 543 _positionSubview(view.node, index);
537 } 544 }
538 } 545 }
539 546
540 int findIndex(D targetItem) { 547 int findIndex(D targetItem) {
541 // TODO(jacobr): move this to a util library or modify this class so that 548 // TODO(jacobr): move this to a util library or modify this class so that
542 // the data is an List not a Collection. 549 // the data is an List not a Collection.
543 int i = 0; 550 int i = 0;
544 for (D item in _data) { 551 for (D item in _data) {
545 if (item == targetItem) { 552 if (item == targetItem) {
546 return i; 553 return i;
547 } 554 }
548 i++; 555 i++;
549 } 556 }
550 return null; 557 return null;
551 } 558 }
552 559
553 void _positionSubview(Element node, int index) { 560 void _positionSubview(Element node, int index) {
554 if (_vertical) { 561 if (_vertical) {
555 FxUtil.setTranslate(node, 0, _layout.getOffset(index), 0); 562 FxUtil.setTranslate(node, 0, _layout.getOffset(index), 0);
556 } else { 563 } else {
557 FxUtil.setTranslate(node, _layout.getOffset(index), 0, 0); 564 FxUtil.setTranslate(node, _layout.getOffset(index), 0, 0);
558 } 565 }
559 node.style.zIndex = index.toString(); 566 node.style.zIndex = index.toString();
560 } 567 }
561 568
562 void _select(int index, bool selected) { 569 void _select(int index, bool selected) {
563 if (index != null) { 570 if (index != null) {
564 final subview = getSubview(index); 571 final subview = getSubview(index);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
602 } 609 }
603 } 610 }
604 } 611 }
605 612
606 class FixedSizeListViewLayout<D> implements ListViewLayout<D> { 613 class FixedSizeListViewLayout<D> implements ListViewLayout<D> {
607 final ViewFactory<D> itemViewFactory; 614 final ViewFactory<D> itemViewFactory;
608 final bool _vertical; 615 final bool _vertical;
609 List<D> _data; 616 List<D> _data;
610 bool _paginate; 617 bool _paginate;
611 618
612 FixedSizeListViewLayout(this.itemViewFactory, this._data, this._vertical, 619 FixedSizeListViewLayout(
613 this._paginate); 620 this.itemViewFactory, this._data, this._vertical, this._paginate);
614 621
615 void onDataChange() {} 622 void onDataChange() {}
616 623
617 View newView(int index) { 624 View newView(int index) {
618 return itemViewFactory.newView(_data[index]); 625 return itemViewFactory.newView(_data[index]);
619 } 626 }
620 627
621 int get _itemLength { 628 int get _itemLength {
622 return _vertical ? itemViewFactory.height : itemViewFactory.width; 629 return _vertical ? itemViewFactory.height : itemViewFactory.width;
623 } 630 }
624 631
625
626 int getWidth(int viewLength) { 632 int getWidth(int viewLength) {
627 return _vertical ? itemViewFactory.width : getLength(viewLength); 633 return _vertical ? itemViewFactory.width : getLength(viewLength);
628 } 634 }
629 635
630 int getHeight(int viewLength) { 636 int getHeight(int viewLength) {
631 return _vertical ? getLength(viewLength) : itemViewFactory.height; 637 return _vertical ? getLength(viewLength) : itemViewFactory.height;
632 } 638 }
633 639
634 int getEstimatedHeight(int viewLength) { 640 int getEstimatedHeight(int viewLength) {
635 // Returns the exact height as it is trivial to compute for this layout. 641 // Returns the exact height as it is trivial to compute for this layout.
636 return getHeight(viewLength); 642 return getHeight(viewLength);
637 } 643 }
638 644
639 int getEstimatedWidth(int viewLength) { 645 int getEstimatedWidth(int viewLength) {
640 // Returns the exact height as it is trivial to compute for this layout. 646 // Returns the exact height as it is trivial to compute for this layout.
641 return getWidth(viewLength); 647 return getWidth(viewLength);
642 } 648 }
643 649
644 int getEstimatedLength(int viewLength) { 650 int getEstimatedLength(int viewLength) {
645 // Returns the exact length as it is trivial to compute for this layout. 651 // Returns the exact length as it is trivial to compute for this layout.
646 return getLength(viewLength); 652 return getLength(viewLength);
647 } 653 }
648 654
649 int getLength(int viewLength) { 655 int getLength(int viewLength) {
650 int itemLength = 656 int itemLength = _vertical ? itemViewFactory.height : itemViewFactory.width;
651 _vertical ? itemViewFactory.height : itemViewFactory.width;
652 if (viewLength == null || viewLength == 0) { 657 if (viewLength == null || viewLength == 0) {
653 return itemLength * _data.length; 658 return itemLength * _data.length;
654 } else if (_paginate) { 659 } else if (_paginate) {
655 if (_data.length > 0) { 660 if (_data.length > 0) {
656 final pageLength = getPageLength(viewLength); 661 final pageLength = getPageLength(viewLength);
657 return getPage(_data.length - 1, viewLength) 662 return getPage(_data.length - 1, viewLength) * pageLength +
658 * pageLength + Math.max(viewLength, pageLength); 663 Math.max(viewLength, pageLength);
659 } else { 664 } else {
660 return 0; 665 return 0;
661 } 666 }
662 } else { 667 } else {
663 return itemLength * (_data.length - 1) + Math.max(viewLength, itemLength); 668 return itemLength * (_data.length - 1) + Math.max(viewLength, itemLength);
664 } 669 }
665 } 670 }
666 671
667 int getOffset(int index) { 672 int getOffset(int index) {
668 return index * _itemLength; 673 return index * _itemLength;
(...skipping 29 matching lines...) Expand all
698 targetIntervalStart, 703 targetIntervalStart,
699 _data.length); 704 _data.length);
700 return new Interval(targetIntervalStart, targetIntervalEnd.toInt()); 705 return new Interval(targetIntervalStart, targetIntervalEnd.toInt());
701 } 706 }
702 } 707 }
703 708
704 /** 709 /**
705 * Simple list view class where each item has fixed width and height. 710 * Simple list view class where each item has fixed width and height.
706 */ 711 */
707 class ListView<D> extends GenericListView<D> { 712 class ListView<D> extends GenericListView<D> {
708
709 /** 713 /**
710 * Creates a new ListView for the given data. If [:_data:] is an 714 * Creates a new ListView for the given data. If [:_data:] is an
711 * [:ObservableList<T>:] then it will listen to changes to the list and 715 * [:ObservableList<T>:] then it will listen to changes to the list and
712 * update the view appropriately. 716 * update the view appropriately.
713 */ 717 */
714 ListView(List<D> data, ViewFactory<D> itemViewFactory, bool scrollable, 718 ListView(List<D> data, ViewFactory<D> itemViewFactory, bool scrollable,
715 bool vertical, ObservableValue<D> selectedItem, 719 bool vertical, ObservableValue<D> selectedItem,
716 [bool snapToItems = false, 720 [bool snapToItems = false,
717 bool paginate = false, 721 bool paginate = false,
718 bool removeClippedViews = false, 722 bool removeClippedViews = false,
719 bool showScrollbar = false, 723 bool showScrollbar = false,
720 PageState pages = null]) 724 PageState pages = null])
721 : super(new FixedSizeListViewLayout<D>(itemViewFactory, data, vertical, 725 : super(
722 paginate), 726 new FixedSizeListViewLayout<D>(
723 data, scrollable, vertical, selectedItem, snapToItems, paginate, 727 itemViewFactory, data, vertical, paginate),
724 removeClippedViews, showScrollbar, pages); 728 data,
729 scrollable,
730 vertical,
731 selectedItem,
732 snapToItems,
733 paginate,
734 removeClippedViews,
735 showScrollbar,
736 pages);
725 } 737 }
726 738
727 /** 739 /**
728 * Layout where each item may have variable size along the axis the list view 740 * Layout where each item may have variable size along the axis the list view
729 * extends. 741 * extends.
730 */ 742 */
731 class VariableSizeListViewLayout<D> implements ListViewLayout<D> { 743 class VariableSizeListViewLayout<D> implements ListViewLayout<D> {
732 List<D> _data; 744 List<D> _data;
733 List<int> _itemOffsets; 745 List<int> _itemOffsets;
734 List<int> _lengths; 746 List<int> _lengths;
735 int _lastOffset = 0; 747 int _lastOffset = 0;
736 bool _vertical; 748 bool _vertical;
737 bool _paginate; 749 bool _paginate;
738 VariableSizeViewFactory<D> itemViewFactory; 750 VariableSizeViewFactory<D> itemViewFactory;
739 Interval _lastVisibleInterval; 751 Interval _lastVisibleInterval;
740 752
741 VariableSizeListViewLayout(this.itemViewFactory, data, this._vertical, 753 VariableSizeListViewLayout(
742 this._paginate) : 754 this.itemViewFactory, data, this._vertical, this._paginate)
743 _data = data, 755 : _data = data,
744 _lastVisibleInterval = new Interval(0, 0) { 756 _lastVisibleInterval = new Interval(0, 0) {
745 _itemOffsets = <int>[]; 757 _itemOffsets = <int>[];
746 _lengths = <int>[]; 758 _lengths = <int>[];
747 _itemOffsets.add(0); 759 _itemOffsets.add(0);
748 } 760 }
749 761
750 void onDataChange() { 762 void onDataChange() {
751 _itemOffsets.clear(); 763 _itemOffsets.clear();
752 _itemOffsets.add(0); 764 _itemOffsets.add(0);
753 _lengths.clear(); 765 _lengths.clear();
754 } 766 }
755 767
756 View newView(int index) => itemViewFactory.newView(_data[index]); 768 View newView(int index) => itemViewFactory.newView(_data[index]);
757 769
758 int getWidth(int viewLength) { 770 int getWidth(int viewLength) {
759 if (_vertical) { 771 if (_vertical) {
760 return itemViewFactory.getWidth(null); 772 return itemViewFactory.getWidth(null);
761 } else { 773 } else {
762 return getLength(viewLength); 774 return getLength(viewLength);
(...skipping 30 matching lines...) Expand all
793 if (_lengths.length == _data.length) { 805 if (_lengths.length == _data.length) {
794 // No need to estimate... we have all the data already. 806 // No need to estimate... we have all the data already.
795 return getLength(viewLength); 807 return getLength(viewLength);
796 } 808 }
797 if (_itemOffsets.length > 1 && _lengths.length > 0) { 809 if (_itemOffsets.length > 1 && _lengths.length > 0) {
798 // Estimate length by taking the average of the lengths 810 // Estimate length by taking the average of the lengths
799 // of the known views. 811 // of the known views.
800 num lengthFromAllButLastElement = 0; 812 num lengthFromAllButLastElement = 0;
801 if (_itemOffsets.length > 2) { 813 if (_itemOffsets.length > 2) {
802 lengthFromAllButLastElement = 814 lengthFromAllButLastElement =
803 (getOffset(_itemOffsets.length - 2) - 815 (getOffset(_itemOffsets.length - 2) - getOffset(0)) *
804 getOffset(0)) * 816 (_data.length / (_itemOffsets.length - 2));
805 (_data.length / (_itemOffsets.length - 2));
806 } 817 }
807 return (lengthFromAllButLastElement + 818 return (lengthFromAllButLastElement +
808 Math.max(viewLength, _lengths[_lengths.length - 1])).toInt(); 819 Math.max(viewLength, _lengths[_lengths.length - 1]))
820 .toInt();
809 } else { 821 } else {
810 if (_lengths.length == 1) { 822 if (_lengths.length == 1) {
811 return Math.max(viewLength, _lengths[0]); 823 return Math.max(viewLength, _lengths[0]);
812 } else { 824 } else {
813 return viewLength; 825 return viewLength;
814 } 826 }
815 } 827 }
816 } 828 }
817 829
818 int getLength(int viewLength) { 830 int getLength(int viewLength) {
819 if (_data.length == 0) { 831 if (_data.length == 0) {
820 return viewLength; 832 return viewLength;
821 } else { 833 } else {
822 // Hack so that _lengths[length - 1] is available. 834 // Hack so that _lengths[length - 1] is available.
823 getOffset(_data.length); 835 getOffset(_data.length);
824 return (getOffset(_data.length - 1) - getOffset(0)) + 836 return (getOffset(_data.length - 1) - getOffset(0)) +
825 Math.max(_lengths[_lengths.length - 1], viewLength); 837 Math.max(_lengths[_lengths.length - 1], viewLength);
826 } 838 }
827 } 839 }
828 840
829 int getOffset(int index) { 841 int getOffset(int index) {
830 if (index >= _itemOffsets.length) { 842 if (index >= _itemOffsets.length) {
831 int offset = _itemOffsets[_itemOffsets.length - 1]; 843 int offset = _itemOffsets[_itemOffsets.length - 1];
832 for (int i = _itemOffsets.length; i <= index; i++) { 844 for (int i = _itemOffsets.length; i <= index; i++) {
833 int length = _vertical ? itemViewFactory.getHeight(_data[i - 1]) 845 int length = _vertical
846 ? itemViewFactory.getHeight(_data[i - 1])
834 : itemViewFactory.getWidth(_data[i - 1]); 847 : itemViewFactory.getWidth(_data[i - 1]);
835 offset += length; 848 offset += length;
836 _itemOffsets.add(offset); 849 _itemOffsets.add(offset);
837 _lengths.add(length); 850 _lengths.add(length);
838 } 851 }
839 } 852 }
840 return _itemOffsets[index]; 853 return _itemOffsets[index];
841 } 854 }
842 855
843 int getPage(int index, int viewLength) { 856 int getPage(int index, int viewLength) {
844 // TODO(jacobr): implement. 857 // TODO(jacobr): implement.
845 throw 'Not implemented'; 858 throw 'Not implemented';
846 } 859 }
847 860
848 int getPageStartIndex(int page, int viewLength) { 861 int getPageStartIndex(int page, int viewLength) {
849 // TODO(jacobr): implement. 862 // TODO(jacobr): implement.
850 throw 'Not implemented'; 863 throw 'Not implemented';
851 } 864 }
852 865
853 int getSnapIndex(num offset, int viewLength) { 866 int getSnapIndex(num offset, int viewLength) {
854 for (int i = 1; i < _data.length; i++) { 867 for (int i = 1; i < _data.length; i++) {
855 if (getOffset(i) + getOffset(i - 1) > -offset * 2) { 868 if (getOffset(i) + getOffset(i - 1) > -offset * 2) {
856 return i - 1; 869 return i - 1;
857 } 870 }
858 } 871 }
859 return _data.length - 1; 872 return _data.length - 1;
860 } 873 }
861 874
862 Interval computeVisibleInterval( 875 Interval computeVisibleInterval(
863 num offset, num viewLength, num bufferLength) { 876 num offset, num viewLength, num bufferLength) {
864 offset = offset.toInt(); 877 offset = offset.toInt();
865 int start = _findFirstItemBefore( 878 int start = _findFirstItemBefore(-offset - bufferLength,
866 -offset - bufferLength,
867 _lastVisibleInterval != null ? _lastVisibleInterval.start : 0); 879 _lastVisibleInterval != null ? _lastVisibleInterval.start : 0);
868 int end = _findFirstItemAfter( 880 int end = _findFirstItemAfter(-offset + viewLength + bufferLength,
869 -offset + viewLength + bufferLength,
870 _lastVisibleInterval != null ? _lastVisibleInterval.end : 0); 881 _lastVisibleInterval != null ? _lastVisibleInterval.end : 0);
871 _lastVisibleInterval = new Interval(start, Math.max(start, end)); 882 _lastVisibleInterval = new Interval(start, Math.max(start, end));
872 _lastOffset = offset; 883 _lastOffset = offset;
873 return _lastVisibleInterval; 884 return _lastVisibleInterval;
874 } 885 }
875 886
876 int _findFirstItemAfter(num target, int hint) { 887 int _findFirstItemAfter(num target, int hint) {
877 for (int i = 0; i < _data.length; i++) { 888 for (int i = 0; i < _data.length; i++) {
878 if (getOffset(i) > target) { 889 if (getOffset(i) > target) {
879 return i; 890 return i;
880 } 891 }
881 } 892 }
882 return _data.length; 893 return _data.length;
883 } 894 }
884 895
885 // TODO(jacobr): use hint. 896 // TODO(jacobr): use hint.
886 int _findFirstItemBefore(num target, int hint) { 897 int _findFirstItemBefore(num target, int hint) {
887 // We go search this direction delaying computing the actual view size 898 // We go search this direction delaying computing the actual view size
888 // as long as possible. 899 // as long as possible.
889 for (int i = 1; i < _data.length; i++) { 900 for (int i = 1; i < _data.length; i++) {
890 if (getOffset(i) >= target) { 901 if (getOffset(i) >= target) {
891 return i - 1; 902 return i - 1;
892 } 903 }
893 } 904 }
894 return Math.max(_data.length - 1, 0); 905 return Math.max(_data.length - 1, 0);
895 } 906 }
896 } 907 }
897 908
898 class VariableSizeListView<D> extends GenericListView<D> { 909 class VariableSizeListView<D> extends GenericListView<D> {
899 910 VariableSizeListView(List<D> data, VariableSizeViewFactory<D> itemViewFactory,
900 VariableSizeListView(List<D> data, 911 bool scrollable, bool vertical, ObservableValue<D> selectedItem,
901 VariableSizeViewFactory<D> itemViewFactory, 912 [bool snapToItems = false,
902 bool scrollable, 913 bool paginate = false,
903 bool vertical, 914 bool removeClippedViews = false,
904 ObservableValue<D> selectedItem, 915 bool showScrollbar = false,
905 [bool snapToItems = false, 916 PageState pages = null])
906 bool paginate = false, 917 : super(
907 bool removeClippedViews = false, 918 new VariableSizeListViewLayout(
908 bool showScrollbar = false, 919 itemViewFactory, data, vertical, paginate),
909 PageState pages = null]) 920 data,
910 : super(new VariableSizeListViewLayout(itemViewFactory, data, vertical, 921 scrollable,
911 paginate), 922 vertical,
912 data, scrollable, vertical, selectedItem, snapToItems, 923 selectedItem,
913 paginate, removeClippedViews, showScrollbar, pages); 924 snapToItems,
925 paginate,
926 removeClippedViews,
927 showScrollbar,
928 pages);
914 } 929 }
915 930
916 /** A back button that is equivalent to clicking "back" in the browser. */ 931 /** A back button that is equivalent to clicking "back" in the browser. */
917 class BackButton extends View { 932 class BackButton extends View {
918 BackButton() : super(); 933 BackButton() : super();
919 934
920 Element render() => new Element.html('<div class="back-arrow button"></div>'); 935 Element render() => new Element.html('<div class="back-arrow button"></div>');
921 936
922 void afterRender(Element node) { 937 void afterRender(Element node) {
923 addOnClick((e) => window.history.back()); 938 addOnClick((e) => window.history.back());
924 } 939 }
925 } 940 }
926 941
927
928 // TODO(terry): Maybe should be part of ButtonView class in appstack/view? 942 // TODO(terry): Maybe should be part of ButtonView class in appstack/view?
929 /** OS button. */ 943 /** OS button. */
930 class PushButtonView extends View { 944 class PushButtonView extends View {
931 final String _text; 945 final String _text;
932 final String _cssClass; 946 final String _cssClass;
933 final _clickHandler; 947 final _clickHandler;
934 948
935 PushButtonView(this._text, this._cssClass, this._clickHandler) : super(); 949 PushButtonView(this._text, this._cssClass, this._clickHandler) : super();
936 950
937 Element render() { 951 Element render() {
938 return new Element.html('<button class="${_cssClass}">${_text}</button>'); 952 return new Element.html('<button class="${_cssClass}">${_text}</button>');
939 } 953 }
940 954
941 void afterRender(Element node) { 955 void afterRender(Element node) {
942 addOnClick(_clickHandler); 956 addOnClick(_clickHandler);
943 } 957 }
944 } 958 }
945 959
946
947 // TODO(terry): Add a drop shadow around edge and corners need to be rounded. 960 // TODO(terry): Add a drop shadow around edge and corners need to be rounded.
948 // Need to support conveyor for contents of dialog so it's not 961 // Need to support conveyor for contents of dialog so it's not
949 // larger than the parent window. 962 // larger than the parent window.
950 /** A generic dialog view supports title, done button and dialog content. */ 963 /** A generic dialog view supports title, done button and dialog content. */
951 class DialogView extends View { 964 class DialogView extends View {
952 final String _title; 965 final String _title;
953 final String _cssName; 966 final String _cssName;
954 final View _content; 967 final View _content;
955 Element container; 968 Element container;
956 PushButtonView _done; 969 PushButtonView _done;
957 970
958 DialogView(this._title, this._cssName, this._content) : super() {} 971 DialogView(this._title, this._cssName, this._content) : super() {}
959 972
960 Element render() { 973 Element render() {
961 final node = new Element.html(''' 974 final node = new Element.html('''
962 <div class="dialog-modal"> 975 <div class="dialog-modal">
963 <div class="dialog $_cssName"> 976 <div class="dialog $_cssName">
964 <div class="dialog-title-area"> 977 <div class="dialog-title-area">
965 <span class="dialog-title">$_title</span> 978 <span class="dialog-title">$_title</span>
966 </div> 979 </div>
967 <div class="dialog-body"></div> 980 <div class="dialog-body"></div>
968 </div> 981 </div>
969 </div>'''); 982 </div>''');
970 983
971 _done = new PushButtonView('Done', 'done-button', 984 _done = new PushButtonView(
972 EventBatch.wrap((e) => onDone())); 985 'Done', 'done-button', EventBatch.wrap((e) => onDone()));
973 final titleArea = node.querySelector('.dialog-title-area'); 986 final titleArea = node.querySelector('.dialog-title-area');
974 titleArea.nodes.add(_done.node); 987 titleArea.nodes.add(_done.node);
975 988
976 container = node.querySelector('.dialog-body'); 989 container = node.querySelector('.dialog-body');
977 container.nodes.add(_content.node); 990 container.nodes.add(_content.node);
978 991
979 return node; 992 return node;
980 } 993 }
981 994
982 /** Override to handle dialog done. */ 995 /** Override to handle dialog done. */
983 void onDone() { } 996 void onDone() {}
984 } 997 }
OLDNEW
« no previous file with comments | « samples-dev/swarm/UIState.dart ('k') | samples-dev/swarm/swarm_ui_lib/base/AnimationScheduler.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698