//+------------------------------------------------------------------+
//|                                                          Box.mqh |
//|                                                   Enrico Lambino |
//|                                      www.mql5.com/en/users/iceron|
//+------------------------------------------------------------------+
#property copyright "Enrico Lambino"
#property link      "www.mql5.com/en/users/iceron"
#include <Controls\WndClient.mqh>
#define CLASS_LAYOUT 999
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum LAYOUT_STYLE
  {
   LAYOUT_STYLE_VERTICAL,
   LAYOUT_STYLE_HORIZONTAL
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum VERTICAL_ALIGN
  {
   VERTICAL_ALIGN_CENTER,
   VERTICAL_ALIGN_CENTER_NOSIDES,
   VERTICAL_ALIGN_TOP,
   VERTICAL_ALIGN_BOTTOM
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum HORIZONTAL_ALIGN
  {
   HORIZONTAL_ALIGN_CENTER,
   HORIZONTAL_ALIGN_CENTER_NOSIDES,
   HORIZONTAL_ALIGN_LEFT,
   HORIZONTAL_ALIGN_RIGHT
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CBox : public CWndClient
  {
protected:
   LAYOUT_STYLE      m_layout_style;
   VERTICAL_ALIGN    m_vertical_align;
   HORIZONTAL_ALIGN  m_horizontal_align;
   CSize             m_min_size;
   int               m_controls_total;
   int               m_padding_top;
   int               m_padding_bottom;
   int               m_padding_left;
   int               m_padding_right;
   int               m_total_x;
   int               m_total_y;
   
public:
                     CBox();
                    ~CBox();
   virtual int       Type() const {return CLASS_LAYOUT;}
   virtual bool      Create(const long chart,const string name,const int subwin,
                           const int x1,const int y1,const int x2,const int y2);
   virtual bool      Pack();
   void              LayoutStyle(LAYOUT_STYLE style){m_layout_style=style;}
   LAYOUT_STYLE      LayoutStyle() const {return(m_layout_style);}
   void              HorizontalAlign(const HORIZONTAL_ALIGN align){m_horizontal_align=align;}
   HORIZONTAL_ALIGN  HorizontalAlign() const {return(m_horizontal_align);}
   void              VerticalAlign(const VERTICAL_ALIGN align){m_vertical_align=align;}
   VERTICAL_ALIGN    VerticalAlign() const {return(m_vertical_align);}
   void              Padding(const int top,const int bottom,const int left,const int right);
   void              Padding(const int padding);
   void              PaddingTop(const int padding) {m_padding_top=padding;}
   int               PaddingTop() const {return(m_padding_top);}
   void              PaddingRight(const int padding) {m_padding_right=padding;}
   int               PaddingRight() const {return(m_padding_right);}
   void              PaddingBottom(const int padding) {m_padding_bottom=padding;}
   int               PaddingBottom() const  {return(m_padding_bottom);}
   void              PaddingLeft(const int padding) {m_padding_left=padding;}
   int               PaddingLeft() const {return(m_padding_left);}
   
protected:
   virtual void      CheckControlSize(CWnd *control);
   virtual void      GetTotalControlsSize(void);
   virtual bool      GetSpace(int &x_space,int &y_space);
   virtual bool      Render(void);
   virtual void      Shift(CWnd *control,int &x,int &y,const int x_space,const int y_space);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CBox::CBox() : m_layout_style(LAYOUT_STYLE_HORIZONTAL),
               m_vertical_align(VERTICAL_ALIGN_CENTER),
               m_horizontal_align(HORIZONTAL_ALIGN_CENTER),
               m_controls_total(0),
               m_padding_top(2),
               m_padding_bottom(2),
               m_padding_left(2),
               m_padding_right(2),
               m_total_x(0),
               m_total_y(0)

  {
   m_min_size.cx = 0;
   m_min_size.cy = 0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CBox::~CBox()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CBox::Create(const long chart,const string name,const int subwin,
                  const int x1,const int y1,const int x2,const int y2)
  {
   if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
   if(!CreateBack())
      return(false);
   if(!ColorBackground(CONTROLS_DIALOG_COLOR_CLIENT_BG))
      return(false);
   if(!ColorBorder(clrNONE))
      return(false);
   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CBox::Pack(void)
  {
   GetTotalControlsSize();
   return(Render());
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CBox::CheckControlSize(CWnd *control)
  {
   bool adjust=false;
   CSize size=Size();
   CSize control_size=control.Size();
   if(control_size.cx>size.cx-(m_padding_left+m_padding_right))
     {
      control_size.cx=size.cx-(m_padding_left+m_padding_right);
      adjust=true;
     }
   if(control_size.cy>size.cy-(m_padding_top+m_padding_bottom))
     {
      control_size.cy=size.cy-(m_padding_top+m_padding_bottom);
      adjust=true;
     }
   if(adjust)
      control.Size(control_size.cx,control_size.cy);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CBox::GetTotalControlsSize(void)
  {
   m_total_x = 0;
   m_total_y = 0;
   m_controls_total = 0;
   m_min_size.cx = 0;
   m_min_size.cy = 0;   
   int total=ControlsTotal();
   for(int i=0;i<total;i++)
     {
      CWnd *control=Control(i);
      if(control==NULL)
         continue;
      if(control==GetPointer(m_background))
         continue;
      CheckControlSize(GetPointer(control));
      CSize control_size=control.Size();
      if(m_min_size.cx<control_size.cx)
         m_min_size.cx=control_size.cx;
      if(m_min_size.cy<control_size.cy)
         m_min_size.cy=control_size.cy;
      m_total_x += control_size.cx;
      m_total_y += control_size.cy;
      m_controls_total++;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CBox::GetSpace(int &x_space,int &y_space)
  {
   if(m_controls_total==0)
      return(true);
   if(m_controls_total==1)
     {
      if(m_horizontal_align==HORIZONTAL_ALIGN_CENTER_NOSIDES)
         m_horizontal_align= HORIZONTAL_ALIGN_CENTER;
      if(m_vertical_align==VERTICAL_ALIGN_CENTER_NOSIDES)
         m_vertical_align= VERTICAL_ALIGN_CENTER;
     }
   CSize size=Size();
   int x_space_total=0;
   int y_space_total=0;
   if(m_layout_style==LAYOUT_STYLE_HORIZONTAL)
     {
      x_space_total=size.cx-(m_total_x+m_padding_left+m_padding_right);
      y_space_total=size.cy-(m_min_size.cy+m_padding_top+m_padding_bottom);

      if(m_horizontal_align==HORIZONTAL_ALIGN_CENTER_NOSIDES)
         x_space=x_space_total/(m_controls_total-1);
      else if(m_horizontal_align==HORIZONTAL_ALIGN_CENTER)
         x_space=x_space_total/(m_controls_total+1);
      else
         x_space=x_space_total/m_controls_total;

      if(m_vertical_align==VERTICAL_ALIGN_CENTER || m_vertical_align==VERTICAL_ALIGN_CENTER_NOSIDES)
         y_space=y_space_total/2;
      else y_space=y_space_total;
     }
   else if(m_layout_style==LAYOUT_STYLE_VERTICAL)
     {
      x_space_total=size.cx-(m_min_size.cx+m_padding_left+m_padding_right);
      y_space_total=size.cy -(m_total_y+m_padding_top+m_padding_bottom);

      if(m_horizontal_align==HORIZONTAL_ALIGN_CENTER || m_horizontal_align==HORIZONTAL_ALIGN_CENTER_NOSIDES)
         x_space=x_space_total/2;
      else x_space=x_space_total;

      if(m_vertical_align==VERTICAL_ALIGN_CENTER_NOSIDES)
         y_space=y_space_total/(m_controls_total-1);
      else if(m_vertical_align==VERTICAL_ALIGN_CENTER)
         y_space=y_space_total/(m_controls_total+1);
      else y_space=y_space_total/m_controls_total;
     }
   else return(false);
   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CBox::Shift(CWnd *control,int &x,int &y,const int x_space,const int y_space)
  {
   if(m_layout_style==LAYOUT_STYLE_HORIZONTAL)
      x+=x_space+control.Width();
   else if(m_layout_style==LAYOUT_STYLE_VERTICAL)
      y+=y_space+control.Height();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CBox::Render(void)
  {
   int x_space=0,y_space=0;
   if(!GetSpace(x_space,y_space))
      return(false);
   int x=Left()+m_padding_left+
      ((m_horizontal_align==HORIZONTAL_ALIGN_LEFT||m_horizontal_align==HORIZONTAL_ALIGN_CENTER_NOSIDES)?0:x_space);
   int y=Top()+m_padding_top+
      ((m_vertical_align==VERTICAL_ALIGN_TOP||m_vertical_align==VERTICAL_ALIGN_CENTER_NOSIDES)?0:y_space);
   for(int j=0;j<ControlsTotal();j++)
     {
      CWnd *control=Control(j);
      if(control==NULL) 
         continue;
      if(control==GetPointer(m_background)) 
         continue;
      control.Move(x,y);
      if(control.Type()==CLASS_LAYOUT)
        {
         CBox *container=control;
         container.Pack();
        }        
      if (j<ControlsTotal()-1)
         Shift(GetPointer(control),x,y,x_space,y_space);      
     }
   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CBox::Padding(const int top,const int right,const int bottom,const int left)
  {
   m_padding_top=top;
   m_padding_right=right;
   m_padding_bottom=bottom;
   m_padding_left=left;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CBox::Padding(const int padding)
  {
   m_padding_top=padding;
   m_padding_right=padding;
   m_padding_bottom=padding;
   m_padding_left=padding;
  }
//+------------------------------------------------------------------+
