338 lines
11 KiB
Plaintext
338 lines
11 KiB
Plaintext
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| 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;
|
||
|
|
}
|