API Reference 0.7.1rikulo_layoutLayoutManager

LayoutManager class

The layout mananger that manages the layout controllers (Layout). There is exactly one layout manager per application.

class LayoutManager extends RunOnceViewManager {
 final Map<String, Layout> _layouts;
 final Set<String> _imgWaits;
 final List<_Task> _afters;
 int _inLayout = 0, _inCallback = 0;

 LayoutManager(): _layouts = new HashMap(), _imgWaits = new Set(), _afters = [],
 super(null) {
   addLayout("linear", new LinearLayout());
   addLayout("tile", new TileLayout());

   final freeLayout = new FreeLayout();
   addLayout("none", freeLayout);
   addLayout("", freeLayout);
 }

 /** Adds the layout for the given name.
  */
 Layout addLayout(String name, Layout clayout) {
   final Layout old = _layouts[name];
   _layouts[name] = clayout;
   return old;
 }
 /** Removes the layout of the given name if any.
  */
 Layout removeLayout(String name) {
   return _layouts.remove(name);
 }
 /** Returns the layout of the given name, or null if not found.
  */
 Layout getLayout(String name) {
   return _layouts[name];
 }
 /** Returns the type of the given layout, or null if it is not registered.
  */
 String getType(Layout layout) {
   for (final nm in _layouts.keys)
     if (layout == _layouts[nm])
       return nm;
 }

 /** Handles the layout of the given view.
  */
 void requestLayout(View view, bool immediate, bool descendantOnly) {
   if (!descendantOnly) {
     final View parent = view.parent;
     //Start the layout from parent only if necessary
     //Currently, we start from parent if in some layout, not anchored/popup
     if (view.profile.anchorView == null
     && parent != null && !parent.layout.type.isEmpty)
       view = parent; //start from parent (slower performance but safer)
   }

   if (immediate) flush(view, true); //yes, force the depended task to flush too
   else queue(view);
 }

 /** Returns whether the layout manager is handling the offset and dimension.
  *
  * Notice that it is also false in the event listener
  * (including 'layout' and 'preLayout').
  */
 bool get inLayout => _inLayout > 0 && _inCallback <= 0;

 @override
 void flush([View view, bool force=false]) {
   //ignore flush if not empty (_onImageLoaded will invoke it later)
   if (_imgWaits.isEmpty)
     super.flush(view, force);
   else if (view != null)
     queue(view); //do it later
 }

 @override
 void handle_(View view) {
   ++_inLayout;
   try {
     final mctx = new MeasureContext();
     mctx.preLayout(view); //note: onLayout is called by doLayout

     final parent = view.parent;
     if (parent == null) { //root without anchor
       //including anchored
       rootLayout(mctx, view);
     } else if (view.profile.anchorView != null) {
       new AnchorRelation(parent)
         ._layoutAnchored(mctx, view.profile.anchorView, view);
     } else if (parent.layout.type.isEmpty) {
       mctx.setWidthByProfile(view, () => parent.clientWidth);
       mctx.setHeightByProfile(view, () => parent.clientHeight);
     }

     doLayout(mctx, view);
   } finally {
     if (--_inLayout <= 0 && isQueueEmpty() && !_afters.isEmpty) {
       final List<_Task> afters = new List.from(_afters);
       _afters.clear();
       for (final _Task task in afters)
         task();
     }
   }
 }
 /** Schedules a task to be run after the layout is done.
  * If there is no pending layouts, it will be executed immediately.
  */
 void afterLayout(void task()) {
   if (_inLayout <= 0 && isQueueEmpty())
     task();
   else
     _afters.add(task);
 }

 /** Handles the layout of the given view.
  */
 void doLayout(MeasureContext mctx, View view) {
   if (view.visible) {
     view.layout.handler.doLayout(mctx, view);
     ++_inCallback;
     try {
       view.onLayout_(mctx);
     } finally {
       --_inCallback;
     }
   }
 }

 /** Wait until the given image is loaded.
  * If the width and height of the image is not known in advance, this method
  * shall be called to make the layout manager wait until the image is loaded.
  *
  * Currently, [Image] will invoke this method automatically
  * if the width or height of the image is not specified.
  */
 void waitImageLoaded(String imgURI) {
   if (imgURI != null && !imgURI.isEmpty && !_imgWaits.contains(imgURI)) {
     _imgWaits.add(imgURI);
     final ImageElement img = new Element.tag("img");
     var func = (event) { //DOM event
       _onImageLoaded(imgURI);
     };
     img..onLoad.listen(func)
       ..onError.listen(func)
       ..src = imgURI;
   }
 }
 void _onImageLoaded(String imgURI) {
   _imgWaits.remove(imgURI);
   if (_imgWaits.isEmpty)
     flush(); //flush all
 }
}

Extends

RunOnceViewManager > LayoutManager

Constructors

new LayoutManager() #

Constructor.

  • task is the view-handling task. Notice that if you pass null here, you have override handle_ to handle it.

  • ignoreDetached specifies whether to ignore the views that are not attached to the docuemnt (ie.., ignore views if View.inDocument is false).

  • ignoreSubviews specifies whether to ignore the sub views. In other words, a view will be ignored, if one of its ancestor has been queued for handling too.

docs inherited from RunOnceViewManager
LayoutManager(): _layouts = new HashMap(), _imgWaits = new Set(), _afters = [],
super(null) {
 addLayout("linear", new LinearLayout());
 addLayout("tile", new TileLayout());

 final freeLayout = new FreeLayout();
 addLayout("none", freeLayout);
 addLayout("", freeLayout);
}

Properties

final bool inLayout #

Returns whether the layout manager is handling the offset and dimension.

Notice that it is also false in the event listener (including 'layout' and 'preLayout').

bool get inLayout => _inLayout > 0 && _inCallback <= 0;

Methods

Layout addLayout(String name, Layout clayout) #

Adds the layout for the given name.

Layout addLayout(String name, Layout clayout) {
 final Layout old = _layouts[name];
 _layouts[name] = clayout;
 return old;
}

void addReadyCheck(RunOnceReadyCheck ready) #

inherited from RunOnceViewManager

Adds a callback to check if this manager can handle the views (i.e., whether it has to wait). It is used if you'd like this manage to depend on other conditions.

void addReadyCheck(RunOnceReadyCheck ready) {
 _readyChecks.add(ready);
}

void afterLayout(void task()) #

Schedules a task to be run after the layout is done. If there is no pending layouts, it will be executed immediately.

void afterLayout(void task()) {
 if (_inLayout <= 0 && isQueueEmpty())
   task();
 else
   _afters.add(task);
}

void doLayout(MeasureContext mctx, View view) #

Handles the layout of the given view.

void doLayout(MeasureContext mctx, View view) {
 if (view.visible) {
   view.layout.handler.doLayout(mctx, view);
   ++_inCallback;
   try {
     view.onLayout_(mctx);
   } finally {
     --_inCallback;
   }
 }
}

void flush([View view, bool force = false]) #

Hanldes the give view, if not null, or all queued views, if the give view is null.

  • force specifies whether to force the tasks registered with addReadyCheck
docs inherited from RunOnceViewManager
@override
void flush([View view, bool force=false]) {
 //ignore flush if not empty (_onImageLoaded will invoke it later)
 if (_imgWaits.isEmpty)
   super.flush(view, force);
 else if (view != null)
   queue(view); //do it later
}

Layout getLayout(String name) #

Returns the layout of the given name, or null if not found.

Layout getLayout(String name) {
 return _layouts[name];
}

String getType(Layout layout) #

Returns the type of the given layout, or null if it is not registered.

String getType(Layout layout) {
 for (final nm in _layouts.keys)
   if (layout == _layouts[nm])
     return nm;
}

void handle_(View view) #

Handles the given view. Don't call this method directly. It is called automatically when a view is required to handle.

Default: invoke the task that was assigned in the constructor.

You can override this method if you don't pass a task in the constructor.

docs inherited from RunOnceViewManager
@override
void handle_(View view) {
 ++_inLayout;
 try {
   final mctx = new MeasureContext();
   mctx.preLayout(view); //note: onLayout is called by doLayout

   final parent = view.parent;
   if (parent == null) { //root without anchor
     //including anchored
     rootLayout(mctx, view);
   } else if (view.profile.anchorView != null) {
     new AnchorRelation(parent)
       ._layoutAnchored(mctx, view.profile.anchorView, view);
   } else if (parent.layout.type.isEmpty) {
     mctx.setWidthByProfile(view, () => parent.clientWidth);
     mctx.setHeightByProfile(view, () => parent.clientHeight);
   }

   doLayout(mctx, view);
 } finally {
   if (--_inLayout <= 0 && isQueueEmpty() && !_afters.isEmpty) {
     final List<_Task> afters = new List.from(_afters);
     _afters.clear();
     for (final _Task task in afters)
       task();
   }
 }
}

bool isQueueEmpty([View view]) #

inherited from RunOnceViewManager

Returns if there is no view is queued.

  • view if specified, this method check only if the given view and its descendant views is in the queue.

bool isQueueEmpty([View view]) {
 if (view == null)
   return _views.isEmpty;

 for (final v in _views)
   if (v.isDescendantOf(view))
     return false;
 return true;
}

void queue(View view) #

inherited from RunOnceViewManager

Adds the given view to the queue.

void queue(View view) {
 //we don't check view.inDocument here since it might be attached later
 _views.add(view);
 _runQue.add("", () {flush();}, 0);
}

Layout removeLayout(String name) #

Removes the layout of the given name if any.

Layout removeLayout(String name) {
 return _layouts.remove(name);
}

void requestLayout(View view, bool immediate, bool descendantOnly) #

Handles the layout of the given view.

void requestLayout(View view, bool immediate, bool descendantOnly) {
 if (!descendantOnly) {
   final View parent = view.parent;
   //Start the layout from parent only if necessary
   //Currently, we start from parent if in some layout, not anchored/popup
   if (view.profile.anchorView == null
   && parent != null && !parent.layout.type.isEmpty)
     view = parent; //start from parent (slower performance but safer)
 }

 if (immediate) flush(view, true); //yes, force the depended task to flush too
 else queue(view);
}

void unqueue(View view) #

inherited from RunOnceViewManager

Removes the given view from the queue, so the action won't take place.

void unqueue(View view) {
 _views.remove(view);
}

void waitImageLoaded(String imgURI) #

Wait until the given image is loaded. If the width and height of the image is not known in advance, this method shall be called to make the layout manager wait until the image is loaded.

Currently, Image will invoke this method automatically if the width or height of the image is not specified.

void waitImageLoaded(String imgURI) {
 if (imgURI != null && !imgURI.isEmpty && !_imgWaits.contains(imgURI)) {
   _imgWaits.add(imgURI);
   final ImageElement img = new Element.tag("img");
   var func = (event) { //DOM event
     _onImageLoaded(imgURI);
   };
   img..onLoad.listen(func)
     ..onError.listen(func)
     ..src = imgURI;
 }
}