Esempio n. 1
0
        /// <summary>
        /// Expand part of the specified lazy box.
        /// Todo: implement firstItemToExpand, limItemToExpand.
        /// </summary>
        internal void ExpandItems(LazyBox <T> source, int firstItemToExpand, int limItemToExpand,
                                  int topOfFirstItemToExpand, int bottomOfLastItemToExpand)
        {
            var root          = ContainingBox.Root;
            int oldRootHeight = root.Height;
            var builder       = ContainingBox.Builder;

            builder.CurrentHookup = this;
            var objects = new T[limItemToExpand - firstItemToExpand];

            source.Items.CopyTo(firstItemToExpand, objects, 0, limItemToExpand - firstItemToExpand);
            int insertAt = Children.IndexOf(source);             // default, insert in place of source (or before it).

            if (firstItemToExpand > 0)
            {
                // we will keep source to represent the unexpanded items at the start.
                insertAt += 1;                 // insert right after source.
                if (limItemToExpand < source.Items.Count)
                {
                    // We will have to make a new lazy box to insert after the expanded items
                    var newLazyBox = new LazyBox <T>(source.Style, this,
                                                     source.Items.Skip(limItemToExpand));
                    Children.Insert(insertAt, newLazyBox);
                    ContainingBox.InsertBox(newLazyBox, source);
                    // We will still insert the expanded items after source, before newLazyBox.
                }
                // Remove the items no longer considered part of source.
                source.RemoveItems(firstItemToExpand, source.Items.Count - firstItemToExpand);
            }
            else if (limItemToExpand < source.Items.Count)
            {
                // We will keep source to represent the unexpanded items at the end.
                source.RemoveItems(0, limItemToExpand);
            }
            else
            {
                // Everything is being expanded: get rid of source altogether.
                ContainingBox.RemoveBoxes(source, source);
                Children.RemoveAt(insertAt);                 // get rid of the lazy box from hookup collection
            }

            // Generate the new items.
            for (int i = 0; i < objects.Length; i++)
            {
                BuildAnItemDisplay(builder, objects[i], insertAt + i);
            }
            using (var gh = ContainingBox.Root.Site.DrawingInfo)
            {
                ContainingBox.RelayoutWithParents(gh, true);
            }

            // Notify root of changed overall size and possibly scroll position.
            root.RaiseLazyExpanded(new RootBox.LazyExpandedEventArgs()
            {
                EstimatedTop    = topOfFirstItemToExpand,
                EstimatedBottom = bottomOfLastItemToExpand, DeltaHeight = root.Height - oldRootHeight
            });
        }
        ///// <summary>
        /////  Update the display of the objects from min to lim (whether or not the sequence of objects has changed).
        ///// </summary>
        //public void UpdateDisplayOfSubSequence(int min, int lim)
        //{
        //    UpdateDisplayOfSubSequence(Fetcher().ToList(), min, lim, lim);
        //}
        /// <summary>
        /// Given the complete list of Ts that is the current property to be displayed,
        /// we want to replace the old display of objects from firstDiff to limCurrent
        /// with a newly created display of the propContent from firstDiff to limNew.
        /// </summary>
        private void UpdateDisplayOfSubSequence(List <T> propContent, int firstDiff, int limNew, int limCurrent)
        {
            var builder = ContainingBox.Builder;

            builder.CurrentHookup = this;
            // Items 0 to firstDiff are the same.
            // Items limCurrent to end of current equal items limNew to end of new.
            // Items firstDiff to limCurrent need to be deleted.
            if (limCurrent > firstDiff)
            {
                if (ContainingBox is ParaBox)
                {
                    // remove runs. Enhance: allow for possibly empty items. Allow boxes nested in para.
                    var firstDelChild = (LiteralStringParaHookup)((ItemHookup)Children[firstDiff]).Children.First();
                    var lastDelChild  = (LiteralStringParaHookup)((ItemHookup)Children[limCurrent - 1]).Children.Last();
                    ((ParaBox)ContainingBox).RemoveRuns(firstDelChild.ClientRunIndex,
                                                        lastDelChild.ClientRunIndex - firstDelChild.ClientRunIndex + 1);
                }
                else
                {
                    // remove child boxes. Enhance: allow for possibly empty items.
                    var firstGoner = ((ItemHookup)Children[firstDiff]).FirstBox;
                    var lastGoner  = ((ItemHookup)Children[limCurrent - 1]).LastBox;
                    ContainingBox.RemoveBoxes(firstGoner, lastGoner);
                }
                for (int i = firstDiff; i < limCurrent; i++)
                {
                    var disposeChild = Children[i] as IDisposable;
                    if (disposeChild != null)
                    {
                        disposeChild.Dispose();
                    }
                }
                Children.RemoveRange(firstDiff, limCurrent - firstDiff);
            }
            // Items firstDiff to limNew are new and must be inserted.
            for (int i = firstDiff; i < limNew; i++)
            {
                BuildAnItemDisplay(builder, propContent[i], i);
            }
            using (var gh = ContainingBox.Root.Site.DrawingInfo)
            {
                ContainingBox.RelayoutWithParents(gh);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Sent when the contents of the property we are monitoring changes.
        /// </summary>
        public override void PropChanged(object sender, EventArgs args)
        {
            var builder = ContainingBox.Builder;

            builder.CurrentHookup = this;
            var newT     = Fetcher();
            var currentT = (T)Children[0].Target;

            if (ContainingBox is ParaBox)
            {
                // remove runs. Enhance: allow for possibly empty items. Allow boxes nested in para.
                var firstDelChild = (LiteralStringParaHookup)((ItemHookup)Children[0]).Children.First();
                ((ParaBox)ContainingBox).RemoveRuns(firstDelChild.ClientRunIndex, 1);
            }
            else
            {
                // remove child boxes. Enhance: allow for possibly empty items.
                var firstGoner = ((ItemHookup)Children[0]).FirstBox;
                var lastGoner  = ((ItemHookup)Children[0]).LastBox;
                if (firstGoner != null || lastGoner != null)
                {
                    ContainingBox.RemoveBoxes(firstGoner, lastGoner);
                }
            }
            var disposeChild = Children[0] as IDisposable;

            if (disposeChild != null)
            {
                disposeChild.Dispose();
            }
            Children.RemoveRange(0, 1);
            // Items firstDiff to limNew are new and must be inserted.
            BuildAnItemDisplay(builder, newT, 0);
            using (var gh = ContainingBox.Root.Site.DrawingInfo)
            {
                ContainingBox.RelayoutWithParents(gh);
            }
        }
        public TestCaseCachedBufferedContainer()
            : base(5, 2)
        {
            string[] labels =
            {
                "uncached",
                "cached",
                "uncached with rotation",
                "cached with rotation",
                "uncached with movement",
                "cached with movement",
                "uncached with parent scale",
                "cached with parent scale",
                "uncached with parent scale&fade",
                "cached with parent scale&fade",
            };

            var boxes = new List <ContainingBox>();

            for (int i = 0; i < Rows * Cols; ++i)
            {
                ContainingBox box;

                Cell(i).AddRange(new Drawable[]
                {
                    new SpriteText
                    {
                        Text = labels[i],
                        Font = new FontUsage(size: 20),
                    },
                    box = new ContainingBox(i >= 6, i >= 8)
                    {
                        Child = new CountingBox(i == 2 || i == 3, i == 4 || i == 5)
                        {
                            CacheDrawnFrameBuffer = i % 2 == 1,
                        },
                    }
                });

                boxes.Add(box);
            }

            AddWaitStep("wait for boxes", 5);

            // ensure uncached is always updating children.
            AddAssert("box 0 count > 0", () => boxes[0].Count > 0);
            AddAssert("even box counts equal", () =>
                      boxes[0].Count == boxes[2].Count &&
                      boxes[2].Count == boxes[4].Count &&
                      boxes[4].Count == boxes[6].Count);

            // ensure cached is never updating children.
            AddAssert("box 1 count is 1", () => boxes[1].Count == 1);

            // ensure rotation changes are invalidating cache (for now).
            AddAssert("box 2 count > 0", () => boxes[2].Count > 0);
            AddAssert("box 2 count equals box 3 count", () => boxes[2].Count == boxes[3].Count);

            // ensure cached with only translation is never updating children.
            AddAssert("box 5 count is 1", () => boxes[1].Count == 1);

            // ensure a parent scaling is invalidating cache.
            AddAssert("box 5 count equals box 6 count", () => boxes[5].Count == boxes[6].Count);

            // ensure we don't break on colour invalidations (due to blanket invalidation logic in Drawable.Invalidate).
            AddAssert("box 7 count equals box 8 count", () => boxes[7].Count == boxes[8].Count);
        }
Esempio n. 5
0
        public override void PropChanged(object sender, EventArgs args)
        {
            var builder = ContainingBox.Builder;

            builder.CurrentHookup = this;
            var newItems = Fetcher().ToArray();
            // See how much we can keep at the start of the sequence;
            int firstChildToReplace = 0;
            int firstItemToReplace  = 0;

            while (firstChildToReplace < Children.Count)
            {
                var group = ((IItemsHookup)Children[firstChildToReplace]).ItemGroup;
                if (!DoesGroupMatch(group, newItems, firstItemToReplace))
                {
                    break;
                }
                firstChildToReplace++;
                firstItemToReplace += group.Length;
            }
            // See how much we can keep at the end of the sequence;
            int limChildToReplace = Children.Count;
            int limItemToReplace  = newItems.Length;

            while (limChildToReplace > firstChildToReplace)
            {
                var group = ((IItemsHookup)Children[limChildToReplace - 1]).ItemGroup;
                if (!DoesGroupMatch(group, newItems, limItemToReplace - group.Length))
                {
                    break;
                }
                limChildToReplace--;
                limItemToReplace -= group.Length;
            }
            Box firstBoxToRemove = null;

            for (int i = firstChildToReplace; i < limChildToReplace && firstBoxToRemove == null; i++)
            {
                firstBoxToRemove = ((IItemsHookup)Children[i]).FirstBox;
            }
            Box lastBoxToRemove = GetLastBoxInRange(firstChildToReplace, limChildToReplace);

            Children.RemoveRange(firstChildToReplace, limChildToReplace - firstChildToReplace);
            if (firstBoxToRemove != null)
            {
                ContainingBox.RemoveBoxes(firstBoxToRemove, lastBoxToRemove);
            }
            if (limItemToReplace > firstItemToReplace)
            {
                var lazyBox = new LazyBox <T>(builder.NestedBoxStyles, this,
                                              newItems.Skip(firstItemToReplace).Take(limItemToReplace - firstItemToReplace));
                ContainingBox.InsertBox(lazyBox, GetLastBoxInRange(0, firstChildToReplace));
                Children.Insert(firstChildToReplace, lazyBox);
                using (var gh = ContainingBox.Root.Site.DrawingInfo)
                {
                    lazyBox.RelayoutWithParents(gh);
                }
            }
            else if (limChildToReplace > firstChildToReplace)
            {
                // pure deletion.
                using (var gh = ContainingBox.Root.Site.DrawingInfo)
                {
                    ContainingBox.RelayoutWithParents(gh);
                }
            }
        }