//------------------------------------------------------------------------------
// emBorder.h
//
// Copyright (C) 2005-2010,2014-2016,2021 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 emBorder_h
#define emBorder_h

#ifndef emVarModel_h
#include <emCore/emVarModel.h>
#endif

#ifndef emLook_h
#include <emCore/emLook.h>
#endif


//==============================================================================
//================================== emBorder ==================================
//==============================================================================

class emBorder : public emPanel {

public:

        // This is the base class of all toolkit panels. A panel of this class
        // can have a border, a label, a how-to text and an auxiliary area. And
        // it has a content area. The label can consist of a caption, a
        // description and an icon. The how-to text describes how to use the
        // type of panel in general, and maybe something about its state. The
        // auxiliary area is for showing a custom panel with additional things
        // like a configuration or an extended help text. The label, the how-to
        // text and the auxiliary area are shown in the border. Alternatively, a
        // derived class can manage to move the label into the content area.

        emBorder(
                ParentArg parent, const emString & name,
                const emString & caption=emString(),
                const emString & description=emString(),
                const emImage & icon=emImage()
        );
                // Constructor.
                // Arguments:
                //   parent      - Parent for this panel (emPanel or emView).
                //   name        - The name for this panel.
                //   caption     - The label's caption, or empty.
                //   description - The label's description, or empty.
                //   icon        - The label's icon, or empty.

        virtual ~emBorder();
                // Destructor.

        const emString & GetCaption() const;
        void SetCaption(const emString & caption);
                // The caption to be shown in the label.

        const emString & GetDescription() const;
        void SetDescription(const emString & description);
                // The description to be shown in the label.

        const emImage & GetIcon() const;
        void SetIcon(const emImage & icon);
                // The icon to be shown in the label.

        void SetLabel(
                const emString & caption=emString(),
                const emString & description=emString(),
                const emImage & icon=emImage()
        );
                // Set all three things which are making up the label.

        emAlignment GetLabelAlignment() const;
        void SetLabelAlignment(emAlignment labelAlignment);
                // Alignment of the label as a whole within its available space.

        emAlignment GetCaptionAlignment() const;
        void SetCaptionAlignment(emAlignment captionAlignment);
                // Horizontal alignment of lines within the caption text of the
                // label. The top and bottom flags are ignored.

        emAlignment GetDescriptionAlignment() const;
        void SetDescriptionAlignment(emAlignment descriptionAlignment);
                // Horizontal alignment of lines within the description text of
                // the label. The top and bottom flags are ignored.

        bool IsIconAboveCaption() const;
        void SetIconAboveCaption(bool iconAboveCaption=true);
                // Whether the icon is shown above the caption (true), or if it
                // is shown to the left of the caption (false, the default).

        double GetMaxIconAreaTallness() const;
        void SetMaxIconAreaTallness(double maxIconAreaTallness);
                // Maximum tallness (height/width ratio) of the area in the
                // label preserved for the icon (if the label has an icon). The
                // default is 1.0. If you have a group of elements (e.g.
                // buttons) which show icons and captions, and if the icon
                // images have different tallnesses, then it is a good idea to
                // set this parameter to the minimum(!) tallness of all the icon
                // images. Thereby, the icons and captions of all the elements
                // will be aligned pretty equal.

        enum OuterBorderType {
                // Possibles types for the outer border line. This even
                // specifies whether the background of the panel should be
                // filled or not.
                OBT_NONE,
                        // Do not have an outer border line, do not have a
                        // margin and do not fill the background.
                OBT_FILLED,
                        // Like OBT_NONE, but fill the whole background with
                        // background color.
                OBT_MARGIN,
                        // Like OBT_NONE, but have a small margin (for example,
                        // this is used by emLabel and emCheckBox). Larger
                        // margins should be solved through the parent panel,
                        // e.g. see emLinearLayout::SetSpace.
                OBT_MARGIN_FILLED,
                        // Like OBT_MARGIN, but fill the whole background.
                OBT_RECT,
                        // Have a rectangular outer border line and fill the
                        // rectangle with background color. Have a small margin.
                OBT_ROUND_RECT,
                        // Like OBT_RECT but with round corners.
                OBT_GROUP,
                        // Have a small special outer border for groups (used by
                        // group panels like emLinearGroup and so on).
                OBT_INSTRUMENT,
                        // Like OBT_GROUP, but the border line is thicker (for
                        // example, this is used by emTextField).
                OBT_INSTRUMENT_MORE_ROUND,
                        // Like OBT_INSTRUMENT, but with a larger corner radius
                        // (this is used by emButton).
                OBT_POPUP_ROOT
                        // Have a special border for root panels of views which
                        // have the VF_POPUP_ZOOM flag set (should not be used
                        // for something else).
        };

        enum InnerBorderType {
                // Possibles types for the inner border line.
                IBT_NONE,
                        // Do not have an inner border line.
                IBT_GROUP,
                        // Have a special round inner border line for groups.
                IBT_INPUT_FIELD,
                        // Have a special round inner border and background for
                        // editable fields.
                IBT_OUTPUT_FIELD,
                        // Have a special round inner border and background for
                        // non-editable fields.
                IBT_CUSTOM_RECT
                        // Have a special rectangular inner border for custom
                        // stuff. Herewith, the content rectangle never has
                        // round corners.
        };

        OuterBorderType GetOuterBorderType() const;
        InnerBorderType GetInnerBorderType() const;
        void SetOuterBorderType(OuterBorderType obt);
        void SetInnerBorderType(InnerBorderType ibt);
        void SetBorderType(OuterBorderType obt, InnerBorderType ibt);
                // Outer and inner border types. The default is OBT_NONE and
                // IBT_NONE.

        double GetBorderScaling() const;
        void SetBorderScaling(double borderScaling);
                // Scale factor for the size of the border. The default is 1.0.

        const emLook & GetLook() const;
        virtual void SetLook(const emLook & look, bool recursively=false);
                // Look of this toolkit panel. At construction of a panel, the
                // look is copied from the parent panel (if the parent is not
                // emBorder, the grand parent is asked, and so on). When
                // setting the look with the argument recursively=true, all
                // descendant panels of class emBorder are even set through
                // calling emLook::Apply for every child panel.

        void HaveAux(const emString & panelName, double tallness);
                // Make this border having a rectangular area for auxiliary
                // stuff. It could be a user interface for configuring this
                // panel, or an extended function, or some additional help or
                // what ever you want. Either you could show the things through
                // a child panel or through custom painting, but doing it with a
                // child panel is easier. Whenever you create that panel. It is
                // laid out automatically into the auxiliary area.
                // Arguments:
                //   panelName - Name of the child panel to be laid out in the
                //               auxiliary area.
                //   tallness  - Height/width ratio of the auxiliary area.

        void RemoveAux();
                // Inversion of HaveAux (does not delete the auxiliary panel).

        bool HasAux() const;
                // Whether this border has an area for auxiliary stuff.

        const emString & GetAuxPanelName() const;
        double GetAuxTallness() const;
                // Properties of the auxiliary area set with HaveAux. Valid only
                // if HasAux()==true.

        emPanel * GetAuxPanel();
                // Returns the auxiliary child panel, or NULL if not present.

        void GetAuxRect(
                double * pX, double * pY, double * pW, double * pH,
                emColor * pCanvasColor=NULL
        ) const;
                // Get the coordinates and canvas color of the auxiliary area.
                // Valid only if HasAux()==true.

        virtual void GetSubstanceRect(double * pX, double * pY,
                                      double * pW, double * pH,
                                      double * pR) const;
                // Overloaded from emPanel (read there).

        virtual void GetContentRoundRect(
                double * pX, double * pY, double * pW, double * pH, double * pR,
                emColor * pCanvasColor=NULL
        ) const;
                // Get the coordinates and canvas color of the content area as a
                // round rectangle (argument pR is for returning the radius of
                // the corners).

        virtual void GetContentRect(
                double * pX, double * pY, double * pW, double * pH,
                emColor * pCanvasColor=NULL
        ) const;
                // Get the coordinates and canvas color of the content area as a
                // rectangle. If the inner border has round corners, the
                // rectangle returned here is smaller than with
                // GetContentRoundRect, so that it fits completely into the
                // content area.

        virtual void GetContentRectUnobscured(
                double * pX, double * pY, double * pW, double * pH,
                emColor * pCanvasColor=NULL
        ) const;
                // Get the coordinates and canvas color of the unobscured part
                // of the content area. Some border types are painting an
                // overlay like a shadow at the edges of the content area, after
                // PaintContent is called. This does not work for child panels,
                // because they are painted after the overlay. Therefore child
                // panels should be laid out in the rectangle returned by
                // GetContentRectUnobscured. It returns the inner part, which is
                // not painted over.

protected:

        virtual void Notice(NoticeFlags flags);
        virtual bool IsOpaque() const;
        virtual void Paint(const emPainter & painter, emColor canvasColor) const;
        virtual void LayoutChildren();
                // See emPanel. Hint: For painting the content area, please
                // overload PaintContent instead of Paint, because with certain
                // border types, a shadow is painted over the content area.

        virtual bool HasHowTo() const;
        virtual emString GetHowTo() const;
                // This is about a text describing how to use this panel. If
                // HasHowTo()==true, the text returned by GetHowTo() is shown
                // very small in the center of the left edge of the border. When
                // overloading GetHowTo(), please do not forget to call the
                // original version and to include that text at the beginning.
                // The default implementation of GetHowTo() returns a preface,
                // and optionally a description of the disable state (if
                // disabled) and optionally a description of the keyboard focus
                // (if focusable). The default implementation of HasHowTo()
                // return false, because the default text alone is not so
                // helpful, and because the text would disturb some panel types.

        virtual void PaintContent(
                const emPainter & painter, double x, double y, double w,
                double h, emColor canvasColor
        ) const;
                // This can be overloaded for painting the content area. The
                // default implementation does nothing. The coordinates x,y,w,h
                // are like from GetContentRect, but you could even use the
                // coordinates returned by GetContentRoundRect.

        virtual bool HasLabel() const;
                // Whether this panel has a label. The default implementation
                // checks whether at least one of caption, description and icon
                // is not empty.

        virtual double GetBestLabelTallness() const;
                // Get the ideal tallness for the label area. The default
                // implementation calculates this for the default implementation
                // of PaintLabel.

        virtual void PaintLabel(
                const emPainter & painter, double x, double y, double w,
                double h, emColor color, emColor canvasColor
        ) const;
                // Paint the label. The default implementation paints the
                // caption, description and icon. This could be overloaded to
                // paint something else for the label.

        bool IsLabelInBorder() const;
        void SetLabelInBorder(bool labelInBorder);
                // Whether to show the label as part of the border. The default
                // is true. If a derived class wants to have the label as part
                // of the content, it should set false here and call PaintLabel
                // itself.

        struct TkResources {
                TkResources();
                ~TkResources();
                emImage ImgButton;
                emImage ImgButtonBorder;
                emImage ImgButtonChecked;
                emImage ImgButtonPressed;
                emImage ImgCheckBox;
                emImage ImgCheckBoxPressed;
                emImage ImgCustomRectBorder;
                emImage ImgDir;
                emImage ImgDirUp;
                emImage ImgGroupBorder;
                emImage ImgGroupInnerBorder;
                emImage ImgIOField;
                emImage ImgPopupBorder;
                emImage ImgRadioBox;
                emImage ImgRadioBoxPressed;
                emImage ImgSplitter;
                emImage ImgSplitterPressed;
                emImage ImgTunnel;
        };
        const TkResources & GetTkResources() const;
                // Shared resources used by the toolkit panel implementations.
                // This is more or less private stuff - do not use in custom
                // classes.

        // - - - - - - - - - - Depreciated methods - - - - - - - - - - - - - - -
        // The following virtual non-const methods have been replaced by const
        // methods (see above). The old versions still exist here with the
        // "final" keyword added, so that old overridings will fail to compile.
        // If you run into this, please adapt your overridings by adding "const".
public:
        virtual void GetContentRoundRect(
                double * pX, double * pY, double * pW, double * pH, double * pR,
                emColor * pCanvasColor=NULL
        ) final;
        virtual void GetContentRect(
                double * pX, double * pY, double * pW, double * pH,
                emColor * pCanvasColor=NULL
        ) final;
        virtual void GetContentRectUnobscured(
                double * pX, double * pY, double * pW, double * pH,
                emColor * pCanvasColor=NULL
        ) final;
protected:
        virtual bool HasHowTo() final;
        virtual emString GetHowTo() final;
        virtual void PaintContent(
                const emPainter & painter, double x, double y, double w,
                double h, emColor canvasColor
        ) final;
        virtual bool HasLabel() final;
        virtual double GetBestLabelTallness() final;
        virtual void PaintLabel(
                const emPainter & painter, double x, double y, double w,
                double h, emColor color, emColor canvasColor
        ) final;
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

private:

        enum DoBorderFunc {
                BORDER_FUNC_PAINT,
                BORDER_FUNC_SUBSTANCE_ROUND_RECT,
                BORDER_FUNC_CONTENT_ROUND_RECT,
                BORDER_FUNC_CONTENT_RECT,
                BORDER_FUNC_CONTENT_RECT_UNOBSCURED,
                BORDER_FUNC_AUX_RECT
        };
        void DoBorder(
                DoBorderFunc func, const emPainter * painter,
                emColor canvasColor, double * pX, double * pY, double * pW,
                double * pH, double * pR, emColor * pCanvasColor
        ) const;

        enum DoLabelFunc {
                LABEL_FUNC_PAINT,
                LABEL_FUNC_GET_BEST_TALLNESS
        };
        void DoLabel(
                DoLabelFunc func, const emPainter * painter, double x, double y,
                double w, double h, emColor color, emColor canvasColor,
                double * pBestTallness
        ) const;

        struct AuxData {
                emString PanelName;
                double Tallness;
                emCrossPtr<emPanel> PanelPointerCache;
        };

        emRef<emVarModel<TkResources> > TkResVarModel;
        emString Caption;
        emString Description;
        emImage Icon;
        AuxData * Aux;
        emLook Look;
        double MaxIconAreaTallness;
        double BorderScaling;
        emAlignment LabelAlignment;
        emAlignment CaptionAlignment;
        emAlignment DescriptionAlignment;
        emByte OuterBorder;
        emByte InnerBorder;
        bool IconAboveCaption;
        bool LabelInBorder;

        static const char * const HowToPreface;
        static const char * const HowToDisabled;
        static const char * const HowToFocus;
};

inline const emString & emBorder::GetCaption() const
{
        return Caption;
}

inline const emString & emBorder::GetDescription() const
{
        return Description;
}

inline const emImage & emBorder::GetIcon() const
{
        return Icon;
}

inline emAlignment emBorder::GetLabelAlignment() const
{
        return LabelAlignment;
}

inline emAlignment emBorder::GetCaptionAlignment() const
{
        return CaptionAlignment;
}

inline emAlignment emBorder::GetDescriptionAlignment() const
{
        return DescriptionAlignment;
}

inline bool emBorder::IsIconAboveCaption() const
{
        return IconAboveCaption;
}

inline double emBorder::GetMaxIconAreaTallness() const
{
        return MaxIconAreaTallness;
}

inline emBorder::OuterBorderType emBorder::GetOuterBorderType() const
{
        return (OuterBorderType)OuterBorder;
}

inline emBorder::InnerBorderType emBorder::GetInnerBorderType() const
{
        return (InnerBorderType)InnerBorder;
}

inline double emBorder::GetBorderScaling() const
{
        return BorderScaling;
}

inline const emLook & emBorder::GetLook() const
{
        return Look;
}

inline bool emBorder::HasAux() const
{
        return Aux!=NULL;
}

inline bool emBorder::IsLabelInBorder() const
{
        return LabelInBorder;
}

inline const emBorder::TkResources & emBorder::GetTkResources() const
{
        return TkResVarModel->Var;
}


#endif