Files
2025-02-07 19:12:13 +03:30

386 lines
13 KiB
Plaintext

//+------------------------------------------------------------------+
//| 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
#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;
// }
//+------------------------------------------------------------------+