• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:flutter/foundation.dart';
6import 'package:flutter/widgets.dart';
7
8/// Provides an iterable that efficiently returns all the elements
9/// rooted at the given element. See [CachingIterable] for details.
10///
11/// This method must be called again if the tree changes. You cannot
12/// call this function once, then reuse the iterable after having
13/// changed the state of the tree, because the iterable returned by
14/// this function caches the results and only walks the tree once.
15///
16/// The same applies to any iterable obtained indirectly through this
17/// one, for example the results of calling `where` on this iterable
18/// are also cached.
19Iterable<Element> collectAllElementsFrom(
20  Element rootElement, {
21  @required bool skipOffstage,
22}) {
23  return CachingIterable<Element>(_DepthFirstChildIterator(rootElement, skipOffstage));
24}
25
26class _DepthFirstChildIterator implements Iterator<Element> {
27  _DepthFirstChildIterator(Element rootElement, this.skipOffstage)
28    : _stack = _reverseChildrenOf(rootElement, skipOffstage).toList();
29
30  final bool skipOffstage;
31
32  Element _current;
33
34  final List<Element> _stack;
35
36  @override
37  Element get current => _current;
38
39  @override
40  bool moveNext() {
41    if (_stack.isEmpty)
42      return false;
43
44    _current = _stack.removeLast();
45    // Stack children in reverse order to traverse first branch first
46    _stack.addAll(_reverseChildrenOf(_current, skipOffstage));
47
48    return true;
49  }
50
51  static Iterable<Element> _reverseChildrenOf(Element element, bool skipOffstage) {
52    assert(element != null);
53    final List<Element> children = <Element>[];
54    if (skipOffstage) {
55      element.debugVisitOnstageChildren(children.add);
56    } else {
57      element.visitChildren(children.add);
58    }
59    return children.reversed;
60  }
61}
62