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; |
+ } |
+} |