Add files via upload
This commit is contained in:
+385
@@ -0,0 +1,385 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
// }
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,66 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ComboBoxResizable.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#include <Controls/ComboBox.mqh>
|
||||
|
||||
class ComboBoxResizable: public CComboBox
|
||||
{
|
||||
public:
|
||||
virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) override;
|
||||
|
||||
virtual bool OnResize(void) override
|
||||
{
|
||||
m_edit.Width(Width());
|
||||
|
||||
int x1 = Width() - (CONTROLS_BUTTON_SIZE + CONTROLS_COMBO_BUTTON_X_OFF);
|
||||
int y1 = (Height() - CONTROLS_BUTTON_SIZE) / 2;
|
||||
m_drop.Move(Left() + x1, Top() + y1);
|
||||
|
||||
m_list.Width(Width());
|
||||
|
||||
return CWndContainer::OnResize();
|
||||
}
|
||||
|
||||
virtual bool OnClickButton(void) override
|
||||
{
|
||||
// this is a hack to trigger resizing of elements in the list
|
||||
// we need it because standard ListView is incorrectly coded in such a way
|
||||
// that elements are resized only if vscroll is present
|
||||
bool vs = m_list.VScrolled();
|
||||
if(m_drop.Pressed())
|
||||
{
|
||||
m_list.VScrolled(true);
|
||||
}
|
||||
bool b = CComboBox::OnClickButton();
|
||||
m_list.VScrolled(vs);
|
||||
return b;
|
||||
}
|
||||
|
||||
virtual bool Enable(void) override
|
||||
{
|
||||
m_edit.Show();
|
||||
m_drop.Show();
|
||||
return CComboBox::Enable();
|
||||
}
|
||||
|
||||
virtual bool Disable(void) override
|
||||
{
|
||||
m_edit.Hide();
|
||||
m_drop.Hide();
|
||||
return CComboBox::Disable();
|
||||
}
|
||||
};
|
||||
|
||||
#define EXIT_ON_DISABLED \
|
||||
if(!IsEnabled()) \
|
||||
{ \
|
||||
return false; \
|
||||
}
|
||||
|
||||
EVENT_MAP_BEGIN(ComboBoxResizable)
|
||||
EXIT_ON_DISABLED
|
||||
ON_EVENT(ON_CLICK, m_drop, OnClickButton)
|
||||
EVENT_MAP_END(CComboBox)
|
||||
@@ -0,0 +1,153 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Grid.mqh |
|
||||
//| Enrico Lambino |
|
||||
//| www.mql5.com/en/users/iceron|
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Enrico Lambino"
|
||||
#property link "http://www.mql5.com"
|
||||
#property strict
|
||||
#include "Box.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CGrid: public CBox
|
||||
{
|
||||
protected:
|
||||
int m_cols;
|
||||
int m_rows;
|
||||
int m_hgap;
|
||||
int m_vgap;
|
||||
CSize m_cell_size;
|
||||
|
||||
public:
|
||||
CGrid();
|
||||
CGrid(int rows, int cols, int hgap = 0, int vgap = 0);
|
||||
~CGrid();
|
||||
virtual int Type() const
|
||||
{
|
||||
return CLASS_LAYOUT;
|
||||
}
|
||||
virtual bool Init(int rows, int cols, int hgap = 0, int vgap = 0);
|
||||
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 int Columns()
|
||||
{
|
||||
return (m_cols);
|
||||
}
|
||||
virtual void Columns(int cols)
|
||||
{
|
||||
m_cols = cols;
|
||||
}
|
||||
virtual int Rows()
|
||||
{
|
||||
return (m_rows);
|
||||
}
|
||||
virtual void Rows(int rows)
|
||||
{
|
||||
m_rows = rows;
|
||||
}
|
||||
virtual int HGap()
|
||||
{
|
||||
return (m_hgap);
|
||||
}
|
||||
virtual void HGap(int gap)
|
||||
{
|
||||
m_hgap = gap;
|
||||
}
|
||||
virtual int VGap()
|
||||
{
|
||||
return (m_vgap);
|
||||
}
|
||||
virtual void VGap(int gap)
|
||||
{
|
||||
m_vgap = gap;
|
||||
}
|
||||
virtual bool Pack();
|
||||
|
||||
protected:
|
||||
virtual void CheckControlSize(CWnd *control);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGrid::CGrid()
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGrid::CGrid(int rows, int cols, int hgap = 0, int vgap = 0)
|
||||
{
|
||||
Init(rows, cols, hgap, vgap);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGrid::~CGrid()
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGrid::Init(int rows, int cols, int hgap = 0, int vgap = 0)
|
||||
{
|
||||
Columns(cols);
|
||||
Rows(rows);
|
||||
HGap(hgap);
|
||||
VGap(vgap);
|
||||
return (true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGrid::Create(const long chart, const string name, const int subwin,
|
||||
const int x1, const int y1, const int x2, const int y2)
|
||||
{
|
||||
return (CBox::Create(chart, name, subwin, x1, y1, x2, y2));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGrid::Pack()
|
||||
{
|
||||
CSize size = Size();
|
||||
m_cell_size.cx = (size.cx - ((m_cols + 1) * m_hgap)) / m_cols;
|
||||
m_cell_size.cy = (size.cy - ((m_rows + 1) * m_vgap)) / m_rows;
|
||||
int x = Left(), y = Top();
|
||||
int cnt = 0;
|
||||
for(int i = 0; i < ControlsTotal(); i++)
|
||||
{
|
||||
CWnd *control = Control(i);
|
||||
if(control == NULL)
|
||||
continue;
|
||||
if(control == GetPointer(m_background))
|
||||
continue;
|
||||
if(cnt == 0 || Right() - (x + m_cell_size.cx) < m_cell_size.cx + m_hgap)
|
||||
{
|
||||
if(cnt == 0)
|
||||
y += m_vgap;
|
||||
else
|
||||
y += m_vgap + m_cell_size.cy;
|
||||
x = Left() + m_hgap;
|
||||
}
|
||||
else
|
||||
x += m_cell_size.cx + m_hgap;
|
||||
CheckControlSize(control);
|
||||
control.Move(x, y);
|
||||
if(control.Type() == CLASS_LAYOUT)
|
||||
{
|
||||
CBox *container = control;
|
||||
container.Pack();
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGrid::CheckControlSize(CWnd *control)
|
||||
{
|
||||
control.Size(m_cell_size.cx, m_cell_size.cy);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,154 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| GridTk.mqh |
|
||||
//| Enrico Lambino |
|
||||
//| www.mql5.com/en/users/iceron|
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Enrico Lambino"
|
||||
#property link "http://www.mql5.com"
|
||||
#property strict
|
||||
#include "Grid.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CGridConstraints: public CObject
|
||||
{
|
||||
protected:
|
||||
CWnd *m_control;
|
||||
int m_row;
|
||||
int m_col;
|
||||
int m_rowspan;
|
||||
int m_colspan;
|
||||
|
||||
public:
|
||||
CGridConstraints(CWnd *control, int row, int column, int rowspan = 1, int colspan = 1);
|
||||
~CGridConstraints();
|
||||
CWnd *Control()
|
||||
{
|
||||
return (m_control);
|
||||
}
|
||||
int Row()
|
||||
{
|
||||
return (m_row);
|
||||
}
|
||||
int Column()
|
||||
{
|
||||
return (m_col);
|
||||
}
|
||||
int RowSpan()
|
||||
{
|
||||
return (m_rowspan);
|
||||
}
|
||||
int ColSpan()
|
||||
{
|
||||
return (m_colspan);
|
||||
}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGridConstraints::CGridConstraints(CWnd *control, int row, int column, int rowspan = 1, int colspan = 1)
|
||||
{
|
||||
m_control = control;
|
||||
m_row = MathMax(0, row);
|
||||
m_col = MathMax(0, column);
|
||||
m_rowspan = MathMax(1, rowspan);
|
||||
m_colspan = MathMax(1, colspan);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGridConstraints::~CGridConstraints()
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
class CGridTk: public CGrid
|
||||
{
|
||||
protected:
|
||||
CArrayObj m_constraints;
|
||||
|
||||
public:
|
||||
CGridTk();
|
||||
~CGridTk();
|
||||
bool Grid(CWnd *control, int row, int column, int rowspan, int colspan);
|
||||
bool Pack();
|
||||
CGridConstraints *GetGridConstraints(CWnd *control);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGridTk::CGridTk(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGridTk::~CGridTk(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGridTk::Grid(CWnd *control, int row, int column, int rowspan = 1, int colspan = 1)
|
||||
{
|
||||
CGridConstraints *constraints = new CGridConstraints(control, row, column, rowspan, colspan);
|
||||
if(!CheckPointer(constraints))
|
||||
return (false);
|
||||
if(!m_constraints.Add(constraints))
|
||||
return (false);
|
||||
return (Add(control));
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CGridTk::Pack()
|
||||
{
|
||||
CGrid::Pack();
|
||||
CSize size = Size();
|
||||
m_cell_size.cx = (size.cx - (m_cols + 1) * m_hgap) / m_cols;
|
||||
m_cell_size.cy = (size.cy - (m_rows + 1) * m_vgap) / m_rows;
|
||||
for(int i = 0; i < ControlsTotal(); i++)
|
||||
{
|
||||
int x = Left(), y = Top();
|
||||
CWnd *control = Control(i);
|
||||
if(control == NULL)
|
||||
continue;
|
||||
if(control == GetPointer(m_background))
|
||||
continue;
|
||||
CGridConstraints *constraints = GetGridConstraints(control);
|
||||
if(constraints == NULL)
|
||||
continue;
|
||||
int column = constraints.Column();
|
||||
int row = constraints.Row();
|
||||
x += (column * m_cell_size.cx) + ((column + 1) * m_hgap);
|
||||
y += (row * m_cell_size.cy) + ((row + 1) * m_vgap);
|
||||
int colspan = constraints.ColSpan();
|
||||
int rowspan = constraints.RowSpan();
|
||||
control.Size(colspan * m_cell_size.cx + ((colspan - 1) * m_hgap), rowspan * m_cell_size.cy + ((rowspan - 1) * m_vgap));
|
||||
control.Move(x, y);
|
||||
if(control.Type() == CLASS_LAYOUT)
|
||||
{
|
||||
CBox *container = control;
|
||||
container.Pack();
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
CGridConstraints *CGridTk::GetGridConstraints(CWnd *control)
|
||||
{
|
||||
for(int i = 0; i < m_constraints.Total(); i++)
|
||||
{
|
||||
CGridConstraints *constraints = m_constraints.At(i);
|
||||
CWnd *ctrl = constraints.Control();
|
||||
if(ctrl == NULL)
|
||||
continue;
|
||||
if(ctrl == control)
|
||||
return (constraints);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,337 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| MaximizableAppDialog.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#include <Controls\Dialog.mqh>
|
||||
#include <Controls\Button.mqh>
|
||||
|
||||
#resource "res\\Expand2.bmp"
|
||||
#resource "res\\size6.bmp"
|
||||
#resource "res\\size10.bmp"
|
||||
|
||||
class MaximizableAppDialog: public CAppDialog
|
||||
{
|
||||
protected:
|
||||
CBmpButton m_button_truemax;
|
||||
CBmpButton m_button_size;
|
||||
bool m_maximized;
|
||||
CRect m_max_rect;
|
||||
CSize m_size_limit;
|
||||
bool m_sizing;
|
||||
|
||||
// window maximization
|
||||
virtual bool CreateButtonMinMax(void) override;
|
||||
virtual void OnClickButtonMinMax(void) override;
|
||||
virtual void OnClickButtonTrueMax(void);
|
||||
virtual void OnClickButtonSizeFixMe(void);
|
||||
virtual void Expand(void);
|
||||
virtual void Restore(void);
|
||||
|
||||
virtual void Minimize(void) override;
|
||||
|
||||
// window resizing
|
||||
bool CreateButtonSize(void);
|
||||
bool OnDialogSizeStart(void);
|
||||
virtual bool OnDialogDragStart(void) override;
|
||||
virtual bool OnDialogDragProcess(void) override;
|
||||
virtual bool OnDialogDragEnd(void) override;
|
||||
|
||||
virtual void SelfAdjustment(const bool minimized = false) = 0;
|
||||
|
||||
public:
|
||||
MaximizableAppDialog(): m_maximized(false), m_sizing(false) {}
|
||||
virtual bool Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2) override;
|
||||
virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) override;
|
||||
|
||||
virtual bool OnChartChange(const long &lparam, const double &dparam, const string &sparam);
|
||||
|
||||
void ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
|
||||
|
||||
void SetSizeLimit(const CSize &limit) { m_size_limit = limit; }
|
||||
CSize GetSizeLimit() { return m_size_limit; }
|
||||
};
|
||||
|
||||
void MaximizableAppDialog::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
||||
{
|
||||
if(id == CHARTEVENT_CHART_CHANGE)
|
||||
{
|
||||
if(OnChartChange(lparam, dparam, sparam)) return;
|
||||
}
|
||||
CAppDialog::ChartEvent(id, lparam, dparam, sparam);
|
||||
}
|
||||
|
||||
EVENT_MAP_BEGIN(MaximizableAppDialog)
|
||||
ON_EVENT(ON_CLICK, m_button_truemax, OnClickButtonTrueMax)
|
||||
ON_EVENT(ON_CLICK, m_button_size, OnClickButtonSizeFixMe)
|
||||
ON_EVENT(ON_DRAG_START, m_button_size, OnDialogSizeStart)
|
||||
ON_EVENT_PTR(ON_DRAG_PROCESS, m_drag_object, OnDialogDragProcess)
|
||||
ON_EVENT_PTR(ON_DRAG_END, m_drag_object, OnDialogDragEnd)
|
||||
EVENT_MAP_END(CAppDialog)
|
||||
|
||||
bool MaximizableAppDialog::Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2)
|
||||
{
|
||||
// 1 * CONTROLS_BORDER_WIDTH - stays here, because the standard control library minimizes window
|
||||
// when it's height is 1 pixel smaller than the entire chart height
|
||||
m_max_rect.SetBound(0,
|
||||
0,
|
||||
(int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS) - 0 * CONTROLS_BORDER_WIDTH,
|
||||
(int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS) - 1 * CONTROLS_BORDER_WIDTH);
|
||||
if(!CAppDialog::Create(chart, name, subwin, x1, y1, x2, y2)) return false;
|
||||
if(!CreateButtonSize()) return false;
|
||||
m_size_limit.cx = x2 - x1;
|
||||
m_size_limit.cy = y2 - y1;
|
||||
if(m_size_limit.cx >= m_max_rect.Width() || m_size_limit.cy >= m_max_rect.Height())
|
||||
{
|
||||
m_size_limit.cx = m_min_rect.Width() * 3;
|
||||
m_size_limit.cy = m_min_rect.Height() * 7;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaximizableAppDialog::CreateButtonMinMax(void) override
|
||||
{
|
||||
if(!CAppDialog::CreateButtonMinMax()) return false;
|
||||
|
||||
// add maximization button
|
||||
int off = (m_panel_flag) ? 0 : 2 * CONTROLS_BORDER_WIDTH;
|
||||
|
||||
int x1 = Width() - off - 3 * (CONTROLS_BUTTON_SIZE + CONTROLS_DIALOG_BUTTON_OFF);
|
||||
int y1 = off + CONTROLS_DIALOG_BUTTON_OFF;
|
||||
int x2 = x1 + CONTROLS_BUTTON_SIZE;
|
||||
int y2 = y1 + CONTROLS_BUTTON_SIZE;
|
||||
|
||||
if(!m_button_truemax.Create(m_chart_id, m_name + "TrueMax", m_subwin, x1, y1, x2, y2)) return false;
|
||||
if(!m_button_truemax.BmpNames("::res\\Expand2.bmp", "::res\\Restore.bmp")) return false;
|
||||
if(!CWndContainer::Add(m_button_truemax)) return false;
|
||||
|
||||
m_button_truemax.Locking(true);
|
||||
m_button_truemax.Alignment(WND_ALIGN_RIGHT, 0, 0, off + 2 * CONTROLS_BUTTON_SIZE + 2 * CONTROLS_DIALOG_BUTTON_OFF, 0);
|
||||
|
||||
CaptionAlignment(WND_ALIGN_WIDTH, off, 0, off + 3 * (CONTROLS_BUTTON_SIZE + CONTROLS_DIALOG_BUTTON_OFF), 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaximizableAppDialog::CreateButtonSize(void)
|
||||
{
|
||||
int off = (m_panel_flag) ? 0 : 2 * CONTROLS_BORDER_WIDTH;
|
||||
|
||||
int x1 = Width() - CONTROLS_BUTTON_SIZE + 1;
|
||||
int y1 = Height() - CONTROLS_BUTTON_SIZE + 1;
|
||||
int x2 = x1 + CONTROLS_BUTTON_SIZE - 1;
|
||||
int y2 = y1 + CONTROLS_BUTTON_SIZE - 1;
|
||||
|
||||
if(!m_button_size.Create(m_chart_id, m_name + "Size", m_subwin, x1, y1, x2, y2)) return false;
|
||||
if(!m_button_size.BmpNames("::res\\size6.bmp", "::res\\size10.bmp")) return false;
|
||||
if(!CWndContainer::Add(m_button_size)) return false;
|
||||
m_button_size.Alignment(WND_ALIGN_RIGHT|WND_ALIGN_BOTTOM, 0, 0, 0, 0);
|
||||
m_button_size.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MaximizableAppDialog::OnClickButtonTrueMax(void)
|
||||
{
|
||||
if(m_button_truemax.Pressed())
|
||||
Expand();
|
||||
else
|
||||
Restore();
|
||||
|
||||
SubwinOff();
|
||||
}
|
||||
|
||||
// This is a hack. It's required because in minimized state sizing button somehow "overlaps"
|
||||
// the close button and intercepts clicks on it (which prevents exit from minimized app).
|
||||
// This happens despite the fact that the sizing button is hidden, disabled and assigned
|
||||
// with minimal Z-order (checked out, then removed).
|
||||
// Looks like a bug in the standard control library, specifically:
|
||||
// In CWnd::OnMouseEvent there must be a line:
|
||||
//
|
||||
// if(!IS_ENABLED || !IS_VISIBLE) return false;
|
||||
//
|
||||
// but it's not there, so invisible, disabled and even background objects are processed
|
||||
// in the same manner as all other objects. Specifically in CWndContainer::OnMouseEvent
|
||||
// there is a reverse loop through all objects (it does _not_ respect Z-order anyhow).
|
||||
|
||||
void MaximizableAppDialog::OnClickButtonSizeFixMe(void)
|
||||
{
|
||||
if(m_minimized)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void MaximizableAppDialog::Expand(void)
|
||||
{
|
||||
m_maximized = true;
|
||||
m_minimized = false;
|
||||
m_button_minmax.Pressed(false);
|
||||
Rebound(m_max_rect);
|
||||
m_button_size.Hide();
|
||||
m_button_size.StateFlagsReset(WND_STATE_FLAG_ENABLE);
|
||||
m_button_size.PropFlagsReset(WND_PROP_FLAG_CAN_DRAG);
|
||||
if(!m_panel_flag)
|
||||
{
|
||||
m_caption.PropFlagsReset(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
|
||||
ClientAreaVisible(true);
|
||||
SelfAdjustment();
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Restore dialog window |
|
||||
//+------------------------------------------------------------------+
|
||||
void MaximizableAppDialog::Restore(void)
|
||||
{
|
||||
m_maximized = false;
|
||||
m_minimized = false;
|
||||
m_button_minmax.Pressed(false);
|
||||
m_button_size.Show();
|
||||
m_button_size.StateFlagsSet(WND_STATE_FLAG_ENABLE);
|
||||
m_button_size.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
CAppDialog::Maximize();
|
||||
if(!m_panel_flag)
|
||||
{
|
||||
m_caption.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
SelfAdjustment();
|
||||
}
|
||||
|
||||
void MaximizableAppDialog::Minimize()
|
||||
{
|
||||
CAppDialog::Minimize();
|
||||
m_button_size.Hide();
|
||||
m_button_size.StateFlagsReset(WND_STATE_FLAG_ENABLE);
|
||||
m_button_size.PropFlagsReset(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
|
||||
bool MaximizableAppDialog::OnChartChange(const long &lparam, const double &dparam, const string &sparam)
|
||||
{
|
||||
m_max_rect.SetBound(0, 0,
|
||||
(int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS) - 0 * CONTROLS_BORDER_WIDTH,
|
||||
(int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS) - 1 * CONTROLS_BORDER_WIDTH);
|
||||
if(m_maximized)
|
||||
{
|
||||
if(m_rect.Width() != m_max_rect.Width() || m_rect.Height() != m_max_rect.Height())
|
||||
{
|
||||
Rebound(m_max_rect);
|
||||
SelfAdjustment();
|
||||
m_chart.Redraw();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MaximizableAppDialog::OnClickButtonMinMax(void)
|
||||
{
|
||||
CAppDialog::OnClickButtonMinMax();
|
||||
m_button_truemax.Pressed(false);
|
||||
m_maximized = false;
|
||||
if(m_minimized)
|
||||
{
|
||||
m_button_size.Hide();
|
||||
m_button_size.StateFlagsReset(WND_STATE_FLAG_ENABLE);
|
||||
m_button_size.PropFlagsReset(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_button_size.Show();
|
||||
m_button_size.StateFlagsSet(WND_STATE_FLAG_ENABLE);
|
||||
m_button_size.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
if(!m_panel_flag)
|
||||
{
|
||||
m_caption.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
}
|
||||
SelfAdjustment(m_minimized);
|
||||
}
|
||||
|
||||
bool MaximizableAppDialog::OnDialogSizeStart(void)
|
||||
{
|
||||
if(m_drag_object == NULL)
|
||||
{
|
||||
m_drag_object = new CDragWnd;
|
||||
if(m_drag_object == NULL) return false;
|
||||
}
|
||||
int x1 = m_button_size.Left() - CONTROLS_DRAG_SPACING;
|
||||
int y1 = m_button_size.Top() - CONTROLS_DRAG_SPACING;
|
||||
int x2 = m_button_size.Right() + CONTROLS_DRAG_SPACING;
|
||||
int y2 = m_button_size.Bottom() + CONTROLS_DRAG_SPACING;
|
||||
|
||||
m_drag_object.Create(m_chart_id, "", m_subwin, x1, y1, x2, y2);
|
||||
m_drag_object.PropFlagsSet(WND_PROP_FLAG_CAN_DRAG);
|
||||
|
||||
CChart chart;
|
||||
chart.Attach(m_chart_id);
|
||||
m_drag_object.Limits(-CONTROLS_DRAG_SPACING, -CONTROLS_DRAG_SPACING,
|
||||
chart.WidthInPixels() + CONTROLS_DRAG_SPACING,
|
||||
chart.HeightInPixels(m_subwin) + CONTROLS_DRAG_SPACING);
|
||||
chart.Detach();
|
||||
|
||||
m_drag_object.MouseX(m_button_size.MouseX());
|
||||
m_drag_object.MouseY(m_button_size.MouseY());
|
||||
m_drag_object.MouseFlags(m_button_size.MouseFlags());
|
||||
|
||||
m_sizing = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaximizableAppDialog::OnDialogDragStart(void)
|
||||
{
|
||||
if(m_maximized) return false;
|
||||
|
||||
return CAppDialog::OnDialogDragStart();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Continue dragging the dialog box |
|
||||
//+------------------------------------------------------------------+
|
||||
bool MaximizableAppDialog::OnDialogDragProcess(void)
|
||||
{
|
||||
if(!m_sizing) return CDialog::OnDialogDragProcess();
|
||||
|
||||
if(m_drag_object == NULL) return false;
|
||||
|
||||
int x = m_drag_object.Right() - Right() - CONTROLS_DRAG_SPACING;
|
||||
int y = m_drag_object.Bottom() - Bottom() - CONTROLS_DRAG_SPACING;
|
||||
|
||||
// resize dialog
|
||||
CRect r = Rect();
|
||||
r.right += x;
|
||||
r.bottom += y;
|
||||
|
||||
if(r.Width() < m_size_limit.cx) r.right = r.left + m_size_limit.cx;
|
||||
if(r.Height() < m_size_limit.cy) r.bottom = r.top + m_size_limit.cy;
|
||||
|
||||
Rebound(r);
|
||||
|
||||
SelfAdjustment();
|
||||
|
||||
return true;
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| End dragging the dialog box |
|
||||
//+------------------------------------------------------------------+
|
||||
bool MaximizableAppDialog::OnDialogDragEnd(void)
|
||||
{
|
||||
if(!m_sizing) return CDialog::OnDialogDragEnd();
|
||||
|
||||
if(m_drag_object != NULL)
|
||||
{
|
||||
m_button_size.MouseFlags(m_drag_object.MouseFlags());
|
||||
delete m_drag_object;
|
||||
m_drag_object = NULL;
|
||||
}
|
||||
|
||||
m_norm_rect.SetBound(m_rect);
|
||||
m_sizing = false;
|
||||
|
||||
SelfAdjustment();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SpinEditResizable.mqh |
|
||||
//| Copyright (c) 2019, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#include <Controls/SpinEdit.mqh>
|
||||
|
||||
class SpinEditResizable: public CSpinEdit
|
||||
{
|
||||
public:
|
||||
virtual bool OnResize(void) override
|
||||
{
|
||||
m_edit.Width(Width());
|
||||
m_edit.Height(Height());
|
||||
|
||||
int x1 = Width() - (CONTROLS_BUTTON_SIZE + CONTROLS_SPIN_BUTTON_X_OFF);
|
||||
int y1 = (Height() - 2 * CONTROLS_SPIN_BUTTON_SIZE) / 2;
|
||||
m_inc.Move(Left() + x1, Top() + y1);
|
||||
|
||||
x1 = Width() - (CONTROLS_BUTTON_SIZE + CONTROLS_SPIN_BUTTON_X_OFF);
|
||||
y1 = (Height() - 2 * CONTROLS_SPIN_BUTTON_SIZE) / 2 + CONTROLS_SPIN_BUTTON_SIZE;
|
||||
m_dec.Move(Left() + x1, Top() + y1);
|
||||
|
||||
return CWndContainer::OnResize();
|
||||
}
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Reference in New Issue
Block a user