| Index: runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart
|
| diff --git a/runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart b/runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..da3539ef7c0f88bed37e4f4642281f0c63c9bf3f
|
| --- /dev/null
|
| +++ b/runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart
|
| @@ -0,0 +1,108 @@
|
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +import 'dart:async';
|
| +
|
| +import 'package:observatory/src/elements/helpers/rendering_queue.dart';
|
| +export 'package:observatory/src/elements/helpers/rendering_queue.dart';
|
| +
|
| +/// A generic renderable object.
|
| +abstract class Renderable {
|
| + void render();
|
| +}
|
| +
|
| +/// Event related to a Renderable rendering phase.
|
| +class RenderedEvent<T extends Renderable> {
|
| + /// Renderable to which the event is related
|
| + final T element;
|
| + /// Is another rendering scheduled for this element.
|
| + final bool otherRenderScheduled;
|
| +
|
| + RenderedEvent(this.element, this.otherRenderScheduled) {
|
| + assert(element != null);
|
| + assert(otherRenderScheduled != null);
|
| + }
|
| +}
|
| +
|
| +/// Scheduler for rendering operations.
|
| +class RenderingScheduler<T extends Renderable> implements RenderingTask {
|
| + bool _enabled = false;
|
| + bool _dirty = false;
|
| + bool _renderingScheduled = false;
|
| + bool _notificationScheduled = false;
|
| + /// Element managed by this scheduler.
|
| + final T element;
|
| + /// Queue used for rendering operations.
|
| + final RenderingQueue queue;
|
| +
|
| + final StreamController<RenderedEvent<T>> _onRendered =
|
| + new StreamController<RenderedEvent<T>>.broadcast();
|
| + Stream<RenderedEvent<T>> get onRendered => _onRendered.stream;
|
| +
|
| + /// Creates a new scheduler for an element.
|
| + /// If no queue is provided it will create a new default configured queue.
|
| + factory RenderingScheduler(T element, {RenderingQueue queue}) {
|
| + assert(element != null);
|
| + if (queue == null) { queue = new RenderingQueue(); }
|
| + return new RenderingScheduler<T>._(element, queue);
|
| + }
|
| +
|
| + RenderingScheduler._(this.element, this.queue);
|
| +
|
| + /// Enable the scheduler.
|
| + /// New dirty or schedule request will be considered.
|
| + void enable() {
|
| + if (_enabled) return;
|
| + _enabled = true;
|
| + scheduleRendering();
|
| + }
|
| +
|
| + /// Disable the scheduler.
|
| + /// New dirty or schedule request will be discarded.
|
| + /// [optional] notify: send a final RenderEvent.
|
| + void disable({bool notify: false}) {
|
| + assert(notify != null);
|
| + if (!_enabled) return;
|
| + _enabled = false;
|
| + if (notify) scheduleNotification();
|
| + }
|
| +
|
| + /// Set the object as dirty. A rendering will be scheduled.
|
| + void dirty() {
|
| + if (_dirty) return;
|
| + _dirty = true;
|
| + scheduleRendering();
|
| + }
|
| +
|
| + /// Schedules a new rendering phase.
|
| + void scheduleRendering() {
|
| + if (_renderingScheduled) return;
|
| + if (!_enabled) return;
|
| + queue.enqueue(this);
|
| + _renderingScheduled = true;
|
| + }
|
| +
|
| + /// Renders the element (if the scheduler is enabled).
|
| + /// It will clear the dirty flag.
|
| + void render() {
|
| + if (!_enabled) return;
|
| + _dirty = false;
|
| + element.render();
|
| + _renderingScheduled = false;
|
| + scheduleNotification();
|
| + if (_dirty) scheduleRendering();
|
| + }
|
| +
|
| + /// Schedules a notification.
|
| + void scheduleNotification() {
|
| + if (_notificationScheduled) return;
|
| + _notify();
|
| + _notificationScheduled = true;
|
| + }
|
| +
|
| + Future _notify() async {
|
| + _onRendered.add(new RenderedEvent<T>(element, _dirty));
|
| + _notificationScheduled = false;
|
| + }
|
| +}
|
|
|