//------------------------------------------------------------------------------
// emLinearLayout.h
//
// Copyright (C) 2015,2017,2020-2022 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 emLinearLayout_h
#define emLinearLayout_h

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


//==============================================================================
//=============================== emLinearLayout ===============================
//==============================================================================

class emLinearLayout : public emBorder {

public:

        // A panel of this class automatically lays out its child panels within
        // the content area, either horizontally or vertically. The child panels
        // can get different sizes by applying weights, minimums, maximums or
        // fixed tallnesses to the panels.
        //
        //                   Horizontal layout
        //   +---------------------------------------------+
        //   | +---+  +------------+  +-----+  +--------+  |
        //   | |   |  |            |  |     |  |        |  |
        //   | |   |  |            |  |     |  |        |  |
        //   | +---+  +------------+  +-----+  +--------+  |
        //   +---------------------------------------------+
        //
        //                   Vertical layout
        //                  +---------------+
        //                  | +-----------+ |
        //                  | |           | |
        //                  | |           | |
        //                  | |           | |
        //                  | |           | |
        //                  | +-----------+ |
        //                  |               |
        //                  | +-----------+ |
        //                  | |           | |
        //                  | +-----------+ |
        //                  |               |
        //                  | +-----------+ |
        //                  | |           | |
        //                  | |           | |
        //                  | +-----------+ |
        //                  +---------------+
        //
        // 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 emLinearGroup.

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

        virtual ~emLinearLayout();
                // Destructor.

        void SetHorizontal();
                // Set horizontal layout.
                // (This is a short cut for SetOrientationThresholdTallness(1E100).)

        void SetVertical();
                // Set vertical layout.
                // (This is a short cut for SetOrientationThresholdTallness(0.0).)

        double GetOrientationThresholdTallness() const;
        void SetOrientationThresholdTallness(double tallness);
                // Threshold tallness for deciding the orientation of the
                // layout. If the tallness of the content area of the panel is
                // greater than this threshold, the orientation is vertical,
                // otherwise it is horizontal.

        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 GetMinChildTallness(int index) const;
        void SetMinChildTallness(int index, double minCT);
                // Get or set the minimum 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
                // minimum tallness is 1E-4.

        void SetMinChildTallness(double minCT);
                // Set the minimum tallness of all child panels to the given
                // value.

        double GetMaxChildTallness(int index) const;
        void SetMaxChildTallness(int index, double maxCT);
                // Get or set the maximum 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
                // maximum tallness is 1E4.

        void SetMaxChildTallness(double maxCT);
                // Set the maximum tallness of all child panels to the given
                // value.

        void SetChildTallness(int index, double tallness);
                // Set a fixed tallness for a child panel. This actually sets
                // the minimum and maximum tallness to the given value.

        void SetChildTallness(double tallness);
                // Set a fixed tallness for all child panels.

        emAlignment GetAlignment() const;
        void SetAlignment(emAlignment alignment);
                // Alignment of the child panels as a whole within the available
                // space. This applies only if the available space cannot be
                // filled completely because of minimum, maximum or fixed
                // tallnesses of the child panels. The default is
                // EM_ALIGN_CENTER.

        double GetSpaceL() const;
        double GetSpaceT() const;
        double GetSpaceH() const;
        double GetSpaceV() const;
        double GetSpaceR() const;
        double GetSpaceB() const;
        void SetSpaceL(double l);
        void SetSpaceT(double t);
        void SetSpaceH(double h);
        void SetSpaceV(double v);
        void SetSpaceR(double r);
        void SetSpaceB(double b);
        void SetSpace(double l, double t, double h, double v, double r,
                      double b);
        void SetSpace(double lr, double tb, double h, double v);
        void SetInnerSpace(double h, double v);
        void SetOuterSpace(double l, double t, double r, double b);
        void SetOuterSpace(double lr, double tb);
                // Left, top, horizontal, vertical, right and bottom space (l,
                // t, h, v, r, b). This defines space between child panels, and
                // between child panels and borders. Here is a chart showing the
                // meaning of the six parameters:
                //
                //   +-------------------- border -------------------+
                //   |         t             t             t         |
                //   |     +-------+     +-------+     +-------+     |
                //   |  l  | panel |  h  | panel |  h  | panel |  r  |
                //   |     +-------+     +-------+     +-------+     |
                //   |         b             b             b         |
                //   +-----------------------------------------------+
                //
                //
                //   +------ border -----+
                //   |         t         |
                //   |     +-------+     |
                //   |  l  | panel |  r  |
                //   |     +-------+     |
                //   |         v         |
                //   |     +-------+     |
                //   |  l  | panel |  r  |
                //   |     +-------+     |
                //   |         v         |
                //   |     +-------+     |
                //   |  l  | panel |  r  |
                //   |     +-------+     |
                //   |         b         |
                //   +-------------------+
                //
                // The method argument lr means to set l and r to the same
                // value, same with tb for t and b.
                //
                // The values are relative to the average size of the child
                // panels. For example, v=0.5 means that the vertical space
                // between child panels gets half as tall as an average child
                // panel. The default is zero for all parameters.

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:

        double CalculateForce(int cells, double w, double h, bool horizontal) const;

        double OrientationThreshold;
        double DefaultWeight,DefaultMinTallness,DefaultMaxTallness;
        double SpaceL,SpaceT,SpaceH,SpaceV,SpaceR,SpaceB;
        emArray<double> WeightArray;
        emArray<double> MinCTArray;
        emArray<double> MaxCTArray;
        int MinCellCount;
        emAlignment Alignment;
};

inline double emLinearLayout::GetOrientationThresholdTallness() const
{
        return OrientationThreshold;
}

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

inline emAlignment emLinearLayout::GetAlignment() const
{
        return Alignment;
}

inline double emLinearLayout::GetSpaceL() const
{
        return SpaceL;
}

inline double emLinearLayout::GetSpaceT() const
{
        return SpaceT;
}

inline double emLinearLayout::GetSpaceH() const
{
        return SpaceH;
}

inline double emLinearLayout::GetSpaceV() const
{
        return SpaceV;
}

inline double emLinearLayout::GetSpaceR() const
{
        return SpaceR;
}

inline double emLinearLayout::GetSpaceB() const
{
        return SpaceB;
}


#endif