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