I have manage to fix the problem of super inside super does not measure correctly by caching the calculated super bounds and use them during the DoLayout operation.
This is the code:
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> private HashSet Invalids = new HashSet();
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> private Dictionary<object, Rect> superMeasures = new Dictionary<object, Rect>();
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”>
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> public override void DoLayout(IEnumerable nodes, IEnumerable links) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> // collect “Super” data to be laid out
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> var supers = new HashSet();
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> // look for any new “Super” nodes
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> foreach (var super in nodes.Where(n => n.Category == “Super”)) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (Double.IsNaN(super.Location.X)) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> var sdata = super.Data as State;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (sdata != null) supers.Add(sdata);
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> var model = this.Diagram.Model;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> foreach (var sid in this.Invalids) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> var sdata = model.FindNodeByKey(sid) as State;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (sdata != null) supers.Add(sdata);
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”>
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> // Repeatedly go through SUPERS collection to layout
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> // those “Super” nodes that don’t have any nested invalid “Super” nodes.
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> while (supers.Count > 0) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> var delay = new HashSet();
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> // set size and location for each invalidated Super state
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> foreach (var sdata in supers) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (SuperIsReady(sdata, supers)) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> LayoutSuper(sdata);
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> else {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> delay.Add(sdata);
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> supers = delay;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”>
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> Invalids.Clear();
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> superMeasures.Clear();
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”>
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> private bool SuperIsReady(State sdata, HashSet supers) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> foreach (var mdata in sdata.Members) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (supers.Contains(mdata)) return false;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> return true;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”>
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> private void LayoutSuper(State sdata) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (sdata == null) return;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> var model = this.Diagram.Model;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> var mgr = this.Diagram.PartManager;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> Node super = mgr.FindNodeForData(sdata, model);
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (super != null) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> Rect bounds = ComputerBounds(sdata.Members.Select(d => mgr.FindNodeForData(d, model) as Part));
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (!bounds.IsEmpty) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> super.Location = new Point(bounds.X - 5, bounds.Y - 20);
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> var shape = super.FindNamedDescendant(“Shape”);
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (shape != null) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> shape.Width = bounds.Width + 10;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> shape.Height = bounds.Height + 25;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”>
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> superMeasures.Add(sdata, new Rect(super.Location, new Size(shape.Width, shape.Height)));
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”>
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> private Rect ComputerBounds(IEnumerable parts) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> double top = double.MaxValue,
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> right = double.MinValue,
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> bottom = double.MinValue,
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> left = double.MaxValue;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”>
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> foreach (var part in parts) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> Rect elementBounds;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (!superMeasures.TryGetValue(part.Data, out elementBounds)) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> elementBounds = part.GetElementBounds(part.VisualElement);
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if ((
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> ((elementBounds.Width != 0.0) ||
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> (elementBounds.Height != 0.0)) ||
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> ((elementBounds.X != 0.0) || (elementBounds.Y != 0.0))) &&
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> (!double.IsNaN(elementBounds.X) && !double.IsNaN(elementBounds.Y))
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> ) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (elementBounds.Left < left) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> left = elementBounds.Left;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (elementBounds.Top < top) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> top = elementBounds.Top;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (elementBounds.Right > right) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> right = elementBounds.Right;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (elementBounds.Bottom > bottom) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> bottom = elementBounds.Bottom;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”>
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> if (left == double.MaxValue) {
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> return Rect.Empty;
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> return new Rect(left, top, right - left, bottom - top);
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
<font =“apple-style-span”="" face="‘Courier New’, Courier, mono" size=“2”> }
Thank you,
Ido.