    //------------------------------------------------------------------------------
    // emPackLayout.h
    //
    // Copyright (C) 2015 Oliver Hamann.
    //
    // Homepage: http://eaglemode.sourceforge.net/
    //
    // This program is free software: you can redistribute it and/or modify it under
    // the terms of the GNU General Public License version 3 as published by the
    // Free Software Foundation.
    //
    // This program is distributed in the hope that it will be useful, but WITHOUT
    // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
    // more details.
    //
    // You should have received a copy of the GNU General Public License version 3
    // along with this program. If not, see <http://www.gnu.org/licenses/>.
    //------------------------------------------------------------------------------

    #ifndef emPackLayout_h
    #define emPackLayout_h

    #ifndef emBorder_h
    #include <emCore/emBorder.h>
    #endif

    //==============================================================================
    //================================ emPackLayout ================================
    //==============================================================================

    class emPackLayout : public emBorder {

    public:

            // A panel of this class automatically lays out its child panels within
            // the content area by a special "pack" algorithm, which allows to give
            // each child panel a weight (area proportion) and a preferred tallness
            // (height/width ratio). This should be used only for up to about seven
            // child panels. With more, the algorithm may not find an optimal
            // layout.
            //
            //                    Pack layout
            //   +---------------------------------------------+
            //   | +------------------+  +---------+  +-----+  |
            //   | |                  |  |         |  |     |  |
            //   | |                  |  |         |  |     |  |
            //   | |                  |  |         |  |     |  |
            //   | |                  |  |         |  +-----+  |
            //   | |                  |  |         |           |
            //   | |                  |  |         |  +-----+  |
            //   | |                  |  |         |  |     |  |
            //   | +------------------+  |         |  |     |  |
            //   |                       |         |  |     |  |
            //   | +------------------+  |         |  |     |  |
            //   | |                  |  |         |  |     |  |
            //   | |                  |  |         |  |     |  |
            //   | +------------------+  +---------+  +-----+  |
            //   +---------------------------------------------+
            //
            // The algorithm recursively divides the available area and the child
            // panel set into two areas and two child panel sets until each area has
            // only one panel. Thereby, the order of child panels is kept. The area
            // proportions are calculated from the given weights. The decision where
            // (at which child panel) and how (horizontally or vertically) the
            // dividing in each recursive step is made, is determined by iterating
            // multiple possibilities until a solution is found which satisfies the
            // preferred tallnesses best possible. Because this would be too time
            // consuming for large sets, the algorithm reduces the number of
            // iterations in a recursive step depending on the size of the set (down
            // to zero for large sets). This way, an optimum is guaranteed only for
            // up to seven child panels.
            //
            // By default, a panel of this class is not focusable and has no border,
            // because it is meant as a pure layout programming tool. For other use,
            // please see the derived class emPackGroup.

            emPackLayout(
                    ParentArg parent, const emString & name,
                    const emString & caption=emString(),
                    const emString & description=emString(),
                    const emImage & icon=emImage()
            );
                    // Like emBorder, but sets non-focusable.

            virtual ~emPackLayout();
                    // Destructor.

            int GetMinCellCount() const;
            void SetMinCellCount(int minCellCount);
                    // Minimum number of cells to be generated. The layout algorithm
                    // behaves like if there were at least this number of child
                    // panels. The additional cells are simply making up unused
                    // space. The default is zero.

            double GetChildWeight(int index) const;
            void SetChildWeight(int index, double weight);
                    // Get or set the weight of a child panel. The bigger the weight
                    // of a child panel, the bigger is the proportion of the
                    // available area given to that panel by the layout algorithm.
                    // It is a simple linear relation. The index argument denotes a
                    // child panel. Zero means first child, one means second, and so
                    // on. The default weight is 1.0.

            void SetChildWeight(double weight);
                    // Set the weight of all child panels to the given value.

            double GetPrefChildTallness(int index) const;
            void SetPrefChildTallness(int index, double pct);
                    // Get or set the preferred tallness (height/width ratio) of a
                    // child panel. The index argument denotes a child panel. Zero
                    // means first child, one means second, and so on. The default
                    // preferred tallness is 0.2.

            void SetPrefChildTallness(double pct);
                    // Set the preferred tallness of all child panels to the given
                    // value.

    protected:

            virtual void LayoutChildren();
                    // Lays out all child panels in the content area (except for an
                    // auxiliary panel, which is laid out in the border).

    private:

            struct TmpPanelInfo {
                    double PCT;
                    double CumulativeWeight;
                    double CumulativeLogPCT;
                    emPanel * Panel;
            };

            struct TmpInfo {
                    TmpPanelInfo * TPIs;
                    emColor CanvasColor;
            };

            int CountCells();
            void FillTPIs(int count);
            double GetTPIWeightSum(int index, int count) const;
            double GetTPILogPCTSum(int index, int count) const;

            double RateCell(int index, double w, double h);

            double Pack1(
                    int index,
                    double x, double y, double w, double h,
                    bool execute
            );

            double Pack2(
                    int index,
                    double x, double y, double w, double h,
                    double bestError, bool execute
            );

            double Pack3(
                    int index,
                    double x, double y, double w, double h,
                    double bestError, bool execute
            );

            double PackN(
                    int index, int count,
                    double x, double y, double w, double h,
                    double bestError, bool execute
            );

            double RateHorizontally(
                    int index, int count, int div,
                    double x, double y, double w1, double w2, double h,
                    double bestError
            );

            double RateVertically(
                    int index, int count, int div,
                    double x, double y, double w, double h1, double h2,
                    double bestError
            );

            double DefaultWeight;
            double DefaultPCT;
            emArray<double> WeightArray;
            emArray<double> PCTArray;
            int MinCellCount;
            TmpInfo * TI;
            int Ratings;
    };

    inline int emPackLayout::GetMinCellCount() const
    {
            return MinCellCount;
    }

    #endif