using System;
using System.Windows;
using System.Windows.Controls;

namespace CustomPanels
{
    public class OverlapPanel : Panel
    {
        double _totalChildrenSize = 0; /**********/

        // Kierunek układania
        public static readonly DependencyProperty OrientationProperty =
          DependencyProperty.Register("Orientation", typeof(Orientation),
          typeof(OverlapPanel), new FrameworkPropertyMetadata(Orientation.Vertical,
          FrameworkPropertyMetadataOptions.AffectsMeasure));

        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            Size desiredSize = new Size();

            foreach (UIElement child in this.Children)
            {
                if (child != null)
                {
                    /************/
                    // Zobacz, jak duży chce być każdy element podrzędny, gdyby miał całe dostępne miejsce.
                    child.Measure(availableSize);
                    /************/

                    // Nasz pożądany rozmiar jest sumą rozmiarów elementów podrzędnych 
                    // w kierunku układania oraz rozmiaru największego elementu
                    // podrzędnego w kierunku przeciwnym.
                    if (Orientation == Orientation.Vertical)
                    {
                        desiredSize.Width = Math.Max(desiredSize.Width,
                                                     child.DesiredSize.Width);
                        desiredSize.Height += child.DesiredSize.Height;
                    }
                    else
                    {
                        desiredSize.Height = Math.Max(desiredSize.Height,
                                                      child.DesiredSize.Height);
                        desiredSize.Width += child.DesiredSize.Width;
                    }
                }
            }

            _totalChildrenSize = (Orientation == Orientation.Vertical ? desiredSize.Height : desiredSize.Width); /************/

            return desiredSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            double offset = 0;
            /************/
            double overlap = 0;

            // Określ szerokość nakładania, sprawdzając, o ile mniej miejsca mamy, niż potrzeba,
            // i rozdzielając tę wartość równomiernie między elementy podrzędne.
            if (Orientation == Orientation.Vertical)
            {
                if (finalSize.Height > _totalChildrenSize)
                    // Jeśli mamy więcej miejsca niż _totalChildrenSize, ujemna wartość overlap
                    // określa, o ile powinien zostać rozciągnięty cały układ.
                    overlap = (_totalChildrenSize - finalSize.Height) / this.Children.Count;
                else
                    // W takim przypadku this.DesiredSize zawiera rzeczywisty, mniejszy rozmiar.
                    overlap = (_totalChildrenSize - this.DesiredSize.Height) / this.Children.Count;
            }
            else
            {
                if (finalSize.Width > _totalChildrenSize)
                    // Jeśli mamy więcej miejsca niż _totalChildrenSize, ujemna wartość overlap
                    // określa, o ile powinien zostać rozciągnięty cały układ.
                    overlap = (_totalChildrenSize - finalSize.Width) / this.Children.Count;
                else
                    // W takim przypadku this.DesiredSize zawiera rzeczywisty, mniejszy rozmiar.
                    overlap = (_totalChildrenSize - this.DesiredSize.Width) / this.Children.Count;
            }
            /************/

            foreach (UIElement child in this.Children)
            {
                if (child != null)
                {
                    if (Orientation == Orientation.Vertical)
                    {
                        // Parametr offset przesuwa element podrzędny o jedno piętro w dół.
                        // Oddaj elementowi podrzędnemu naszą całą szerokość, ale tylko 
                        // tyle wysokości, ile potrzebuje
                        // albo więcej, jeśli overlap jest ujemny. /**********/
                        child.Arrange(new Rect(0, offset, finalSize.Width,
                                                          child.DesiredSize.Height + (overlap > 0 ? 0 : -overlap)));

                        // Zaktualizuj parametr offset dla kolejnego elementu podrzędnego.
                        offset += (child.DesiredSize.Height - overlap); /************/
                    }
                    else
                    {
                        // Parametr offset przesuwa element podrzędny o jedno piętro w dół.
                        // Oddaj elementowi podrzędnemu naszą całą szerokość, ale tylko
                        // tyle wysokości, ile potrzebuje
                        // albo więcej, jeśli overlap jest ujemny. /**********/
                        child.Arrange(new Rect(offset, 0, child.DesiredSize.Width + (overlap > 0 ? 0 : -overlap),
                                                          finalSize.Height));

                        // Zaktualizuj parametr offset dla kolejnego elementu podrzędnego.
                        offset += (child.DesiredSize.Width - overlap); /************/
                    }
                }
            }

            // Wypełnij całą przydzieloną przestrzeń.
            return finalSize;
        }
    }
}