Example #1
0
        /// <summary>
        /// Initialize a new instance of the MetaPanelBase class.
        /// </summary>
        public MetaPanelBase()
        {
            // List used to collect entries that are to be removed from panel
            _removeList = new MetaElementStateList();

            // Use dictionary to associate each element with its animation state
            _stateDict = new MetaElementStateDict();

            // Create and monitor changes in the layout collection
            _layoutCollection                    = new LayoutCollection(this);
            _layoutCollection.NeedMeasure       += new EventHandler(OnNeedMeasure);
            _layoutCollection.CollectionChanged += new EventHandler(OnNeedMeasure);
            MonitorExtendElement(_layoutCollection);

            // Create and monitor changes in the animate collection
            _animateCollection              = new AnimateDefinitions(this);
            _animateCollection.NeedMeasure += new EventHandler(OnNeedMeasure);
            MonitorExtendElement(_animateCollection);

            // Default layout/animate to be applied as the default in case collections are empty or not applied
            _defaultLayout  = new StretchLayout();
            _defaultAnimate = new NullAnimate();

            // Let the Silverlight/WPF specific construction take place
            PlatformConstructor();
        }
Example #2
0
 /// <summary>
 /// Calculate target state for each element based on layout algorithm.
 /// </summary>
 /// <param name="layoutId">Identifier of the layout to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be arranged.</param>
 /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
 public override void TargetChildren(string layoutId,
                                     MetaPanelBase metaPanel,
                                     MetaElementStateDict stateDict,
                                     ICollection elements,
                                     Size finalSize)
 {
     // Only apply if we match the incoming layout identifier
     if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
     {
         Rect newTargetRect = new Rect(Utility.PointZero, finalSize);
         foreach (UIElement element in elements)
         {
             // We ignore items being removed
             if (stateDict[element].Status != MetaElementStatus.Removing)
             {
                 // Store the new target rectangle
                 if (!stateDict[element].TargetRect.Equals(newTargetRect))
                 {
                     stateDict[element].TargetChanged = true;
                     stateDict[element].TargetRect    = newTargetRect;
                 }
             }
         }
     }
 }
Example #3
0
        private void MeasureElements(MetaElementStateDict stateDict,
                                     ICollection elements)
        {
            foreach (UIElement element in elements)
            {
                // Find the row/col definitions for this element
                int col = Math.Max(0, Math.Min(_columns.Count - 1, GetColumn(element)));
                int row = Math.Max(0, Math.Min(_rows.Count - 1, GetRow(element)));

                // Find the row/col spanning definitions for this element (convert to zero based spanning)
                int colSpan = Math.Max(Math.Min(_columns.Count - col, GetColumnSpan(element)), 1) - 1;
                int rowSpan = Math.Max(Math.Min(_rows.Count - row, GetRowSpan(element)), 1) - 1;

                // Find column width to use for measuring
                int    index        = col;
                double measureWidth = 0;
                do
                {
                    measureWidth += _proxyColumns[index].MeasureSize;
                } while ((measureWidth < double.PositiveInfinity) && (index++ < (col + colSpan)));

                // Find row height to use for measuring
                index = row;
                double measureHeight = 0;
                do
                {
                    measureHeight += _proxyRows[index].MeasureSize;
                } while ((measureWidth < double.PositiveInfinity) && (index++ < (row + rowSpan)));

                stateDict[element].Element.Measure(new Size(measureWidth, measureHeight));
            }
        }
        /// <summary>
        /// Perform animation effects on the set of children.
        /// </summary>
        /// <param name="animateId">Identifier of the animate to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be animated.</param>
        /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
        public override void ApplyAnimation(string animateId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            double elapsedMilliseconds)
        {
            // Only apply if we match the incoming animate identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(animateId))
            {
                foreach (UIElement element in elements)
                {
                    MetaElementState elementState = stateDict[element];

                    // Only interested in elements being removed...
                    if (elementState.Status == MetaElementStatus.Removing)
                    {
                        // ...and having the final target rectangle calculated just the once...
                        if (!elementState.RemoveCalculated)
                        {
                            // Calculate the correct target rectangle
                            Rect positionRect = RectFromSize(Size, RectFromLocation(Location, metaPanel, elementState), elementState);

                            // Update the final target value
                            elementState.TargetRect      = positionRect;
                            elementState.TargetChanged   = true;
                            elementState.AnimateComplete = false;
                        }
                    }
                }
            }

            // Let base class take care of easing animations
            base.ApplyAnimation(animateId, metaPanel, stateDict, elements, elapsedMilliseconds);
        }
        /// <summary>
        /// Perform animation effects on the set of children.
        /// </summary>
        /// <param name="animateId">Identifier of the animate to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be animated.</param>
        /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
        public override void ApplyAnimation(string animateId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            double elapsedMilliseconds)
        {
            // Only apply if we match the incoming animate identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(animateId))
            {
                foreach (UIElement element in elements)
                {
                    MetaElementState elementState = stateDict[element];

                    // If this is a new element that has not had its current rectangle set
                    if ((elementState.Status == MetaElementStatus.New) && elementState.NewCalculating)
                    {
                        elementState.CurrentRect = RectFromSize(Size, RectFromLocation(Location, metaPanel, elementState), elementState);
                        elementState.TargetChanged = true;
                        elementState.AnimateComplete = false;
                    }
                }
            }

            // Let base class take care of easing animations
            base.ApplyAnimation(animateId, metaPanel, stateDict, elements, elapsedMilliseconds);
        }
 /// <summary>
 /// Calculate target state for each element based on layout algorithm.
 /// </summary>
 /// <param name="layoutId">Identifier of the layout to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be arranged.</param>
 /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
 public override void TargetChildren(string layoutId,
                                     MetaPanelBase metaPanel,
                                     MetaElementStateDict stateDict,
                                     ICollection elements,
                                     Size finalSize)
 {
     // Only apply if we match the incoming layout identifier
     if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
     {
         Rect newTargetRect = new Rect(Utility.PointZero, finalSize);
         foreach (UIElement element in elements)
         {
             // We ignore items being removed
             if (stateDict[element].Status != MetaElementStatus.Removing)
             {
                 // Store the new target rectangle
                 if (!stateDict[element].TargetRect.Equals(newTargetRect))
                 {
                     stateDict[element].TargetChanged = true;
                     stateDict[element].TargetRect = newTargetRect;
                 }
             }
         }
     }
 }
        /// <summary>
        /// Perform animation effects on the set of children.
        /// </summary>
        /// <param name="animateId">Identifier of the animate to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be animated.</param>
        /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
        public override void ApplyAnimation(string animateId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            double elapsedMilliseconds)
        {
            // Only apply if we match the incoming animate identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(animateId))
            {
                foreach (UIElement element in elements)
                {
                    MetaElementState elementState = stateDict[element];

                    // Only interested in elements being removed...
                    if (elementState.Status == MetaElementStatus.Removing)
                    {
                        // ...and having the final target rectangle calculated just the once...
                        if (!elementState.RemoveCalculated)
                        {
                            // Calculate the correct target rectangle
                            Rect positionRect = RectFromSize(Size, RectFromLocation(Location, metaPanel, elementState), elementState);

                            // Update the final target value
                            elementState.TargetRect = positionRect;
                            elementState.TargetChanged = true;
                            elementState.AnimateComplete = false;
                        }
                    }
                }
            }

            // Let base class take care of easing animations
            base.ApplyAnimation(animateId, metaPanel, stateDict, elements, elapsedMilliseconds);
        }
Example #8
0
        /// <summary>
        /// Calculate target state for each element based on layout algorithm.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be arranged.</param>
        /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
        public override void TargetChildren(string layoutId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            Size finalSize)
        {
            if (_count > 0)
            {
                // Each child is an equal angle around the radius
                double angleCurrent = StartAngle;
                double diff         = (EndAngle - StartAngle);
                double angleDelta   = diff / ((diff == (double)360) ? _count : _count - 1);

                // Calculate the radius separately for each dimension
                double radiusX = (finalSize.Width - _maxLength * 2) / 2;
                double radiusY = (finalSize.Height - _maxLength * 2) / 2;

                // Do we force into being a circle?
                if (Circle)
                {
                    // Always reduce to using the smallest direction
                    radiusX = Math.Min(radiusX, radiusY);
                    radiusY = radiusX;
                }

                // Rotate around the center point
                Point center = new Point(finalSize.Width / 2, finalSize.Height / 2);

                // Calculate the target rectangle for each element
                foreach (UIElement element in elements)
                {
                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        // We ignore items that are collapsed
                        if (element.Visibility != Visibility.Collapsed)
                        {
                            // Rotate around the center point using the accumulated angle
                            double childX = center.X + Math.Cos(2 * Math.PI * angleCurrent / 360) * radiusX;
                            double childY = center.Y + Math.Sin(2 * Math.PI * angleCurrent / 360) * radiusY;
                            angleCurrent += angleDelta;

                            // Position the element at
                            Size desiredSize   = element.DesiredSize;
                            Rect newTargetRect = new Rect(childX - desiredSize.Width / 2,
                                                          childY - desiredSize.Height / 2,
                                                          desiredSize.Width,
                                                          desiredSize.Height);

                            // Store the new target rectangle
                            if (!stateDict[element].TargetRect.Equals(newTargetRect))
                            {
                                stateDict[element].TargetChanged = true;
                                stateDict[element].TargetRect    = newTargetRect;
                            }
                        }
                    }
                }
            }
        }
Example #9
0
        /// <summary>
        /// Perform animation effects on the set of children.
        /// </summary>
        /// <param name="animateId">Identifier of the animate to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be animated.</param>
        /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
        public override void ApplyAnimation(string animateId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            double elapsedMilliseconds)
        {
            // Only apply if we match the incoming animate identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(animateId))
            {
                foreach (UIElement element in elements)
                {
                    MetaElementState elementState = stateDict[element];

                    // If this is a new element that has not had its current rectangle set
                    if ((elementState.Status == MetaElementStatus.New) && elementState.NewCalculating)
                    {
                        elementState.CurrentRect     = RectFromSize(Size, RectFromLocation(Location, metaPanel, elementState), elementState);
                        elementState.TargetChanged   = true;
                        elementState.AnimateComplete = false;
                    }
                }
            }

            // Let base class take care of easing animations
            base.ApplyAnimation(animateId, metaPanel, stateDict, elements, elapsedMilliseconds);
        }
Example #10
0
 /// <summary>
 /// Perform animation effects on the set of children.
 /// </summary>
 /// <param name="animateId">Identifier of the animate to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be animated.</param>
 /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
 public override void ApplyAnimation(string animateId,
                                     MetaPanelBase metaPanel,
                                     MetaElementStateDict stateDict,
                                     ICollection elements,
                                     double elapsedMilliseconds)
 {
     ApplyAnimation(animateId, metaPanel, stateDict, elements, elapsedMilliseconds, Start, End);
 }
Example #11
0
        /// <summary>
        /// Calculate target state for each element based on layout algorithm.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be arranged.</param>
        /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
        public override void TargetChildren(string layoutId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            Size finalSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Calculate the target rectangle for each element
                foreach (UIElement element in elements)
                {
                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        // Default to being the desired size but at position zero,zero
                        Rect newTargetRect = new Rect(0, 0, element.DesiredSize.Width, element.DesiredSize.Height);

                        // Use the Left or Right value provided as attached properties of the element
                        double left = CanvasLayout.GetLeft(element);
                        if (!double.IsNaN(left))
                        {
                            newTargetRect.X = left;
                        }
                        else
                        {
                            double right = CanvasLayout.GetRight(element);
                            if (!double.IsNaN(right))
                            {
                                newTargetRect.X = (finalSize.Width - element.DesiredSize.Width) - right;
                            }
                        }

                        // Use the Top or Bottom value provided as attached properties of the element
                        double top = CanvasLayout.GetTop(element);
                        if (!double.IsNaN(top))
                        {
                            newTargetRect.Y = top;
                        }
                        else
                        {
                            double bottom = CanvasLayout.GetBottom(element);
                            if (!double.IsNaN(bottom))
                            {
                                newTargetRect.Y = (finalSize.Height - element.DesiredSize.Height) - bottom;
                            }
                        }

                        // Store the new target rectangle
                        if (!stateDict[element].TargetRect.Equals(newTargetRect))
                        {
                            stateDict[element].TargetChanged = true;
                            stateDict[element].TargetRect    = newTargetRect;
                        }
                    }
                }
            }
        }
Example #12
0
 /// <summary>
 /// Calculate target state for each element based on layout algorithm.
 /// </summary>
 /// <param name="layoutId">Identifier of the layout to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be arranged.</param>
 /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
 public void TargetChildren(string layoutId,
                            MetaPanelBase metaPanel,
                            MetaElementStateDict stateDict,
                            ICollection elements,
                            Size finalSize)
 {
     foreach (Layout layout in this)
     {
         layout.TargetChildren(layoutId, metaPanel, stateDict, elements, finalSize);
     }
 }
 /// <summary>
 /// Perform animation effects on the set of children.
 /// </summary>
 /// <param name="animateId">Identifier of the animate to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be animated.</param>
 /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
 public void ApplyAnimation(string animateId,
                            MetaPanelBase metaPanel,
                            MetaElementStateDict stateDict,
                            ICollection elements,
                            double elapsedMilliseconds)
 {
     foreach (Animate animate in this)
     {
         animate.ApplyAnimation(animateId, metaPanel, stateDict, elements, elapsedMilliseconds);
     }
 }
Example #14
0
        /// <summary>
        /// Perform animation effects on the set of children.
        /// </summary>
        /// <param name="animateId">Identifier of the animate to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be animated.</param>
        /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
        /// <param name="startOpacity">Opacity for start of animation.</param>
        /// <param name="endOpacity">Opacity for end of animation.</param>
        public void ApplyAnimation(string animateId,
                                   MetaPanelBase metaPanel,
                                   MetaElementStateDict stateDict,
                                   ICollection elements,
                                   double elapsedMilliseconds,
                                   double startOpacity,
                                   double endOpacity)
        {
            // Only apply if we match the incoming animate identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(animateId))
            {
                // Only grab the dependancy properties once, for improved perf
                double duration = Duration;

                foreach (UIElement element in elements)
                {
                    // Only apply animation to element of required target state
                    MetaElementState elementState = stateDict[element];
                    if (elementState.Status == Target)
                    {
                        // If the element is the correct target and correct status for starting animation
                        if ((!elementState.RemoveCalculated && (Target == MetaElementStatus.Removing)) ||
                            (elementState.NewCalculating && (Target == MetaElementStatus.New)))
                        {
                            // Use the starting opacity
                            element.Opacity = startOpacity;
                            elementState.ElapsedOpacityTime = 0;
                        }
                        else
                        {
                            // Only perform animation if some time has actually ellapsed and not already at target
                            if ((elapsedMilliseconds > 0) && (element.Opacity != (double)endOpacity))
                            {
                                // Add new elapsed time to the animation running time
                                elementState.ElapsedOpacityTime += elapsedMilliseconds;

                                // Does elapsed time indicate animation should have completed?
                                if (elementState.ElapsedOpacityTime >= duration)
                                {
                                    element.Opacity = endOpacity;
                                }
                                else
                                {
                                    element.Opacity = EasingCalculation.Calculate(elementState.ElapsedOpacityTime, startOpacity, endOpacity - startOpacity, duration);
                                }
                            }
                        }

                        // If not yet at target opacity then not finished with animating
                        elementState.AnimateComplete &= (element.Opacity == (double)endOpacity);
                    }
                }
            }
        }
Example #15
0
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Measure each element in turn
                _validCount = 0;
                Size usedSize = new Size();
                Size maxSize  = new Size();
                foreach (UIElement element in elements)
                {
                    // Allow element to have all the remainder size available
                    Size elementSize = new Size(Math.Max(0.0, (double)(availableSize.Width - usedSize.Width)),
                                                Math.Max(0.0, (double)(availableSize.Height - usedSize.Height)));

                    element.Measure(elementSize);

                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        // Discover the used size and the maximum required size for opposite direction
                        Size desiredSize = element.DesiredSize;
                        switch (GetDock(element))
                        {
                        case Dock.Left:
                        case Dock.Right:
                            maxSize.Height  = Math.Max(maxSize.Height, usedSize.Height + desiredSize.Height);
                            usedSize.Width += desiredSize.Width;
                            break;

                        case Dock.Top:
                        case Dock.Bottom:
                            maxSize.Width    = Math.Max(maxSize.Width, usedSize.Width + desiredSize.Width);
                            usedSize.Height += desiredSize.Height;
                            break;
                        }

                        _validCount++;
                    }
                }

                return(new Size(Math.Max(maxSize.Width, usedSize.Width),
                                Math.Max(maxSize.Height, usedSize.Height)));
            }
            else
            {
                return(Size.Empty);
            }
        }
Example #16
0
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Cache the dependancy properties for faster perf
                Orientation orientation = Orientation;

                // Give children as much space as they want in the opposite direction to the stacking
                if (orientation == Orientation.Horizontal)
                {
                    availableSize.Width = double.PositiveInfinity;
                }
                else
                {
                    availableSize.Height = double.PositiveInfinity;
                }

                // Measure each element in turn
                Size measureSize = new Size();
                foreach (UIElement element in elements)
                {
                    element.Measure(availableSize);

                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        // Accumulate in the orientation direction, but track maximum value in the opposite
                        if (orientation == Orientation.Horizontal)
                        {
                            measureSize.Width += element.DesiredSize.Width;
                            measureSize.Height = Math.Max(measureSize.Height, element.DesiredSize.Height);
                        }
                        else
                        {
                            measureSize.Width   = Math.Max(measureSize.Width, element.DesiredSize.Width);
                            measureSize.Height += element.DesiredSize.Height;
                        }
                    }
                }

                return(measureSize);
            }
            else
            {
                return(Size.Empty);
            }
        }
Example #17
0
 /// <summary>
 /// Calculate target state for each element based on layout algorithm.
 /// </summary>
 /// <param name="layoutId">Identifier of the layout to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be arranged.</param>
 /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
 public override void TargetChildren(string layoutId,
                                     MetaPanelBase metaPanel,
                                     MetaElementStateDict stateDict,
                                     ICollection elements,
                                     Size finalSize)
 {
     // Only apply if we match the incoming layout identifier
     if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
     {
         // TODO target elements that are not in tree drawing
         TargetTreeNodes(Utility.PointZero, StartNode, stateDict, false);
     }
 }
Example #18
0
        private Size TargetTreeNodes(Point location,
                                     ITreeNode node,
                                     MetaElementStateDict stateDict,
                                     bool downwards)
        {
            Size totalSize = Utility.SizeZero;

            UIElement element = node as UIElement;

            if ((element != null) && (stateDict.ContainsKey(element)))
            {
                // Do not measure children of items being removed
                if (stateDict[element].Status != MetaElementStatus.Removing)
                {
                    // Starting size covers only the node
                    totalSize = element.DesiredSize;

                    // Process each sub tree
                    Point childLocation  = new Point(location.X + element.DesiredSize.Width, location.Y);
                    Size  childTotalSize = Utility.SizeZero;
                    foreach (ITreeNode child in node.ChildNodes())
                    {
                        Size childSize = TargetTreeNodes(childLocation, child, stateDict, downwards);

                        // Stack all the sub trees vertically in sizing
                        childTotalSize.Width   = Math.Max(childTotalSize.Width, childSize.Width);
                        childTotalSize.Height += childSize.Height;
                        childLocation.Y       += childSize.Height;
                    }

                    // Place the set of sub trees to the right of this node
                    totalSize.Width += childTotalSize.Width;
                    totalSize.Height = Math.Max(totalSize.Height, childTotalSize.Height);
                }

                // Position the node vertically centered
                Rect newTargetRect = new Rect(location.X,
                                              location.Y + (totalSize.Height - element.DesiredSize.Height) / 2,
                                              element.DesiredSize.Width,
                                              element.DesiredSize.Height);

                // Store the new target rectangle
                if (!stateDict[element].TargetRect.Equals(newTargetRect))
                {
                    stateDict[element].TargetChanged = true;
                    stateDict[element].TargetRect    = newTargetRect;
                }
            }

            return(totalSize);
        }
        /// <summary>
        /// Calculate target state for each element based on layout algorithm.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be arranged.</param>
        /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
        public override void TargetChildren(string layoutId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            Size finalSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Find the size of each size and start at the top left cell
                Rect cellRect = new Rect(0, 0, finalSize.Width / (double)_columns, finalSize.Height / (double)_rows);

                // Move across to the defined starting column
                cellRect.X += cellRect.Width * FirstColumn;

                // Calculate the right hand side where we need to start a new row
                double finalSizeRight = finalSize.Width - 1.0;

                // Calculate the target rectangle for each element
                foreach (UIElement element in elements)
                {
                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        // We ignore items that are collapsed from view
                        if (element.Visibility != Visibility.Collapsed)
                        {
                            // The new target is the current cell rect
                            Rect newTargetRect = cellRect;

                            // Move across to next column
                            cellRect.X += cellRect.Width;

                            // Do we start a line row?
                            if (cellRect.X >= finalSizeRight)
                            {
                                cellRect.X  = 0;
                                cellRect.Y += cellRect.Height;
                            }

                            // Store the new target rectangle
                            if (!stateDict[element].TargetRect.Equals(newTargetRect))
                            {
                                stateDict[element].TargetChanged = true;
                                stateDict[element].TargetRect    = newTargetRect;
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Perform animation effects on the set of children.
        /// </summary>
        /// <param name="animateId">Identifier of the animate to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be animated.</param>
        /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
        /// <param name="startOpacity">Opacity for start of animation.</param>
        /// <param name="endOpacity">Opacity for end of animation.</param>
        public void ApplyAnimation(string animateId,
                                   MetaPanelBase metaPanel,
                                   MetaElementStateDict stateDict,
                                   ICollection elements,
                                   double elapsedMilliseconds,
                                   double startOpacity,
                                   double endOpacity)
        {
            // Only apply if we match the incoming animate identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(animateId))
            {
                // Only grab the dependancy properties once, for improved perf
                double duration = Duration;

                foreach (UIElement element in elements)
                {
                    // Only apply animation to element of required target state
                    MetaElementState elementState = stateDict[element];
                    if (elementState.Status == Target)
                    {
                        // If the element is the correct target and correct status for starting animation
                        if ((!elementState.RemoveCalculated && (Target == MetaElementStatus.Removing)) ||
                            (elementState.NewCalculating && (Target == MetaElementStatus.New)))
                        {
                            // Use the starting opacity
                            element.Opacity = startOpacity;
                            elementState.ElapsedOpacityTime = 0;
                        }
                        else
                        {
                            // Only perform animation if some time has actually ellapsed and not already at target
                            if ((elapsedMilliseconds > 0) && (element.Opacity != (double)endOpacity))
                            {
                                // Add new elapsed time to the animation running time
                                elementState.ElapsedOpacityTime += elapsedMilliseconds;

                                // Does elapsed time indicate animation should have completed?
                                if (elementState.ElapsedOpacityTime >= duration)
                                    element.Opacity = endOpacity;
                                else
                                    element.Opacity = EasingCalculation.Calculate(elementState.ElapsedOpacityTime, startOpacity, endOpacity - startOpacity, duration);
                            }
                        }

                        // If not yet at target opacity then not finished with animating
                        elementState.AnimateComplete &= (element.Opacity == (double)endOpacity);
                    }
                }
            }
        }
Example #21
0
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // TODO measure elements that are not in tree drawing
                return(MeasureTreeNodes(StartNode, stateDict, false));
            }

            return(Size.Empty);
        }
Example #22
0
        /// <summary>
        /// Position child elements according to already calculated target state.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be arranged.</param>
        /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
        /// <returns>Size used by the layout panel.</returns>
        public Size ArrangeChildren(string layoutId,
                                    MetaPanelBase metaPanel,
                                    MetaElementStateDict stateDict,
                                    ICollection elements,
                                    Size finalSize)
        {
            foreach (UIElement element in elements)
            {
                MetaElementState elementState = stateDict[element];
                elementState.Element.Arrange(elementState.CurrentRect);
            }

            // Layout panel takes all the provided size
            return(finalSize);
        }
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // TODO measure elements that are not in tree drawing
                return MeasureTreeNodes(StartNode, stateDict, false);
            }

            return Size.Empty;
        }
 /// <summary>
 /// Perform animation effects on the set of children.
 /// </summary>
 /// <param name="animateId">Identifier of the animate to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be animated.</param>
 /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
 public override void ApplyAnimation(string animateId,
                                     MetaPanelBase metaPanel,
                                     MetaElementStateDict stateDict,
                                     ICollection elements,
                                     double elapsedMilliseconds)
 {
     // Only apply if we match the incoming animate identifier
     if (string.IsNullOrEmpty(Id) || Id.Equals(animateId))
     {
         foreach (UIElement element in elements)
         {
             // Immediately move to the target rectangle
             MetaElementState elementState = stateDict[element];
             elementState.CurrentRect = elementState.TargetRect;
         }
     }
 }
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Cache the dependancy properties for faster perf
                Orientation orientation = Orientation;

                // Give children as much space as they want in the opposite direction to the stacking
                if (orientation == Orientation.Horizontal)
                    availableSize.Width = double.PositiveInfinity;
                else
                    availableSize.Height = double.PositiveInfinity;

                // Measure each element in turn
                Size measureSize = new Size();
                foreach (UIElement element in elements)
                {
                    element.Measure(availableSize);

                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        // Accumulate in the orientation direction, but track maximum value in the opposite
                        if (orientation == Orientation.Horizontal)
                        {
                            measureSize.Width += element.DesiredSize.Width;
                            measureSize.Height = Math.Max(measureSize.Height, element.DesiredSize.Height);
                        }
                        else
                        {
                            measureSize.Width = Math.Max(measureSize.Width, element.DesiredSize.Width);
                            measureSize.Height += element.DesiredSize.Height;
                        }
                    }
                }

                return measureSize;
            }
            else
                return Size.Empty;
        }
Example #26
0
 /// <summary>
 /// Perform animation effects on the set of children.
 /// </summary>
 /// <param name="animateId">Identifier of the animate to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be animated.</param>
 /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
 public override void ApplyAnimation(string animateId,
                                     MetaPanelBase metaPanel,
                                     MetaElementStateDict stateDict,
                                     ICollection elements,
                                     double elapsedMilliseconds)
 {
     // Only apply if we match the incoming animate identifier
     if (string.IsNullOrEmpty(Id) || Id.Equals(animateId))
     {
         foreach (UIElement element in elements)
         {
             // Immediately move to the target rectangle
             MetaElementState elementState = stateDict[element];
             elementState.CurrentRect = elementState.TargetRect;
         }
     }
 }
Example #27
0
        /// <summary>
        /// Calculate target state for each element based on layout algorithm.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be arranged.</param>
        /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
        public override void TargetChildren(string layoutId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            Size finalSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Cache the dependancy properties for faster perf
                Orientation orientation = Orientation;

                // Calculate the target rectangle for each element
                double offset = 0;
                foreach (UIElement element in elements)
                {
                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        Rect newTargetRect;

                        // Updating the elements target rectangle depends on orientation
                        if (orientation == Orientation.Horizontal)
                        {
                            newTargetRect = new Rect(offset, 0, element.DesiredSize.Width, Math.Max(finalSize.Height, element.DesiredSize.Height));
                            offset       += element.DesiredSize.Width;
                        }
                        else
                        {
                            newTargetRect = new Rect(0, offset, Math.Max(finalSize.Width, element.DesiredSize.Width), element.DesiredSize.Height);
                            offset       += element.DesiredSize.Height;
                        }

                        // Store the new target rectangle
                        if (!stateDict[element].TargetRect.Equals(newTargetRect))
                        {
                            stateDict[element].TargetChanged = true;
                            stateDict[element].TargetRect    = newTargetRect;
                        }
                    }
                }
            }
        }
Example #28
0
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Measure each element in turn
                foreach (UIElement element in elements)
                {
                    stateDict[element].Element.Measure(Utility.SizeInfinity);
                }
            }

            // Return an empty size
            return(Size.Empty);
        }
Example #29
0
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public Size MeasureChildren(string layoutId,
                                    MetaPanelBase metaPanel,
                                    MetaElementStateDict stateDict,
                                    ICollection elements,
                                    Size availableSize)
        {
            Size retSize = new Size();

            foreach (Layout layout in this)
            {
                Size layoutSize = layout.MeasureChildren(layoutId, metaPanel, stateDict, elements, availableSize);

                // Find the largest requested size
                retSize.Width  = Math.Max(retSize.Width, layoutSize.Width);
                retSize.Height = Math.Max(retSize.Height, layoutSize.Height);
            }

            return(retSize);
        }
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Calculate number of rows and columns needed to show all children
                UpdateRowsColumns(stateDict, elements);

                // Each element should be equal sized according to grid cell size
                Size elementSize = new Size(availableSize.Width / (double)_columns,
                                            availableSize.Height / (double)_rows);

                // Measure each element in turn
                double widest  = 0;
                double tallest = 0;
                foreach (UIElement element in elements)
                {
                    element.Measure(elementSize);
                    if (element.Visibility != Visibility.Collapsed)
                    {
                        // We ignore items being removed
                        if (stateDict[element].Status != MetaElementStatus.Removing)
                        {
                            // Track widest/tallest for calculating cell size later
                            widest  = Math.Max(widest, element.DesiredSize.Width);
                            tallest = Math.Max(tallest, element.DesiredSize.Height);
                        }
                    }
                }

                // We would like a size that ensures each cell is big enough for the biggest child
                return(new Size(_columns * widest, _rows * tallest));
            }
            else
            {
                return(Size.Empty);
            }
        }
Example #31
0
        private void ResyncStateDictionary()
        {
            MetaElementStateDict newStateDict = new MetaElementStateDict();

            // Transfer existing state to new dictionary and create new state for new elements
            foreach (UIElement element in Children)
            {
                if (_stateDict.ContainsKey(element))
                {
                    newStateDict.Add(element, _stateDict[element]);
                }
                else
                {
                    newStateDict.Add(element, new MetaElementState(element));
                }
            }

            // Any removed elements will not have state in new dictionary
            _stateDict = newStateDict;
        }
Example #32
0
        /// <summary>
        /// Position child elements according to already calculated target state.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be arranged.</param>
        /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
        /// <returns>Size used by the layout panel.</returns>
        public virtual Size ArrangeChildren(string layoutId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            Size finalSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Position each element
                foreach (UIElement element in elements)
                {
                    MetaElementState elementState = stateDict[element];
                    elementState.Element.Arrange(elementState.CurrentRect);
                }
            }

            // Layout panel takes all the provided size
            return finalSize;
        }
Example #33
0
        /// <summary>
        /// Position child elements according to already calculated target state.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be arranged.</param>
        /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
        /// <returns>Size used by the layout panel.</returns>
        public virtual Size ArrangeChildren(string layoutId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            Size finalSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Position each element
                foreach (UIElement element in elements)
                {
                    MetaElementState elementState = stateDict[element];
                    elementState.Element.Arrange(elementState.CurrentRect);
                }
            }

            // Layout panel takes all the provided size
            return(finalSize);
        }
Example #34
0
        private void TargetLine(MetaElementStateDict stateDict,
                                List <UIElement> targets,
                                double positionOffset,
                                double lineMax,
                                bool itemWidthDefined,
                                bool itemHeightDefined,
                                double itemWidth,
                                double itemHeight,
                                Size finalSize,
                                Orientation orientation)
        {
            double lineOffset = 0;

            foreach (UIElement element in targets)
            {
                // Decide on the actual size we will allocate to the element
                Size childSize = new Size(itemWidthDefined ? itemWidth : element.DesiredSize.Width,
                                          itemHeightDefined ? itemHeight : element.DesiredSize.Height);

                Rect newTargetRect;

                // Updating the elements target rectangle depends on orientation
                if (orientation == Orientation.Horizontal)
                {
                    newTargetRect = new Rect(lineOffset, positionOffset, childSize.Width, lineMax);
                    lineOffset   += childSize.Width;
                }
                else
                {
                    newTargetRect = new Rect(positionOffset, lineOffset, lineMax, childSize.Height);
                    lineOffset   += childSize.Height;
                }

                // Store the new target rectangle
                if (!stateDict[element].TargetRect.Equals(newTargetRect))
                {
                    stateDict[element].TargetChanged = true;
                    stateDict[element].TargetRect    = newTargetRect;
                }
            }
        }
Example #35
0
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            Size retSize = new Size();

            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                foreach (UIElement element in elements)
                {
                    stateDict[element].Element.Measure(availableSize);
                    retSize.Width  = Math.Max(retSize.Width, stateDict[element].Element.DesiredSize.Width);
                    retSize.Height = Math.Max(retSize.Height, stateDict[element].Element.DesiredSize.Height);
                }
            }

            return(retSize);
        }
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            Size retSize = new Size();

            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                foreach (UIElement element in elements)
                {
                    stateDict[element].Element.Measure(availableSize);
                    retSize.Width = Math.Max(retSize.Width, stateDict[element].Element.DesiredSize.Width);
                    retSize.Height = Math.Max(retSize.Height, stateDict[element].Element.DesiredSize.Height);
                }
            }

            return retSize;
        }
Example #37
0
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            // Measure each element in turn
            _count = 0;
            Size maxSize = new Size();

            foreach (UIElement element in elements)
            {
                if (element != null)
                {
                    element.Measure(Utility.SizeInfinity);

                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        // We ignore items that are collapsed
                        if (element.Visibility != Visibility.Collapsed)
                        {
                            // Find the widest and tallest element
                            maxSize.Width  = Math.Max(maxSize.Width, element.DesiredSize.Width);
                            maxSize.Height = Math.Max(maxSize.Height, element.DesiredSize.Height);

                            // Count number of valid elements
                            _count++;
                        }
                    }
                }
            }

            // Max length is the diagonal length of biggest element
            _maxLength = Math.Sqrt((maxSize.Width * maxSize.Width) + (maxSize.Height * maxSize.Height));

            // Always use the provided size
            return(availableSize);
        }
Example #38
0
        private Size MeasureTreeNodes(ITreeNode node,
                                      MetaElementStateDict stateDict,
                                      bool downwards)
        {
            Size totalSize = Utility.SizeZero;

            UIElement element = node as UIElement;

            if ((element != null) && (stateDict.ContainsKey(element)))
            {
                // Use element size as the starting total size
                element.Measure(Utility.SizeInfinity);

                // Do not measure children of items being removed
                if (stateDict[element].Status != MetaElementStatus.Removing)
                {
                    // Starting size covers only the node
                    totalSize = element.DesiredSize;

                    // Process each sub tree
                    Size childTotalSize = Utility.SizeZero;
                    foreach (ITreeNode child in node.ChildNodes())
                    {
                        Size childSize = MeasureTreeNodes(child, stateDict, downwards);

                        // Stack all the sub trees vertically in sizing
                        childTotalSize.Width   = Math.Max(childTotalSize.Width, childSize.Width);
                        childTotalSize.Height += childSize.Height;
                    }

                    // Place the set of sub trees to the right of this node
                    totalSize.Width += childTotalSize.Width;
                    totalSize.Height = Math.Max(totalSize.Height, childTotalSize.Height);
                }
            }

            return(totalSize);
        }
Example #39
0
        private Size CalculateDesiredSize(MetaElementStateDict stateDict,
                                          ICollection elements,
                                          Size availableSize)
        {
            double width  = _proxyColumns[_proxyColumns.Length - 1].MinTotal + _proxyColumns[_proxyColumns.Length - 1].MinSize;
            double height = _proxyRows[_proxyRows.Length - 1].MinTotal + _proxyRows[_proxyRows.Length - 1].MinSize;

            // If any of the columns is marked as Star
            if (HasColumnStars)
            {
                // If we have infinite space then return the measured width needed for all columns, otherwise we just take all the space
                if (availableSize.Width == double.PositiveInfinity)
                {
                    width = _proxyColumns[_proxyColumns.Length - 1].DesiredTotal + _proxyColumns[_proxyColumns.Length - 1].DesiredSize;
                }
                else
                {
                    width = availableSize.Width;
                }
            }

            // If any of the rows is marked as Star
            if (HasRowStars)
            {
                // If we have infinite space then return the measured height needed for all rows, otherwise we just take all the space
                if (availableSize.Height == double.PositiveInfinity)
                {
                    height = _proxyRows[_proxyRows.Length - 1].DesiredTotal + _proxyRows[_proxyRows.Length - 1].DesiredSize;
                }
                else
                {
                    height = availableSize.Height;
                }
            }

            return(new Size(width, height));
        }
        private Size MeasureTreeNodes(ITreeNode node, 
                                      MetaElementStateDict stateDict,
                                      bool downwards)
        {
            Size totalSize = Utility.SizeZero;

            UIElement element = node as UIElement;
            if ((element != null) && (stateDict.ContainsKey(element)))
            {
                // Use element size as the starting total size
                element.Measure(Utility.SizeInfinity);

                // Do not measure children of items being removed
                if (stateDict[element].Status != MetaElementStatus.Removing)
                {
                    // Starting size covers only the node
                    totalSize = element.DesiredSize;

                    // Process each sub tree
                    Size childTotalSize = Utility.SizeZero;
                    foreach (ITreeNode child in node.ChildNodes())
                    {
                        Size childSize = MeasureTreeNodes(child, stateDict, downwards);

                        // Stack all the sub trees vertically in sizing
                        childTotalSize.Width = Math.Max(childTotalSize.Width, childSize.Width);
                        childTotalSize.Height += childSize.Height;
                    }

                    // Place the set of sub trees to the right of this node
                    totalSize.Width += childTotalSize.Width;
                    totalSize.Height = Math.Max(totalSize.Height, childTotalSize.Height);
                }
            }

            return totalSize;
        }
 /// <summary>
 /// Calculate target state for each element based on layout algorithm.
 /// </summary>
 /// <param name="layoutId">Identifier of the layout to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be arranged.</param>
 /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
 public override void TargetChildren(string layoutId,
                                     MetaPanelBase metaPanel,
                                     MetaElementStateDict stateDict,
                                     ICollection elements,
                                     Size finalSize)
 {
     // Only apply if we match the incoming layout identifier
     if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
     {
         // TODO target elements that are not in tree drawing
         TargetTreeNodes(Utility.PointZero, StartNode, stateDict, false);
     }
 }
        private Size CalculateDesiredSize(MetaElementStateDict stateDict,
                                          ICollection elements,
                                          Size availableSize)
        {
            double width = _proxyColumns[_proxyColumns.Length - 1].MinTotal + _proxyColumns[_proxyColumns.Length - 1].MinSize;
            double height = _proxyRows[_proxyRows.Length - 1].MinTotal + _proxyRows[_proxyRows.Length - 1].MinSize;

            // If any of the columns is marked as Star
            if (HasColumnStars)
            {
                // If we have infinite space then return the measured width needed for all columns, otherwise we just take all the space
                if (availableSize.Width == double.PositiveInfinity)
                    width = _proxyColumns[_proxyColumns.Length - 1].DesiredTotal + _proxyColumns[_proxyColumns.Length - 1].DesiredSize;
                else
                    width = availableSize.Width;
            }

            // If any of the rows is marked as Star
            if (HasRowStars)
            {
                // If we have infinite space then return the measured height needed for all rows, otherwise we just take all the space
                if (availableSize.Height == double.PositiveInfinity)
                    height = _proxyRows[_proxyRows.Length - 1].DesiredTotal + _proxyRows[_proxyRows.Length - 1].DesiredSize;
                else
                    height = availableSize.Height;
            }

            return new Size(width, height);
        }
 /// <summary>
 /// Perform animation effects on the set of children.
 /// </summary>
 /// <param name="animateId">Identifier of the animate to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be animated.</param>
 /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
 public override void ApplyAnimation(string animateId,
                                     MetaPanelBase metaPanel,
                                     MetaElementStateDict stateDict,
                                     ICollection elements,
                                     double elapsedMilliseconds)
 {
     ApplyAnimation(animateId, metaPanel, stateDict, elements, elapsedMilliseconds, Start, End);
 }
        /// <summary>
        /// Perform animation effects on the set of children.
        /// </summary>
        /// <param name="animateId">Identifier of the animate to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be animated.</param>
        /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
        public override void ApplyAnimation(string animateId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            double elapsedMilliseconds)
        {
            // Only apply if we match the incoming animate identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(animateId))
            {
                // Update the easing equation with latest value
                EasingCalculation.Easing = Easing;

                // Cache dependancy properties for faster perf
                double duration = Math.Max((double)1, Duration);

                foreach (UIElement element in elements)
                {
                    // Only apply animation to element of required target state
                    MetaElementState elementState = stateDict[element];
                    if (elementState.Status == Target)
                    {
                        Rect targetRect = elementState.TargetRect;
                        Rect currentRect = (elementState.CurrentRect.IsEmpty ? targetRect : elementState.CurrentRect);

                        // If start of animation....
                        if (elementState.TargetChanged)
                        {
                            // Cache starting information
                            elementState.StartRect = currentRect;
                            elementState.ElapsedBoundsTime = 0;
                        }
                        else
                        {
                            // Only perform animation if some time has actually ellapsed and not already at target
                            if ((elapsedMilliseconds > 0) && !currentRect.Equals(targetRect))
                            {
                                // Add new elapsed time to the animation running time
                                elementState.ElapsedBoundsTime += elapsedMilliseconds;

                                // Does elapsed time indicate animation should have completed?
                                if (elementState.ElapsedBoundsTime >= duration)
                                    currentRect = targetRect;
                                else
                                {
                                    Rect startRect = elementState.StartRect;
                                    double elapsedTime = elementState.ElapsedBoundsTime;

                                    // Using animation easing to discover new target rectangle corners
                                    double left = EasingCalculation.Calculate(elapsedTime, startRect.X, targetRect.X - startRect.X, duration);
                                    double top = EasingCalculation.Calculate(elapsedTime, startRect.Y, targetRect.Y - startRect.Y, duration);
                                    double bottom = EasingCalculation.Calculate(elapsedTime, startRect.Bottom, targetRect.Bottom - startRect.Bottom, duration);
                                    double right = EasingCalculation.Calculate(elapsedTime, startRect.Right, targetRect.Right - startRect.Right, duration);

                                    // Normalize edges left/right edges
                                    if (left > right)
                                    {
                                        elapsedTime = left;
                                        left = right;
                                        right = elapsedTime;
                                    }

                                    // Normalize edges top/bottom edges
                                    if (top > bottom)
                                    {
                                        elapsedTime = top;
                                        top = bottom;
                                        bottom = elapsedTime;
                                    }

                                    currentRect = new Rect(left, top, right - left, bottom - top);
                                }
                            }
                        }

                        // Put back the updated rectangle and decide if more animation is needed
                        elementState.CurrentRect = currentRect;
                        elementState.AnimateComplete &= (currentRect.Equals(targetRect));
                    }
                }
            }
        }
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Measure each element in turn
                _validCount = 0;
                Size usedSize = new Size();
                Size maxSize = new Size();
                foreach (UIElement element in elements)
                {
                    // Allow element to have all the remainder size available
                    Size elementSize = new Size(Math.Max(0.0, (double)(availableSize.Width - usedSize.Width)),
                                                Math.Max(0.0, (double)(availableSize.Height - usedSize.Height)));

                    element.Measure(elementSize);

                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        // Discover the used size and the maximum required size for opposite direction
                        Size desiredSize = element.DesiredSize;
                        switch (GetDock(element))
                        {
                            case Dock.Left:
                            case Dock.Right:
                                maxSize.Height = Math.Max(maxSize.Height, usedSize.Height + desiredSize.Height);
                                usedSize.Width += desiredSize.Width;
                                break;
                            case Dock.Top:
                            case Dock.Bottom:
                                maxSize.Width = Math.Max(maxSize.Width, usedSize.Width + desiredSize.Width);
                                usedSize.Height += desiredSize.Height;
                                break;
                        }

                        _validCount++;
                    }
                }

                return new Size(Math.Max(maxSize.Width, usedSize.Width),
                                Math.Max(maxSize.Height, usedSize.Height));
            }
            else
                return Size.Empty;
        }
        /// <summary>
        /// Calculate target state for each element based on layout algorithm.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be arranged.</param>
        /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
        public override void TargetChildren(string layoutId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            Size finalSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // If there are no column/row definitions then arrange to entire final size
                if ((_columns.Count == 0) && (_rows.Count == 0))
                {
                    Rect newTargetRect = new Rect(Utility.PointZero, finalSize);
                    foreach (UIElement element in elements)
                    {
                        // We ignore items being removed
                        if (stateDict[element].Status != MetaElementStatus.Removing)
                        {
                            // Store the new target rectangle
                            if (!stateDict[element].TargetRect.Equals(newTargetRect))
                            {
                                stateDict[element].TargetChanged = true;
                                stateDict[element].TargetRect = newTargetRect;
                            }
                        }
                    }
                }
                else
                {
                    // Calculate final width/height of col/row definitions
                    PreTarget(finalSize);

                    // Update new target rectangle for each non-removing element
                    foreach (UIElement element in elements)
                    {
                        // We ignore items being removed
                        if (stateDict[element].Status != MetaElementStatus.Removing)
                        {
                            // Find the arrange size for the element
                            Rect newTargetRect = TargetArrangeSize(element);

                            // Store the new target rectangle
                            if (!stateDict[element].TargetRect.Equals(newTargetRect))
                            {
                                stateDict[element].TargetChanged = true;
                                stateDict[element].TargetRect = newTargetRect;
                            }
                        }
                    }
                }
            }

            // Update rows and columns with actual widths/heights
            for (int i = 0; i < ColumnDefinitions.Count; i++)
                ColumnDefinitions[i].ActualWidth = _proxyColumns[i].MinSize;

            for (int i = 0; i < RowDefinitions.Count; i++)
                RowDefinitions[i].ActualHeight = _proxyRows[i].MinSize;
        }
        /// <summary>
        /// Calculate target state for each element based on layout algorithm.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be arranged.</param>
        /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
        public override void TargetChildren(string layoutId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            Size finalSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Calculate the target rectangle for each element
                foreach (UIElement element in elements)
                {
                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        // Default to being the desired size but at position zero,zero
                        Rect newTargetRect = new Rect(0, 0, element.DesiredSize.Width, element.DesiredSize.Height);

                        // Use the Left or Right value provided as attached properties of the element
                        double left = CanvasLayout.GetLeft(element);
                        if (!double.IsNaN(left))
                            newTargetRect.X = left;
                        else
                        {
                            double right = CanvasLayout.GetRight(element);
                            if (!double.IsNaN(right))
                                newTargetRect.X = (finalSize.Width - element.DesiredSize.Width) - right;
                        }

                        // Use the Top or Bottom value provided as attached properties of the element
                        double top = CanvasLayout.GetTop(element);
                        if (!double.IsNaN(top))
                            newTargetRect.Y = top;
                        else
                        {
                            double bottom = CanvasLayout.GetBottom(element);
                            if (!double.IsNaN(bottom))
                                newTargetRect.Y = (finalSize.Height - element.DesiredSize.Height) - bottom;
                        }

                        // Store the new target rectangle
                        if (!stateDict[element].TargetRect.Equals(newTargetRect))
                        {
                            stateDict[element].TargetChanged = true;
                            stateDict[element].TargetRect = newTargetRect;
                        }
                    }
                }
            }
        }
        private void TargetLine(MetaElementStateDict stateDict,
                                List<UIElement> targets,
                                double positionOffset,
                                double lineMax,
                                bool itemWidthDefined,
                                bool itemHeightDefined,
                                double itemWidth,
                                double itemHeight,
                                Size finalSize,
                                Orientation orientation)
        {
            double lineOffset = 0;
            foreach (UIElement element in targets)
            {
                // Decide on the actual size we will allocate to the element
                Size childSize = new Size(itemWidthDefined ? itemWidth : element.DesiredSize.Width,
                                          itemHeightDefined ? itemHeight : element.DesiredSize.Height);

                Rect newTargetRect;

                // Updating the elements target rectangle depends on orientation
                if (orientation == Orientation.Horizontal)
                {
                    newTargetRect = new Rect(lineOffset, positionOffset, childSize.Width, lineMax);
                    lineOffset += childSize.Width;
                }
                else
                {
                    newTargetRect = new Rect(positionOffset, lineOffset, lineMax, childSize.Height);
                    lineOffset += childSize.Height;
                }

                // Store the new target rectangle
                if (!stateDict[element].TargetRect.Equals(newTargetRect))
                {
                    stateDict[element].TargetChanged = true;
                    stateDict[element].TargetRect = newTargetRect;
                }
            }
        }
        private Size TargetTreeNodes(Point location, 
                                     ITreeNode node, 
                                     MetaElementStateDict stateDict,
                                     bool downwards)
        {
            Size totalSize = Utility.SizeZero;

            UIElement element = node as UIElement;
            if ((element != null) && (stateDict.ContainsKey(element)))
            {
                // Do not measure children of items being removed
                if (stateDict[element].Status != MetaElementStatus.Removing)
                {
                    // Starting size covers only the node
                    totalSize = element.DesiredSize;

                    // Process each sub tree
                    Point childLocation = new Point(location.X + element.DesiredSize.Width, location.Y);
                    Size childTotalSize = Utility.SizeZero;
                    foreach (ITreeNode child in node.ChildNodes())
                    {
                        Size childSize = TargetTreeNodes(childLocation, child, stateDict, downwards);

                        // Stack all the sub trees vertically in sizing
                        childTotalSize.Width = Math.Max(childTotalSize.Width, childSize.Width);
                        childTotalSize.Height += childSize.Height;
                        childLocation.Y += childSize.Height;
                    }

                    // Place the set of sub trees to the right of this node
                    totalSize.Width += childTotalSize.Width;
                    totalSize.Height = Math.Max(totalSize.Height, childTotalSize.Height);
                }

                // Position the node vertically centered
                Rect newTargetRect = new Rect(location.X,
                                              location.Y + (totalSize.Height - element.DesiredSize.Height) / 2,
                                              element.DesiredSize.Width,
                                              element.DesiredSize.Height);

                // Store the new target rectangle
                if (!stateDict[element].TargetRect.Equals(newTargetRect))
                {
                    stateDict[element].TargetChanged = true;
                    stateDict[element].TargetRect = newTargetRect;
                }
            }

            return totalSize;
        }
Example #50
0
 /// <summary>
 /// Perform animation effects on the set of children.
 /// </summary>
 /// <param name="animateId">Identifier of the animate to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be animated.</param>
 /// <param name="elapsedMilliseconds">Elapsed milliseconds since last animation cycle.</param>
 public abstract void ApplyAnimation(string animateId,
                                     MetaPanelBase metaPanel,
                                     MetaElementStateDict stateDict,
                                     ICollection elements,
                                     double elapsedMilliseconds);
Example #51
0
 /// <summary>
 /// Calculate target state for each element based on layout algorithm.
 /// </summary>
 /// <param name="layoutId">Identifier of the layout to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be arranged.</param>
 /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
 public abstract void TargetChildren(string layoutId,
                                     MetaPanelBase metaPanel,
                                     MetaElementStateDict stateDict,
                                     ICollection elements,
                                     Size finalSize);
Example #52
0
 /// <summary>
 /// Measure the layout size required to arrange all elements.
 /// </summary>
 /// <param name="layoutId">Identifier of the layout to be used.</param>
 /// <param name="metaPanel">Reference to owning panel instance.</param>
 /// <param name="stateDict">Dictionary of per-element state.</param>
 /// <param name="elements">Collection of elements to be measured.</param>
 /// <param name="availableSize">Available size that can be given to elements.</param>
 /// <returns>Size the layout determines it needs based on child element sizes.</returns>
 public abstract Size MeasureChildren(string layoutId,
                                      MetaPanelBase metaPanel,
                                      MetaElementStateDict stateDict,
                                      ICollection elements,
                                      Size availableSize);
        private void ResyncStateDictionary()
        {
            MetaElementStateDict newStateDict = new MetaElementStateDict();

            // Transfer existing state to new dictionary and create new state for new elements
            foreach (UIElement element in Children)
            {
                if (_stateDict.ContainsKey(element))
                    newStateDict.Add(element, _stateDict[element]);
                else
                    newStateDict.Add(element, new MetaElementState(element));
            }

            // Any removed elements will not have state in new dictionary
            _stateDict = newStateDict;
        }
        private void UpdateDefinitions(MetaElementStateDict stateDict,
                                       ICollection elements,
                                       bool spanning)
        {
            foreach (UIElement element in elements)
            {
                // Find the row/col definitions for this element
                int col = Math.Max(0, Math.Min(_columns.Count - 1, GetColumn(element)));
                int row = Math.Max(0, Math.Min(_rows.Count - 1, GetRow(element)));

                // Find the row/col spanning definitions for this element (convert to zero based spanning)
                int colSpan = Math.Max(Math.Min(_columns.Count - col, GetColumnSpan(element)), 1) - 1;
                int rowSpan = Math.Max(Math.Min(_rows.Count - row, GetRowSpan(element)), 1) - 1;

                // If cell covers a single column then update the minimum size of column with desired width
                if (!spanning && (colSpan == 0))
                    _proxyColumns[col].UpdateFromMeasure(stateDict[element].Element.DesiredSize.Width);

                if (spanning && (colSpan > 0))
                {
                    // Quantity of desired width to be allocated
                    double desiredWidth = stateDict[element].Element.DesiredSize.Width;

                    // Scan all spanning columns and remove the already allocated space from desired width
                    int index = col;
                    int autoColumns = 0;
                    do
                    {
                        desiredWidth -= _proxyColumns[index].MinSize;
                        if (_proxyColumns[index].UserGridUnitType == GridUnitType.Auto)
                            autoColumns++;

                    } while (index++ < (col + colSpan));

                    // If there is still some width left to allocate and something to allocate into
                    if ((desiredWidth > 0) && (autoColumns > 0))
                    {
                        index = col;
                        do
                        {
                            if (_proxyColumns[index].UserGridUnitType == GridUnitType.Auto)
                            {
                                double extraSpace = desiredWidth / autoColumns--;
                                desiredWidth -= extraSpace;
                                _proxyColumns[index].UpdateFromMeasure(_proxyColumns[index].MinSize + extraSpace);
                            }

                        } while (index++ < (col + colSpan));
                    }
                }

                // If cell covers a single row then update the minimum size of column with desired height
                if (!spanning & (rowSpan == 0))
                    _proxyRows[row].UpdateFromMeasure(stateDict[element].Element.DesiredSize.Height);

                if (spanning && (rowSpan > 0))    
                {
                    // Quantity of desired height to be allocated
                    double desiredHeight = stateDict[element].Element.DesiredSize.Height;

                    // Scan all spanning columns and remove the already allocated space from desired height
                    int index = col;
                    int autoRows = 0;
                    do
                    {
                        desiredHeight -= _proxyColumns[index].MinSize;
                        if (_proxyColumns[index].UserGridUnitType == GridUnitType.Auto)
                            autoRows++;

                    } while (index++ < (col + colSpan));

                    // If there is still some height left to allocate and something to allocate into
                    if ((desiredHeight > 0) && (autoRows > 0))
                    {
                        index = col;
                        do
                        {
                            if (_proxyColumns[index].UserGridUnitType == GridUnitType.Auto)
                            {
                                double extraSpace = desiredHeight / autoRows--;
                                desiredHeight -= extraSpace;
                                _proxyColumns[index].UpdateFromMeasure(_proxyColumns[index].MinSize + extraSpace);
                            }

                        } while (index++ < (col + colSpan));
                    }
                }
            }
        }
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // Measure each element in turn
                foreach (UIElement element in elements)
                    stateDict[element].Element.Measure(Utility.SizeInfinity);
            }

            // Return an empty size
            return Size.Empty;
        }
        /// <summary>
        /// Calculate target state for each element based on layout algorithm.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be arranged.</param>
        /// <param name="finalSize">Size that layout should use to arrange child elements.</param>
        public override void TargetChildren(string layoutId,
                                            MetaPanelBase metaPanel,
                                            MetaElementStateDict stateDict,
                                            ICollection elements,
                                            Size finalSize)
        {
            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                double x = 0.0;
                double y = 0.0;
                double right = 0.0;
                double bottom = 0.0;

                // If using LastChildFill then the last element takes up all the remainder space
                int lastDockElement = (LastChildFill ? _validCount - 1 : _validCount);

                // Calculate the target rectangle for each element
                int i = 0;
                foreach (UIElement element in elements)
                {
                    // We ignore items being removed
                    if (stateDict[element].Status != MetaElementStatus.Removing)
                    {
                        // Calculate the maximum possible rect for the element
                        Rect newTargetRect = new Rect(x, y,
                                                      Math.Max(0.0, (double)(finalSize.Width - (x + right))),
                                                      Math.Max(0.0, (double)(finalSize.Height - (y + bottom))));

                        if (i < lastDockElement)
                        {
                            // Constrain target rect by the dock edge
                            Size desiredSize = element.DesiredSize;
                            switch (GetDock(element))
                            {
                                case Dock.Left:
                                    x += desiredSize.Width;
                                    newTargetRect.Width = desiredSize.Width;
                                    break;
                                case Dock.Top:
                                    y += desiredSize.Height;
                                    newTargetRect.Height = desiredSize.Height;
                                    break;
                                case Dock.Right:
                                    right += desiredSize.Width;
                                    newTargetRect.X = Math.Max(0.0, (double)(finalSize.Width - right));
                                    newTargetRect.Width = desiredSize.Width;
                                    break;
                                case Dock.Bottom:
                                    bottom += desiredSize.Height;
                                    newTargetRect.Y = Math.Max(0.0, (double)(finalSize.Height - bottom));
                                    newTargetRect.Height = desiredSize.Height;
                                    break;
                            }
                        }

                        // Store the new target rectangle
                        if (!stateDict[element].TargetRect.Equals(newTargetRect))
                        {
                            stateDict[element].TargetChanged = true;
                            stateDict[element].TargetRect = newTargetRect;
                        }

                        i++;
                    }
                }
            }
        }
        private bool AnimateChildren(MetaElementStateDict stateDict, ICollection elements)
        {
            // Find number of milliseconds elapsed since last animation calculation, note that if not
            // currently animating then the elapsed time since the last animation cycle must be 0.
            double elapsedMilliseconds = (!IsAnimating || (_lastTicks == -1) ? 0 : (_nextTicks - _lastTicks) / (double)(10000));

            if (IsAnimationAllowed)
            {
                // Ask the chain of animation classes to apply any required movement changes
                Animates.ApplyAnimation(AnimateId, this, stateDict, elements, elapsedMilliseconds);
            }

            // Post-process on animation state
            bool moreAnimation = false;
            foreach (MetaElementState elementState in stateDict.Values)
            {
                // At end of animation cycle the new/remove values must have been calculated
                elementState.NewCalculating = false;
                if (elementState.Status == MetaElementStatus.Removing)
                    elementState.RemoveCalculated = true;

                // Has the element finished being removed?
                if (elementState.AnimateComplete && (elementState.Status == MetaElementStatus.Removing))
                    _removeList.Add(elementState);
                else
                {
                    // If the element has not finished being animated
                    if (!elementState.AnimateComplete)
                    {
                        // Always reset to being completed, ready for next cycle
                        elementState.AnimateComplete = true;
                        moreAnimation = true;
                    }
                    else
                    {
                        // Has element finished being 'new'?
                        if (elementState.Status == MetaElementStatus.New)
                            elementState.Status = MetaElementStatus.Existing;

                        // Animation is completed so ensure the current rect is same as the target
                        // rect. This ensures that if there are no animation classes actually doing
                        // size/position animation then the child elements actually do get positioned.
                        elementState.CurrentRect = elementState.TargetRect;
                    }
                }

                // Reset the target changed flag
                elementState.TargetChanged = false;

                // Never allow the current rect to be empty
                if (elementState.CurrentRect.IsEmpty)
                    elementState.CurrentRect = elementState.TargetRect;
            }

            // Process the removal list
            foreach (MetaElementState elementState in _removeList)
            {
                RemoveChildElement(elementState.Element);
                stateDict.Remove(elementState.Element);
                moreAnimation = true;
            }

            // Must clear list to prevent dangling references to the removed UIElement instances
            _removeList.Clear();

            return moreAnimation;
        }
        /// <summary>
        /// Measure the layout size required to arrange all elements.
        /// </summary>
        /// <param name="layoutId">Identifier of the layout to be used.</param>
        /// <param name="metaPanel">Reference to owning panel instance.</param>
        /// <param name="stateDict">Dictionary of per-element state.</param>
        /// <param name="elements">Collection of elements to be measured.</param>
        /// <param name="availableSize">Available size that can be given to elements.</param>
        /// <returns>Size the layout determines it needs based on child element sizes.</returns>
        public override Size MeasureChildren(string layoutId,
                                             MetaPanelBase metaPanel,
                                             MetaElementStateDict stateDict,
                                             ICollection elements,
                                             Size availableSize)
        {
            Size retSize = new Size();

            // Only apply if we match the incoming layout identifier
            if (string.IsNullOrEmpty(Id) || Id.Equals(layoutId))
            {
                // If there are no column/row definitions then size to available area
                if ((_columns.Count == 0) && (_rows.Count == 0))
                {
                    foreach (UIElement element in elements)
                    {
                        stateDict[element].Element.Measure(availableSize);
                        retSize.Width = Math.Max(retSize.Width, stateDict[element].Element.DesiredSize.Width);
                        retSize.Height = Math.Max(retSize.Height, stateDict[element].Element.DesiredSize.Height);
                    }
                }
                else
                {
                    BuildProxyColumns();
                    BuildProxyRows();
                    PreMeasure(availableSize);
                    MeasureElements(stateDict, elements);
                    UpdateDefinitions(stateDict, elements, false);
                    UpdateDefinitions(stateDict, elements, true);
                    CalculateOffsetsAndTotals();
                    retSize = CalculateDesiredSize(stateDict, elements, availableSize);
                }
            }

            return retSize;
        }
        /// <summary>
        /// Initialize a new instance of the MetaPanelBase class.
        /// </summary>
        public MetaPanelBase()
        {
            // List used to collect entries that are to be removed from panel
            _removeList = new MetaElementStateList();

            // Use dictionary to associate each element with its animation state
            _stateDict = new MetaElementStateDict();

            // Create and monitor changes in the layout collection
            _layoutCollection = new LayoutCollection(this);
            _layoutCollection.NeedMeasure += new EventHandler(OnNeedMeasure);
            _layoutCollection.CollectionChanged += new EventHandler(OnNeedMeasure);
            MonitorExtendElement(_layoutCollection);

            // Create and monitor changes in the animate collection
            _animateCollection = new AnimateDefinitions(this);
            _animateCollection.NeedMeasure += new EventHandler(OnNeedMeasure);
            MonitorExtendElement(_animateCollection);

            // Default layout/animate to be applied as the default in case collections are empty or not applied
            _defaultLayout = new StretchLayout();
            _defaultAnimate = new NullAnimate();

            // Let the Silverlight/WPF specific construction take place
            PlatformConstructor();
        }
        private void MeasureElements(MetaElementStateDict stateDict,
                                     ICollection elements)
        {
            foreach (UIElement element in elements)
            {
                // Find the row/col definitions for this element
                int col = Math.Max(0, Math.Min(_columns.Count - 1, GetColumn(element)));
                int row = Math.Max(0, Math.Min(_rows.Count - 1, GetRow(element)));

                // Find the row/col spanning definitions for this element (convert to zero based spanning)
                int colSpan = Math.Max(Math.Min(_columns.Count - col, GetColumnSpan(element)), 1) - 1;
                int rowSpan = Math.Max(Math.Min(_rows.Count - row, GetRowSpan(element)), 1) - 1;

                // Find column width to use for measuring
                int index = col;
                double measureWidth = 0;
                do
                {
                    measureWidth += _proxyColumns[index].MeasureSize;

                } while ((measureWidth < double.PositiveInfinity) && (index++ < (col + colSpan)));

                // Find row height to use for measuring
                index = row;
                double measureHeight = 0;
                do
                {
                    measureHeight += _proxyRows[index].MeasureSize;

                } while ((measureWidth < double.PositiveInfinity) && (index++ < (row + rowSpan)));

                stateDict[element].Element.Measure(new Size(measureWidth, measureHeight));
            }
        }