//+------------------------------------------------------------------+ //| Box.mqh | //| Enrico Lambino | //| www.mql5.com/en/users/iceron| //+------------------------------------------------------------------+ #property copyright "Enrico Lambino" #property link "www.mql5.com/en/users/iceron" #include #define CLASS_LAYOUT 999 #ifdef LAYOUT_BOX_DEBUG #define COLOR_BOX_BORDER clrRed #else #define COLOR_BOX_BORDER clrNONE #endif //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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,const int padding); //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); } CSize GetMinSize() const { CSize sz; sz.cx = m_min_size.cx + m_padding_left + m_padding_right; sz.cy = m_min_size.cy + m_padding_top + m_padding_bottom; return sz; } 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(COLOR_BOX_BORDER)) 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 == &m_background) continue; CheckControlSize(control); if(control.Type() == CLASS_LAYOUT) { ((CBox *)control).GetTotalControlsSize(); } 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; if(m_layout_style == LAYOUT_STYLE_HORIZONTAL) m_total_x += control_size.cx; else m_total_x = MathMax(m_min_size.cx, m_total_x); if(m_layout_style == LAYOUT_STYLE_VERTICAL) m_total_y += control_size.cy; else m_total_y = MathMax(m_min_size.cy, m_total_y); m_controls_total++; } CSize size = Size(); if(m_total_x > size.cx && m_layout_style == LAYOUT_STYLE_HORIZONTAL) { size.cx = m_total_x; } if(m_total_y > size.cy && m_layout_style == LAYOUT_STYLE_VERTICAL) // shrink { size.cy = m_total_y; } Size(size); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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); if(x_space < 0) x_space = 0; if(y_space < 0) y_space = 0; 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,const int padding) { 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; // } //+------------------------------------------------------------------+