// THIS FILE IS GENERATED BY MQL5 PACKER UTILITY
// TO PASS THE CODEBASE VALIDATION PROCESS
// WHICH DOES NOT SUPPORT MORE THAN 32 SOURCE FILES IN ONE PROGRAM
// TO GET ACTUAL SOURCE CODES PLEASE EXTRACT THEM
// FROM THE ATTACHED ARCHIVE ChartBrowser.mq5.zip
//+------------------------------------------------------------------+
//| ChartBrowser.mq5 |
//| Copyright (c) 2021, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//| https://www.mql5.com/en/code/33770/ |
//| |
//| https://www.mql5.com/en/articles/7734/ |
//| https://www.mql5.com/en/articles/7739/ |
//| https://www.mql5.com/ru/articles/7795/ |
//+------------------------------------------------------------------+
#property copyright "Copyright (c) 2021, Marketeer"
#property link "https://www.mql5.com/en/users/marketeer"
#property version "1.0"
#property description "Lists all open charts, indicators, experts, and scripts in sorted order.\n"
#property description "Can be used for fast switching."
const string DIALOG_TITLE = "ChartBrowser";
//#include "ChartBrowser.mqh"
//+------------------------------------------------------------------+
//| ChartBrowser.mqh |
//| Copyright (c) 2021, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//| https://www.mql5.com/en/code/33770/ |
//| |
//| https://www.mql5.com/en/articles/7734/ |
//| https://www.mql5.com/en/articles/7739/ |
//| https://www.mql5.com/ru/articles/7795/ |
//+------------------------------------------------------------------+
//#include <ControlsPlus/Dialog.mqh>
//+------------------------------------------------------------------+
//| Dialog.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndContainer.mqh"
//+------------------------------------------------------------------+
//| WndContainer.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "Wnd.mqh"
//+------------------------------------------------------------------+
//| Wnd.mqh |
//| Copyright 2009-2018, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include <Controls/Rect.mqh>
//+------------------------------------------------------------------+
//| Rect.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Structure CPoint |
//| Usage: point of chart in Cartesian coordinates |
//+------------------------------------------------------------------+
struct CPoint
{
int x; // horizontal coordinate
int y; // vertical coordinate
};
//+------------------------------------------------------------------+
//| Structure CSize |
//| Usage: size of area of chart in Cartesian coordinates |
//+------------------------------------------------------------------+
struct CSize
{
int cx; // horizontal size
int cy; // vertical size
};
//+------------------------------------------------------------------+
//| Structure CRect |
//| Usage: area of chart in Cartesian coordinates |
//+------------------------------------------------------------------+
struct CRect
{
int left; // left coordinate
int top; // top coordinate
int right; // right coordinate
int bottom; // bottom coordinate
//--- methods
CPoint LeftTop(void) const;
void LeftTop(const int x,const int y);
void LeftTop(const CPoint& point);
CPoint RightBottom(void) const;
void RightBottom(const int x,const int y);
void RightBottom(const CPoint& point);
CPoint CenterPoint(void) const;
int Width(void) const { return(right-left); }
void Width(const int w) { right=left+w; }
int Height(void) const { return(bottom-top); }
void Height(const int h) { bottom=top+h; }
CSize Size(void) const;
void Size(const int cx,const int cy);
void Size(const CSize& size);
void SetBound(const int l,const int t,const int r,const int b);
void SetBound(const CRect& rect);
void SetBound(const CPoint& point,const CSize& size);
void SetBound(const CPoint& left_top,const CPoint& right_bottom);
void Move(const int x,const int y);
void Move(const CPoint& point);
void Shift(const int dx,const int dy);
void Shift(const CPoint& point);
void Shift(const CSize& size);
bool Contains(const int x,const int y) const;
bool Contains(const CPoint& point) const;
void Normalize(void);
};
//+------------------------------------------------------------------+
//| Get parameters of area |
//+------------------------------------------------------------------+
CPoint CRect::LeftTop(void) const
{
CPoint point;
//--- action
point.x=left;
point.y=top;
//--- result
return(point);
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::LeftTop(const int x,const int y)
{
left=x;
top =y;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::LeftTop(const CPoint& point)
{
left=point.x;
top =point.y;
}
//+------------------------------------------------------------------+
//| Get parameters of area |
//+------------------------------------------------------------------+
CPoint CRect::RightBottom(void) const
{
CPoint point;
//--- action
point.x=right;
point.y=bottom;
//--- result
return(point);
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::RightBottom(const int x,const int y)
{
right =x;
bottom=y;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::RightBottom(const CPoint& point)
{
right =point.x;
bottom=point.y;
}
//+------------------------------------------------------------------+
//| Get parameters of area |
//+------------------------------------------------------------------+
CPoint CRect::CenterPoint(void) const
{
CPoint point;
//--- action
point.x=left+Width()/2;
point.y=top+Height()/2;
//--- result
return(point);
}
//+------------------------------------------------------------------+
//| Get parameters of area |
//+------------------------------------------------------------------+
CSize CRect::Size(void) const
{
CSize size;
//--- action
size.cx=right-left;
size.cy=bottom-top;
//--- result
return(size);
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::Size(const int cx,const int cy)
{
right =left+cx;
bottom=top+cy;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::Size(const CSize& size)
{
right =left+size.cx;
bottom=top+size.cy;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::SetBound(const int l,const int t,const int r,const int b)
{
left =l;
top =t;
right =r;
bottom=b;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::SetBound(const CRect& rect)
{
left =rect.left;
top =rect.top;
right =rect.right;
bottom=rect.bottom;
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::SetBound(const CPoint& point,const CSize& size)
{
LeftTop(point);
Size(size);
}
//+------------------------------------------------------------------+
//| Set parameters of area |
//+------------------------------------------------------------------+
void CRect::SetBound(const CPoint& left_top,const CPoint& right_bottom)
{
LeftTop(left_top);
RightBottom(right_bottom);
}
//+------------------------------------------------------------------+
//| Absolute movement of area |
//+------------------------------------------------------------------+
void CRect::Move(const int x,const int y)
{
right +=x-left;
bottom+=y-top;
left =x;
top =y;
}
//+------------------------------------------------------------------+
//| Absolute movement of area |
//+------------------------------------------------------------------+
void CRect::Move(const CPoint& point)
{
right +=point.x-left;
bottom+=point.y-top;
left =point.x;
top =point.y;
}
//+------------------------------------------------------------------+
//| Relative movement of area |
//+------------------------------------------------------------------+
void CRect::Shift(const int dx,const int dy)
{
left +=dx;
top +=dy;
right +=dx;
bottom+=dy;
}
//+------------------------------------------------------------------+
//| Relative movement of area |
//+------------------------------------------------------------------+
void CRect::Shift(const CPoint& point)
{
left +=point.x;
top +=point.y;
right +=point.x;
bottom+=point.y;
}
//+------------------------------------------------------------------+
//| Relative movement of area |
//+------------------------------------------------------------------+
void CRect::Shift(const CSize& size)
{
left +=size.cx;
top +=size.cy;
right +=size.cx;
bottom+=size.cy;
}
//+------------------------------------------------------------------+
//| Check if a point is within the area |
//+------------------------------------------------------------------+
bool CRect::Contains(const int x,const int y) const
{
//--- check and return the result
return(x>=left && x<=right && y>=top && y<=bottom);
}
//+------------------------------------------------------------------+
//| Check if a point is within the area |
//+------------------------------------------------------------------+
bool CRect::Contains(const CPoint& point) const
{
//--- check and return the result
return(point.x>=left && point.x<=right && point.y>=top && point.y<=bottom);
}
//+------------------------------------------------------------------+
//| Standardizes the height and width |
//+------------------------------------------------------------------+
void CRect::Normalize(void)
{
if(left>right)
{
int tmp1=left;
left=right;
right=tmp1;
}
if(top>bottom)
{
int tmp2=top;
top=bottom;
bottom=tmp2;
}
}
//+------------------------------------------------------------------+
//#include "Defines.mqh"
//+------------------------------------------------------------------+
//| Defines.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Enumerations |
//+------------------------------------------------------------------+
//--- properties flags
enum ENUM_WND_PROP_FLAGS
{
WND_PROP_FLAG_CAN_DBL_CLICK = 1, // can be double clicked by mouse
WND_PROP_FLAG_CAN_DRAG = 2, // can be dragged by mouse
WND_PROP_FLAG_CLICKS_BY_PRESS= 4, // generates the "click" event series on pressing left mouse button
WND_PROP_FLAG_CAN_LOCK = 8, // control with fixed state (usually it is a button)
WND_PROP_FLAG_READ_ONLY =16 // read only (usually it is a edit)
};
//--- state flags
enum ENUM_WND_STATE_FLAGS
{
WND_STATE_FLAG_ENABLE = 1, // "object is enabled" flag
WND_STATE_FLAG_VISIBLE = 2, // "object is visible" flag
WND_STATE_FLAG_ACTIVE = 4, // "object is active" flag
};
//--- mouse flags
enum ENUM_MOUSE_FLAGS
{
MOUSE_INVALID_FLAGS =-1, // no buttons state
MOUSE_EMPTY = 0, // buttons are not pressed
MOUSE_LEFT = 1, // left button pressed
MOUSE_RIGHT = 2 // right button pressed
};
//--- alignment flags
enum ENUM_WND_ALIGN_FLAGS
{
WND_ALIGN_NONE = 0, // no alignment
WND_ALIGN_LEFT = 1, // align by left border
WND_ALIGN_TOP = 2, // align by top border
WND_ALIGN_RIGHT = 4, // align by right border
WND_ALIGN_BOTTOM = 8, // align by bottom border
WND_ALIGN_WIDTH = WND_ALIGN_LEFT|WND_ALIGN_RIGHT, // justify
WND_ALIGN_HEIGHT = WND_ALIGN_TOP|WND_ALIGN_BOTTOM, // align by top and bottom border
WND_ALIGN_CLIENT = WND_ALIGN_WIDTH|WND_ALIGN_HEIGHT // align by all sides
};
//+------------------------------------------------------------------+
//| Drawing styles and colors |
//+------------------------------------------------------------------+
//--- common
#define CONTROLS_FONT_NAME "Trebuchet MS"
#define CONTROLS_FONT_SIZE (10)
//--- Text
#define CONTROLS_COLOR_TEXT C'0x3B,0x29,0x28'
#define CONTROLS_COLOR_TEXT_SEL White
#define CONTROLS_COLOR_BG White
#define CONTROLS_COLOR_BG_SEL C'0x33,0x99,0xFF'
//--- Button
#define CONTROLS_BUTTON_COLOR C'0x3B,0x29,0x28'
#define CONTROLS_BUTTON_COLOR_BG C'0xDD,0xE2,0xEB'
#define CONTROLS_BUTTON_COLOR_BORDER C'0xB2,0xC3,0xCF'
//--- Label
#define CONTROLS_LABEL_COLOR C'0x3B,0x29,0x28'
//--- Edit
#define CONTROLS_EDIT_COLOR C'0x3B,0x29,0x28'
#define CONTROLS_EDIT_COLOR_BG White
#define CONTROLS_EDIT_COLOR_BORDER C'0xB2,0xC3,0xCF'
//--- Scrolls
#define CONTROLS_SCROLL_COLOR_BG C'0xEC,0xEC,0xEC'
#define CONTROLS_SCROLL_COLOR_BORDER C'0xD3,0xD3,0xD3'
//--- Client
#define CONTROLS_CLIENT_COLOR_BG C'0xDE,0xDE,0xDE'
#define CONTROLS_CLIENT_COLOR_BORDER C'0x2C,0x2C,0x2C'
//--- ListView
#define CONTROLS_LISTITEM_COLOR_TEXT C'0x3B,0x29,0x28'
#define CONTROLS_LISTITEM_COLOR_TEXT_SEL White
#define CONTROLS_LISTITEM_COLOR_BG White
#define CONTROLS_LISTITEM_COLOR_BG_SEL C'0x33,0x99,0xFF'
#define CONTROLS_LIST_COLOR_BG White
#define CONTROLS_LIST_COLOR_BORDER C'0xB2,0xC3,0xCF'
//--- CheckGroup
#define CONTROLS_CHECKGROUP_COLOR_BG C'0xF7,0xF7,0xF7'
#define CONTROLS_CHECKGROUP_COLOR_BORDER C'0xB2,0xC3,0xCF'
//--- RadioGroup
#define CONTROLS_RADIOGROUP_COLOR_BG C'0xF7,0xF7,0xF7'
#define CONTROLS_RADIOGROUP_COLOR_BORDER C'0xB2,0xC3,0xCF'
//--- Dialog
#define CONTROLS_DIALOG_COLOR_BORDER_LIGHT White
#define CONTROLS_DIALOG_COLOR_BORDER_DARK C'0xB6,0xB6,0xB6'
#define CONTROLS_DIALOG_COLOR_BG C'0xF0,0xF0,0xF0'
#define CONTROLS_DIALOG_COLOR_CAPTION_TEXT C'0x28,0x29,0x3B'
#define CONTROLS_DIALOG_COLOR_CLIENT_BG C'0xF7,0xF7,0xF7'
#define CONTROLS_DIALOG_COLOR_CLIENT_BORDER C'0xC8,0xC8,0xC8'
//+------------------------------------------------------------------+
//| Constants for the controls |
//+------------------------------------------------------------------+
//--- common
#define CONTROLS_INVALID_ID (-1) // invalid ID
#define CONTROLS_INVALID_INDEX (-1) // invalid index of array
#define CONTROLS_SELF_MESSAGE (-1) // message to oneself
#define CONTROLS_MAXIMUM_ID (10000) // maximum number of IDs in application
#define CONTROLS_BORDER_WIDTH (1) // border width
#define CONTROLS_SUBWINDOW_GAP (3) // gap between sub-windows along the Y axis
#define CONTROLS_DRAG_SPACING (50) // sensitivity threshold for dragging
#define CONTROLS_DBL_CLICK_TIME (100) // double click interval
//--- BmpButton
#define CONTROLS_BUTTON_SIZE (16) // default size of button (16 x 16)
//--- Scrolls
#define CONTROLS_SCROLL_SIZE (18) // default lateral size of scrollbar
#define CONTROLS_SCROLL_THUMB_SIZE (22) // default length of scroll box
//--- RadioButton
#define CONTROLS_RADIO_BUTTON_X_OFF (3) // X offset of radio button (for RadioButton)
#define CONTROLS_RADIO_BUTTON_Y_OFF (3) // Y offset of radio button (for RadioButton)
#define CONTROLS_RADIO_LABEL_X_OFF (20) // X offset of label (for RadioButton)
#define CONTROLS_RADIO_LABEL_Y_OFF (0) // Y offset of label (for RadioButton)
//--- CheckBox
#define CONTROLS_CHECK_BUTTON_X_OFF (3) // X offset of check button (for CheckBox)
#define CONTROLS_CHECK_BUTTON_Y_OFF (3) // Y offset of check button (for CheckBox)
#define CONTROLS_CHECK_LABEL_X_OFF (20) // X offset of label (for CheckBox)
#define CONTROLS_CHECK_LABEL_Y_OFF (0) // Y offset of label (for CheckBox)
//--- Spin
#define CONTROLS_SPIN_BUTTON_X_OFF (2) // X offset of button from right (for SpinEdit)
#define CONTROLS_SPIN_MIN_HEIGHT (18) // minimal height (for SpinEdit)
#define CONTROLS_SPIN_BUTTON_SIZE (8) // default size of button (16 x 8) (for SpinEdit)
//--- Combo
#define CONTROLS_COMBO_BUTTON_X_OFF (2) // X offset of button from right (for ComboBox)
#define CONTROLS_COMBO_MIN_HEIGHT (18) // minimal height (for ComboBox)
#define CONTROLS_COMBO_ITEM_HEIGHT (18) // height of combo box item (for ComboBox)
#define CONTROLS_COMBO_ITEMS_VIEW (8) // number of items in combo box (for ComboBox)
//--- ListView
#define CONTROLS_LIST_ITEM_HEIGHT (18) // height of list item (for ListView)
//--- Dialog
#define CONTROLS_DIALOG_CAPTION_HEIGHT (22) // height of dialog header
#define CONTROLS_DIALOG_BUTTON_OFF (3) // offset of dialog buttons
#define CONTROLS_DIALOG_CLIENT_OFF (2) // offset of dialog client area
#define CONTROLS_DIALOG_MINIMIZE_LEFT (10) // left coordinate of dialog in minimized state
#define CONTROLS_DIALOG_MINIMIZE_TOP (10) // top coordinate of dialog in minimized state
#define CONTROLS_DIALOG_MINIMIZE_WIDTH (100) // width of dialog in minimized state
#define CONTROLS_DIALOG_MINIMIZE_HEIGHT (4*CONTROLS_BORDER_WIDTH+CONTROLS_DIALOG_CAPTION_HEIGHT) // height of dialog in minimized state
//+------------------------------------------------------------------+
//| Macro |
//+------------------------------------------------------------------+
//--- check properties
#define IS_CAN_DBL_CLICK ((m_prop_flags&WND_PROP_FLAG_CAN_DBL_CLICK)!=0)
#define IS_CAN_DRAG ((m_prop_flags&WND_PROP_FLAG_CAN_DRAG)!=0)
#define IS_CLICKS_BY_PRESS ((m_prop_flags&WND_PROP_FLAG_CLICKS_BY_PRESS)!=0)
#define IS_CAN_LOCK ((m_prop_flags&WND_PROP_FLAG_CAN_LOCK)!=0)
#define IS_READ_ONLY ((m_prop_flags&WND_PROP_FLAG_READ_ONLY)!=0)
//--- check state
#define IS_ENABLED ((m_state_flags&WND_STATE_FLAG_ENABLE)!=0)
#define IS_VISIBLE ((m_state_flags&WND_STATE_FLAG_VISIBLE)!=0)
#define IS_ACTIVE ((m_state_flags&WND_STATE_FLAG_ACTIVE)!=0)
//+------------------------------------------------------------------+
//| Macro of event handling map |
//+------------------------------------------------------------------+
#define INTERNAL_EVENT (-1)
//--- beginning of map
#define EVENT_MAP_BEGIN(class_name) bool class_name::OnEvent(const int id,const long& lparam,const double& dparam,const string& sparam) {
//--- end of map
#define EVENT_MAP_END(parent_class_name) return(parent_class_name::OnEvent(id,lparam,dparam,sparam)); }
//--- event handling by numeric ID
#define ON_EVENT(event,control,handler) if(id==(event+CHARTEVENT_CUSTOM) && lparam==control.Id()) { handler(); return(true); }
//--- event handling by numeric ID by pointer of control
#define ON_EVENT_PTR(event,control,handler) if(control!=NULL && id==(event+CHARTEVENT_CUSTOM) && lparam==control.Id()) { handler(); return(true); }
//--- event handling without ID analysis
#define ON_NO_ID_EVENT(event,handler) if(id==(event+CHARTEVENT_CUSTOM)) { return(handler()); }
//--- event handling by row ID
#define ON_NAMED_EVENT(event,control,handler) if(id==(event+CHARTEVENT_CUSTOM) && sparam==control.Name()) { handler(); return(true); }
//--- handling of indexed event
#define ON_INDEXED_EVENT(event,controls,handler) { int total=ArraySize(controls); for(int i=0;i<total;i++) if(id==(event+CHARTEVENT_CUSTOM) && lparam==controls[i].Id()) return(handler(i)); }
//--- handling of external event
#define ON_EXTERNAL_EVENT(event,handler) if(id==(event+CHARTEVENT_CUSTOM)) { handler(lparam,dparam,sparam); return(true); }
//+------------------------------------------------------------------+
//| Events |
//+------------------------------------------------------------------+
#define ON_CLICK (0) // clicking on control event
#define ON_DBL_CLICK (1) // double clicking on control event
#define ON_SHOW (2) // showing control event
#define ON_HIDE (3) // hiding control event
#define ON_CHANGE (4) // changing control event
#define ON_START_EDIT (5) // start of editing event
#define ON_END_EDIT (6) // end of editing event
#define ON_SCROLL_INC (7) // increment of scrollbar event
#define ON_SCROLL_DEC (8) // decrement of scrollbar event
#define ON_MOUSE_FOCUS_SET (9) // the "mouse cursor entered the control" event
#define ON_MOUSE_FOCUS_KILL (10) // the "mouse cursor exited the control" event
#define ON_DRAG_START (11) // the "control dragging start" event
#define ON_DRAG_PROCESS (12) // the "control is being dragged" event
#define ON_DRAG_END (13) // the "control dragging end" event
#define ON_BRING_TO_TOP (14) // the "mouse events priority increase" event
#define ON_APP_CLOSE (100) // "closing the application" event
//+------------------------------------------------------------------+
//#include <Object.mqh>
//+------------------------------------------------------------------+
//| Object.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "StdLibErr.mqh"
//+------------------------------------------------------------------+
//| StdLibErr.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#define ERR_USER_INVALID_HANDLE 1
#define ERR_USER_INVALID_BUFF_NUM 2
#define ERR_USER_ITEM_NOT_FOUND 3
#define ERR_USER_ARRAY_IS_EMPTY 1000
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class CObject. |
//| Purpose: Base class for storing elements. |
//+------------------------------------------------------------------+
class CObject
{
private:
CObject *m_prev; // previous item of list
CObject *m_next; // next item of list
public:
CObject(void): m_prev(NULL),m_next(NULL) { }
~CObject(void) { }
//--- methods to access protected data
CObject *Prev(void) const { return(m_prev); }
void Prev(CObject *node) { m_prev=node; }
CObject *Next(void) const { return(m_next); }
void Next(CObject *node) { m_next=node; }
//--- methods for working with files
virtual bool Save(const int file_handle) { return(true); }
virtual bool Load(const int file_handle) { return(true); }
//--- method of identifying the object
virtual int Type(void) const { return(0); }
//--- method of comparing the objects
virtual int Compare(const CObject *node,const int mode=0) const { return(0); }
};
//+------------------------------------------------------------------+
class CDragWnd;
#define RTTI _rtti = StringFormat("%s %d", typename(this), &this);
struct CRectCreator: public CRect
{
CRectCreator(const int x1, const int y1, const int x2, const int y2)
{
left = x1;
top = y1;
right = x2;
bottom = y2;
}
};
//+------------------------------------------------------------------+
//| Class CWnd |
//| Usage: base class of the control object that creates |
//| control panels and indicator panels |
//+------------------------------------------------------------------+
class CWnd : public CObject
{
public:
string _rtti;
protected:
//--- parameters of creation
long m_chart_id; // chart ID
int m_subwin; // chart subwindow
string m_name; // object name
//--- geometry
CRect m_rect; // chart area
//--- ID
long m_id; // object ID
//--- state flags
int m_state_flags;
//--- properties flags
int m_prop_flags;
//--- alignment
int m_align_flags; // alignment flags
int m_align_left; // fixed offset from left border
int m_align_top; // fixed offset from top border
int m_align_right; // fixed offset from right border
int m_align_bottom; // fixed offset from bottom border
//--- the last saved state of mouse
int m_mouse_x; // X coordinate
int m_mouse_y; // Y coordinate
int m_mouse_flags; // state of buttons
uint m_last_click; // last click time
//--- drag object
CDragWnd *m_drag_object; // pointer to the dragged object
public:
CWnd(void);
~CWnd(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- release memory
virtual void Destroy(const int reason=0);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
virtual bool OnMouseEvent(const int x,const int y,const int flags);
//--- naming (read only)
string Name(void) const { return(m_name); }
//--- access the contents of container
int ControlsTotal(void) const { return(0); }
CWnd* Control(const int ind) const { return(NULL); }
virtual CWnd* ControlFind(const long id);
//--- geometry
const CRect Rect(void) const { return(m_rect); }
int Left(void) const { return(m_rect.left); }
virtual void Left(const int x) { m_rect.left=x; }
int Top(void) const { return(m_rect.top); }
virtual void Top(const int y) { m_rect.top=y; }
int Right(void) const { return(m_rect.right); }
virtual void Right(const int x) { m_rect.right=x; }
int Bottom(void) const { return(m_rect.bottom); }
virtual void Bottom(const int y) { m_rect.bottom=y; }
int Width(void) const { return(m_rect.Width()); }
virtual bool Width(const int w);
int Height(void) const { return(m_rect.Height()); }
virtual bool Height(const int h);
CSize Size(void) const { return(m_rect.Size()); }
virtual bool Size(const int w,const int h);
virtual bool Size(const CSize &size);
virtual bool Move(const int x,const int y);
virtual bool Move(const CPoint &point);
virtual bool Shift(const int dx,const int dy);
bool Contains(const int x,const int y) const { return(m_rect.Contains(x,y)); }
bool Contains(CWnd *control) const;
//--- alignment
void Alignment(const int flags,const int left,const int top,const int right,const int bottom);
virtual bool Align(const CRect &rect);
ENUM_WND_ALIGN_FLAGS Alignment(void) const
{
return (ENUM_WND_ALIGN_FLAGS)m_align_flags;
}
CRect Margins(void) const
{
CRectCreator rect(m_align_left, m_align_top, m_align_right, m_align_bottom);
return rect;
}
void Alignment(const int flags)
{
m_align_flags = flags;
}
void Margins(const int left, const int top, const int right, const int bottom)
{
m_align_left = left;
m_align_top = top;
m_align_right = right;
m_align_bottom = bottom;
}
void Margins(const int all)
{
m_align_left = all;
m_align_top = all;
m_align_right = all;
m_align_bottom = all;
}
//--- ID
virtual long Id(const long id);
long Id(void) const { return(m_id); }
//--- state
bool IsEnabled(void) const { return(IS_ENABLED); }
virtual bool Enable(void);
virtual bool Disable(void);
bool IsVisible(void) const { return(IS_VISIBLE); }
virtual bool Visible(const bool flag);
virtual bool Show(void);
virtual bool Hide(void);
bool IsActive(void) const { return(IS_ACTIVE); }
virtual bool Activate(void);
virtual bool Deactivate(void);
//--- state flags
int StateFlags(void) const { return(m_state_flags); }
void StateFlags(const int flags) { m_state_flags=flags; }
void StateFlagsSet(const int flags) { m_state_flags|=flags; }
void StateFlagsReset(const int flags) { m_state_flags&=~flags; }
//--- properties flags
int PropFlags(void) const { return(m_prop_flags); }
void PropFlags(const int flags) { m_prop_flags=flags; }
void PropFlagsSet(const int flags) { m_prop_flags|=flags; }
void PropFlagsReset(const int flags) { m_prop_flags&=~flags; }
//--- for mouse operations
int MouseX(void) const { return(m_mouse_x); }
void MouseX(const int value) { m_mouse_x=value; }
int MouseY(void) const { return(m_mouse_y); }
void MouseY(const int value) { m_mouse_y=value; }
int MouseFlags(void) const { return(m_mouse_flags); }
virtual void MouseFlags(const int value) { m_mouse_flags=value; }
bool MouseFocusKill(const long id=CONTROLS_INVALID_ID);
bool BringToTop(void);
protected:
//--- internal event handlers
virtual bool OnCreate(void) { return(true); }
virtual bool OnDestroy(void) { return(true); }
virtual bool OnMove(void) { return(true); }
virtual bool OnResize(void) { return(true); }
virtual bool OnEnable(void) { return(true); }
virtual bool OnDisable(void) { return(true); }
virtual bool OnShow(void) { return(true); }
virtual bool OnHide(void) { return(true); }
virtual bool OnActivate(void) { return(true); }
virtual bool OnDeactivate(void) { return(true); }
virtual bool OnClick(void);
virtual bool OnDblClick(void);
virtual bool OnChange(void) { return(true); }
//--- mouse event handlers
virtual bool OnMouseDown(void);
virtual bool OnMouseUp(void);
//--- handlers of dragging
virtual bool OnDragStart(void);
virtual bool OnDragProcess(const int x,const int y);
virtual bool OnDragEnd(void);
//--- methods for drag-object
virtual bool DragObjectCreate(void) { return(false); }
virtual bool DragObjectDestroy(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
bool CWnd::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
if((id!=CHARTEVENT_MOUSE_MOVE))
return(false);
if(!IS_VISIBLE)
return(false);
int x=(int)lparam;
int y=(int)dparam;
int flags=(int)StringToInteger(sparam);
//---
if(m_drag_object!=NULL)
return(m_drag_object.OnMouseEvent(x,y,flags));
//---
return(OnMouseEvent(x,y,flags));
}
//+------------------------------------------------------------------+
//| Common handler of mouse events |
//+------------------------------------------------------------------+
bool CWnd::OnMouseEvent(const int x,const int y,const int flags)
{
if(!IS_ENABLED || !IS_VISIBLE) return false;
if(!Contains(x,y))
{
//--- if cursor is not inside the element and this element is active - deactivate
if(IS_ACTIVE)
{
//--- reset state and coordinates
m_mouse_x =0;
m_mouse_y =0;
m_mouse_flags=MOUSE_INVALID_FLAGS;
//--- deactivate
Deactivate();
}
return(false);
}
//--- check the state of the left mouse button
if((flags&MOUSE_LEFT)!=0)
{
//--- left mouse button is pressed
if(m_mouse_flags==MOUSE_INVALID_FLAGS)
{
//--- but not in this control (i.e., cursor entered the element with mouse button pressed)
//--- activate the control, but there will be no click
if(!IS_ACTIVE)
{
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_MOUSE_FOCUS_SET,m_id,0.0,m_name);
//--- activate
return(Activate());
}
return(true);
}
if((m_mouse_flags&MOUSE_LEFT)!=0)
{
//--- mouse button has already been pressed
if(IS_CAN_DRAG)
return(OnDragProcess(x,y));
if(IS_CLICKS_BY_PRESS)
{
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CLICK,m_id,0.0,m_name);
//--- handled
return(true);
}
}
else
{
//--- mouse button has been released (pressing)
//--- save the state and coordinates
m_mouse_flags=flags;
m_mouse_x =x;
m_mouse_y =y;
//--- call the handler
return(OnMouseDown());
}
}
else
{
//--- left mouse button is released
if(m_mouse_flags==MOUSE_INVALID_FLAGS)
{
//--- cursor entered the control with mouse button released
//--- activate control and save state to the member
m_mouse_flags=flags;
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_MOUSE_FOCUS_SET,m_id,0.0,m_name);
//--- activate
return(Activate());
}
if((m_mouse_flags&MOUSE_LEFT)!=0)
{
//--- mouse button has been pressed (clicking)
//--- save the state and coordinates
m_mouse_flags=flags;
m_mouse_x =x;
m_mouse_y =y;
//--- call the handler
return(OnMouseUp());
}
}
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CWnd::CWnd(void) : m_chart_id(CONTROLS_INVALID_ID),
m_subwin(CONTROLS_INVALID_ID),
m_name(NULL),
m_id(CONTROLS_INVALID_ID),
m_state_flags(WND_STATE_FLAG_ENABLE+WND_STATE_FLAG_VISIBLE),
m_prop_flags(0),
m_align_flags(WND_ALIGN_NONE),
m_align_left(0),
m_align_top(0),
m_align_right(0),
m_align_bottom(0),
m_mouse_x(0),
m_mouse_y(0),
m_mouse_flags(MOUSE_INVALID_FLAGS),
m_last_click(0),
m_drag_object(NULL),
_rtti(typename(this))
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CWnd::~CWnd(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CWnd::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- attach to chart
m_chart_id=chart;
m_name =name;
m_subwin =subwin;
//--- set coordinates of area
Left(x1);
Top(y1);
Right(x2);
Bottom(y2);
//--- always successful
return(true);
}
//+------------------------------------------------------------------+
//| Destruction of the control |
//+------------------------------------------------------------------+
void CWnd::Destroy(const int reason)
{
//--- call virtual event handler
if(OnDestroy())
m_name="";
}
//+------------------------------------------------------------------+
//| Find control by specified ID |
//+------------------------------------------------------------------+
CWnd* CWnd::ControlFind(const long id)
{
CWnd *result=NULL;
//--- check
if(id==m_id)
result=GetPointer(this);
//--- return the result
return(result);
}
//+------------------------------------------------------------------+
//| Change width of control |
//+------------------------------------------------------------------+
bool CWnd::Width(const int w)
{
//--- change width
m_rect.Width(w);
//--- call virtual event handler
return(OnResize());
}
//+------------------------------------------------------------------+
//| Change height of control |
//+------------------------------------------------------------------+
bool CWnd::Height(const int h)
{
//--- change height
m_rect.Height(h);
//--- call virtual event handler
return(OnResize());
}
//+------------------------------------------------------------------+
//| Resize control |
//+------------------------------------------------------------------+
bool CWnd::Size(const int w,const int h)
{
//--- change size
m_rect.Size(w,h);
//--- call virtual event handler
return(OnResize());
}
//+------------------------------------------------------------------+
//| Resize control |
//+------------------------------------------------------------------+
bool CWnd::Size(const CSize &size)
{
//--- change size
m_rect.Size(size);
//--- call virtual event handler
return(OnResize());
}
//+------------------------------------------------------------------+
//| Absolute movement of the control |
//+------------------------------------------------------------------+
bool CWnd::Move(const int x,const int y)
{
//--- moving
m_rect.Move(x,y);
//--- call virtual event handler
return(OnMove());
}
//+------------------------------------------------------------------+
//| Absolute movement of the control |
//+------------------------------------------------------------------+
bool CWnd::Move(const CPoint &point)
{
//--- moving
m_rect.Move(point);
//--- call virtual event handler
return(OnMove());
}
//+------------------------------------------------------------------+
//| Relative movement of the control |
//+------------------------------------------------------------------+
bool CWnd::Shift(const int dx,const int dy)
{
//--- moving
m_rect.Shift(dx,dy);
//--- call virtual event handler
return(OnMove());
}
//+------------------------------------------------------------------+
//| Check contains |
//+------------------------------------------------------------------+
bool CWnd::Contains(CWnd *control) const
{
//--- check
if(control==NULL)
return(false);
//--- result
return(Contains(control.Left(),control.Top()) && Contains(control.Right(),control.Bottom()));
}
//+------------------------------------------------------------------+
//| Enables event handling by the control |
//+------------------------------------------------------------------+
bool CWnd::Enable(void)
{
//--- if there are now changes, then succeed
if(IS_ENABLED)
return(true);
//--- change flag
StateFlagsSet(WND_STATE_FLAG_ENABLE);
//--- call virtual event handler
return(OnEnable());
}
//+------------------------------------------------------------------+
//| Disables event handling by the control |
//+------------------------------------------------------------------+
bool CWnd::Disable(void)
{
//--- if there are now changes, then succeed
if(!IS_ENABLED)
return(true);
//--- change flag
StateFlagsReset(WND_STATE_FLAG_ENABLE);
//--- call virtual event handler
return(OnDisable());
}
//+------------------------------------------------------------------+
//| Set the "object is visible" flag for the control |
//+------------------------------------------------------------------+
bool CWnd::Visible(const bool flag)
{
//--- if there are now changes, then succeed
if(IS_VISIBLE==flag)
return(true);
//--- call virtual event handler
return(flag ? Show() : Hide());
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CWnd::Show(void)
{
//--- change flag
StateFlagsSet(WND_STATE_FLAG_VISIBLE);
//--- call virtual event handler
return(OnShow());
}
//+------------------------------------------------------------------+
//| Makes the control hidden |
//+------------------------------------------------------------------+
bool CWnd::Hide(void)
{
//--- change flag
StateFlagsReset(WND_STATE_FLAG_VISIBLE);
//--- call virtual event handler
return(OnHide());
}
//+------------------------------------------------------------------+
//| Makes the control active |
//+------------------------------------------------------------------+
bool CWnd::Activate(void)
{
//--- if there are now changes, then succeed
if(IS_ACTIVE)
return(true);
//--- change flag
StateFlagsSet(WND_STATE_FLAG_ACTIVE);
//--- call virtual event handler
return(OnActivate());
}
//+------------------------------------------------------------------+
//| Makes the control inactive |
//+------------------------------------------------------------------+
bool CWnd::Deactivate(void)
{
//--- if there are now changes, then succeed
if(!IS_ACTIVE)
return(true);
//--- change flag
StateFlagsReset(WND_STATE_FLAG_ACTIVE);
//--- call virtual event handler
return(OnDeactivate());
}
//+------------------------------------------------------------------+
//| Set ID of control |
//+------------------------------------------------------------------+
long CWnd::Id(const long id)
{
m_id=id;
//--- always use only one ID
return(1);
}
//+------------------------------------------------------------------+
//| Set parameters of alignment |
//+------------------------------------------------------------------+
void CWnd::Alignment(const int flags,const int left,const int top,const int right,const int bottom)
{
m_align_flags =flags;
m_align_left =left;
m_align_top =top;
m_align_right =right;
m_align_bottom=bottom;
}
//+------------------------------------------------------------------+
//| Align element in specified chart area |
//+------------------------------------------------------------------+
bool CWnd::Align(const CRect &rect)
{
if(m_align_flags == WND_ALIGN_NONE) return true;
int new_value = 0;
int new_width = -1;
int new_height = -1;
if((m_align_flags & WND_ALIGN_RIGHT) != 0)
{
// there is alignment by right border,
if((m_align_flags & WND_ALIGN_LEFT) != 0)
{
// and by left border (change size and move)
new_width = rect.Width() - m_align_left - m_align_right;
Move(rect.left + m_align_left, Top());
}
else
{
// no alignment by left border (move)
new_value = rect.right - Width() - m_align_right;
Move(new_value, Top());
}
}
else if((m_align_flags & WND_ALIGN_LEFT) != 0)
{
// alignment by left border only
new_value = rect.left + m_align_left;
Move(new_value, Top());
}
if((m_align_flags & WND_ALIGN_BOTTOM) !=0 )
{
// there is alignment by bottom border,
if((m_align_flags & WND_ALIGN_TOP) != 0)
{
// and by top border (change size and move)
new_height = rect.Height() - m_align_top - m_align_bottom;
Move(Left(), rect.top + m_align_top);
}
else
{
// no alignment by top border (move)
new_value = rect.bottom - Height() - m_align_bottom;
Move(Left(), new_value);
}
}
else
if((m_align_flags & WND_ALIGN_TOP) != 0)
{
// alignment by top border only
new_value = rect.top + m_align_top;
Move(Left(), new_value);
}
if(new_width != -1 || new_height != -1)
{
Size(new_width != -1 ? new_width : Width(), new_height != -1 ? new_height : Height());
}
return true;
}
//+------------------------------------------------------------------+
//| Remove the mouse focus from control |
//+------------------------------------------------------------------+
bool CWnd::MouseFocusKill(const long id)
{
//--- check
if(id==m_id)
return(false);
//--- reset flag
Deactivate();
//--- clean
m_mouse_x =0;
m_mouse_y =0;
m_mouse_flags=MOUSE_INVALID_FLAGS;
//--- call the handler
return(OnDeactivate());
}
//+------------------------------------------------------------------+
//| Increases the priority of an element |
//+------------------------------------------------------------------+
bool CWnd::BringToTop(void)
{
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_BRING_TO_TOP,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "click" event |
//+------------------------------------------------------------------+
bool CWnd::OnClick(void)
{
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CLICK,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "doubl click" event |
//+------------------------------------------------------------------+
bool CWnd::OnDblClick(void)
{
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DBL_CLICK,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button |
//+------------------------------------------------------------------+
bool CWnd::OnMouseDown(void)
{
if(IS_CAN_DRAG)
return(OnDragStart());
if(IS_CLICKS_BY_PRESS)
return(OnClick());
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of releasing the left mouse button |
//+------------------------------------------------------------------+
bool CWnd::OnMouseUp(void)
{
if(IS_CAN_DBL_CLICK)
{
uint last_time=GetTickCount();
if(m_last_click==0 || last_time-m_last_click>CONTROLS_DBL_CLICK_TIME)
{
m_last_click=(last_time==0) ? 1 : last_time;
}
else
{
m_last_click=0;
return(OnDblClick());
}
}
if(IS_CAN_DRAG)
return(OnDragEnd());
if(!IS_CLICKS_BY_PRESS)
return(OnClick());
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the control dragging start |
//+------------------------------------------------------------------+
bool CWnd::OnDragStart(void)
{
if(!IS_CAN_DRAG)
return(true);
//--- disable scrolling of chart with mouse
ChartSetInteger(m_chart_id,CHART_MOUSE_SCROLL,false);
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DRAG_START,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of control dragging process |
//+------------------------------------------------------------------+
bool CWnd::OnDragProcess(const int x,const int y)
{
Shift(x-m_mouse_x,y-m_mouse_y);
//--- save
m_mouse_x=x;
m_mouse_y=y;
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the control dragging end |
//+------------------------------------------------------------------+
bool CWnd::OnDragEnd(void)
{
if(!IS_CAN_DRAG)
return(true);
//--- enable scrolling of chart with mouse
ChartSetInteger(m_chart_id,CHART_MOUSE_SCROLL,true);
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DRAG_END,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Destroy the dragged object |
//+------------------------------------------------------------------+
bool CWnd::DragObjectDestroy(void)
{
if(m_drag_object!=NULL)
{
delete m_drag_object;
m_drag_object=NULL;
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Class CDragWnd |
//| Usage: base class for drag |
//+------------------------------------------------------------------+
class CDragWnd : public CWnd
{
protected:
int m_limit_left; // left constraint
int m_limit_top; // top constraint
int m_limit_right; // right constraint
int m_limit_bottom; // bottom constraint
public:
CDragWnd(void);
~CDragWnd(void);
//--- constraints
void Limits(const int l,const int t,const int r,const int b);
protected:
virtual bool OnDragProcess(const int x,const int y);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CDragWnd::CDragWnd(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CDragWnd::~CDragWnd(void)
{
}
//+------------------------------------------------------------------+
//| Constrain the control dragging |
//+------------------------------------------------------------------+
void CDragWnd::Limits(const int l,const int t,const int r,const int b)
{
//--- save
m_limit_left =l;
m_limit_top =t;
m_limit_right =r;
m_limit_bottom=b;
}
//+------------------------------------------------------------------+
//| Handler of control dragging process |
//+------------------------------------------------------------------+
bool CDragWnd::OnDragProcess(const int x,const int y)
{
int dx=x-m_mouse_x;
int dy=y-m_mouse_y;
//--- check shift
if(Right()+dx>m_limit_right)
dx=m_limit_right-Right();
if(Left()+dx<m_limit_left)
dx=m_limit_left-Left();
if(Bottom()+dy>m_limit_bottom)
dy=m_limit_bottom-Bottom();
if(Top()+dy<m_limit_top)
dy=m_limit_top-Top();
//--- shift
Shift(dx,dy);
//--- save
m_mouse_x=x;
m_mouse_y=y;
//--- generate event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_DRAG_PROCESS,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| ArrayObj.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "Array.mqh"
//+------------------------------------------------------------------+
//| Array.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include <Object.mqh>
//+------------------------------------------------------------------+
//| Class CArray |
//| Purpose: Base class of dynamic arrays. |
//| Derives from class CObject. |
//+------------------------------------------------------------------+
class CArray : public CObject
{
protected:
int m_step_resize; // increment size of the array
int m_data_total; // number of elements
int m_data_max; // maximmum size of the array without memory reallocation
int m_sort_mode; // mode of array sorting
public:
CArray(void);
~CArray(void);
//--- methods of access to protected data
int Step(void) const { return(m_step_resize); }
bool Step(const int step);
int Total(void) const { return(m_data_total); }
int Available(void) const { return(m_data_max-m_data_total); }
int Max(void) const { return(m_data_max); }
bool IsSorted(const int mode=0) const { return(m_sort_mode==mode); }
int SortMode(void) const { return(m_sort_mode); }
//--- cleaning method
void Clear(void) { m_data_total=0; }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- sorting method
void Sort(const int mode=0);
protected:
virtual void QuickSort(int beg,int end,const int mode=0) { m_sort_mode=-1; }
//--- templates for methods of searching for minimum and maximum
template<typename T>
int Minimum(const T &data[],const int start,const int count) const;
template<typename T>
int Maximum(const T &data[],const int start,const int count) const;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArray::CArray(void) : m_step_resize(16),
m_data_total(0),
m_data_max(0),
m_sort_mode(-1)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArray::~CArray(void)
{
}
//+------------------------------------------------------------------+
//| Method Set for variable m_step_resize |
//+------------------------------------------------------------------+
bool CArray::Step(const int step)
{
//--- check
if(step>0)
{
m_step_resize=step;
return(true);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Sorting an array in ascending order |
//+------------------------------------------------------------------+
void CArray::Sort(const int mode)
{
//--- check
if(IsSorted(mode))
return;
m_sort_mode=mode;
if(m_data_total<=1)
return;
//--- sort
QuickSort(0,m_data_total-1,mode);
}
//+------------------------------------------------------------------+
//| Writing header of array to file |
//+------------------------------------------------------------------+
bool CArray::Save(const int file_handle)
{
//--- check handle
if(file_handle!=INVALID_HANDLE)
{
//--- write start marker - 0xFFFFFFFFFFFFFFFF
if(FileWriteLong(file_handle,-1)==sizeof(long))
{
//--- write array type
if(FileWriteInteger(file_handle,Type(),INT_VALUE)==INT_VALUE)
return(true);
}
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Reading header of array from file |
//+------------------------------------------------------------------+
bool CArray::Load(const int file_handle)
{
//--- check handle
if(file_handle!=INVALID_HANDLE)
{
//--- read and check start marker - 0xFFFFFFFFFFFFFFFF
if(FileReadLong(file_handle)==-1)
{
//--- read and check array type
if(FileReadInteger(file_handle,INT_VALUE)==Type())
return(true);
}
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Find minimum of array |
//+------------------------------------------------------------------+
template<typename T>
int CArray::Minimum(const T &data[],const int start,const int count) const
{
int real_count;
//--- check for empty array
if(m_data_total<1)
{
SetUserError(ERR_USER_ARRAY_IS_EMPTY);
return(-1);
}
//--- check for start is out of range
if(start<0 || start>=m_data_total)
{
SetUserError(ERR_USER_ITEM_NOT_FOUND);
return(-1);
}
//--- compute count of elements
real_count=(count==WHOLE_ARRAY || start+count>m_data_total) ? m_data_total-start : count;
#ifdef __MQL5__
return(ArrayMinimum(data,start,real_count));
#else
return(ArrayMinimum(data,real_count,start));
#endif
}
//+------------------------------------------------------------------+
//| Find maximum of array |
//+------------------------------------------------------------------+
template<typename T>
int CArray::Maximum(const T &data[],const int start,const int count) const
{
int real_count;
//--- check for empty array
if(m_data_total<1)
{
SetUserError(ERR_USER_ARRAY_IS_EMPTY);
return(-1);
}
//--- check for start is out of range
if(start<0 || start>=m_data_total)
{
SetUserError(ERR_USER_ITEM_NOT_FOUND);
return(-1);
}
//--- compute count of elements
real_count=(count==WHOLE_ARRAY || start+count>m_data_total) ? m_data_total-start : count;
#ifdef __MQL5__
return(ArrayMaximum(data,start,real_count));
#else
return(ArrayMaximum(data,real_count,start));
#endif
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class CArrayObj. |
//| Puprose: Class of dynamic array of pointers to instances |
//| of the CObject class and its derivatives. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayObj : public CArray
{
protected:
CObject *m_data[]; // data array
bool m_free_mode; // flag of necessity of "physical" deletion of object
public:
CArrayObj(void);
~CArrayObj(void);
//--- methods of access to protected data
bool FreeMode(void) const { return(m_free_mode); }
void FreeMode(const bool mode) { m_free_mode=mode; }
//--- method of identifying the object
virtual int Type(void) const { return(0x7778); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- method of creating an element of array
virtual bool CreateElement(const int index) { return(false); }
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(CObject *element);
bool AddArray(const CArrayObj *src);
bool Insert(CObject *element,const int pos);
bool InsertArray(const CArrayObj *src,const int pos);
bool AssignArray(const CArrayObj *src);
//--- method of access to thre array
CObject *At(const int index) const;
//--- methods of changing
bool Update(const int index,CObject *element);
bool Shift(const int index,const int shift);
//--- methods of deleting
CObject *Detach(const int index);
bool Delete(const int index);
bool DeleteRange(int from,int to);
void Clear(void);
//--- method for comparing arrays
bool CompareArray(const CArrayObj *array) const;
//--- methods for working with the sorted array
bool InsertSort(CObject *element);
int Search(const CObject *element) const;
int SearchGreat(const CObject *element) const;
int SearchLess(const CObject *element) const;
int SearchGreatOrEqual(const CObject *element) const;
int SearchLessOrEqual(const CObject *element) const;
int SearchFirst(const CObject *element) const;
int SearchLast(const CObject *element) const;
protected:
void QuickSort(int beg,int end,const int mode);
int QuickSearch(const CObject *element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayObj::CArrayObj(void) : m_free_mode(true)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayObj::~CArrayObj(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayObj::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
{
//--- "physical" removal of the object (if necessary and possible)
if(m_free_mode && CheckPointer(m_data[dest+i])==POINTER_DYNAMIC)
delete m_data[dest+i];
//---
m_data[dest+i]=m_data[src+i];
m_data[src+i]=NULL;
}
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
{
//--- "physical" removal of the object (if necessary and possible)
if(m_free_mode && CheckPointer(m_data[dest+i])==POINTER_DYNAMIC)
delete m_data[dest+i];
//---
m_data[dest+i]=m_data[src+i];
m_data[src+i]=NULL;
}
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayObj::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
//--- explicitly zeroize all the loose items in the array
for(int i=m_data_total;i<m_data_max;i++)
m_data[i]=NULL;
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayObj::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_total>size)
{
//--- "physical" removal of the object (if necessary and possible)
if(m_free_mode)
for(int i=size;i<m_data_total;i++)
if(CheckPointer(m_data[i])==POINTER_DYNAMIC)
delete m_data[i];
m_data_total=size;
}
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayObj::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
Clear();
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayObj::Add(CObject *element)
{
//--- check
if(!CheckPointer(element))
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayObj::AddArray(const CArrayObj *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayObj::Insert(CObject *element,const int pos)
{
//--- check
if(pos<0 || !CheckPointer(element))
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayObj::InsertArray(const CArrayObj *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num)) return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayObj::AssignArray(const CArrayObj *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
CObject *CArrayObj::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(NULL);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayObj::Update(const int index,CObject *element)
{
//--- check
if(index<0 || !CheckPointer(element) || index>=m_data_total)
return(false);
//--- "physical" removal of the object (if necessary and possible)
if(m_free_mode && CheckPointer(m_data[index])==POINTER_DYNAMIC)
delete m_data[index];
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayObj::Shift(const int index,const int shift)
{
CObject *tmp_node;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_node=m_data[index];
m_data[index]=NULL;
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_node;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayObj::Delete(const int index)
{
//--- check
if(index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1)
{
if(index>=0 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
}
else
if(m_free_mode && CheckPointer(m_data[index])==POINTER_DYNAMIC)
delete m_data[index];
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Detach element from the specified position |
//+------------------------------------------------------------------+
CObject *CArrayObj::Detach(const int index)
{
CObject *result;
//--- check
if(index>=m_data_total)
return(NULL);
//--- detach
result=m_data[index];
//--- reset the array element, so as not remove the method MemMove
m_data[index]=NULL;
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(NULL);
m_data_total--;
//--- successful
return(result);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayObj::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
for(int i=to-from+1;i>0;i--,m_data_total--)
if(m_free_mode && CheckPointer(m_data[m_data_total-1])==POINTER_DYNAMIC)
delete m_data[m_data_total-1];
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Clearing of array without the release of memory |
//+------------------------------------------------------------------+
void CArrayObj::Clear(void)
{
//--- "physical" removal of the object (if necessary and possible)
if(m_free_mode)
{
for(int i=0;i<m_data_total;i++)
{
if(CheckPointer(m_data[i])==POINTER_DYNAMIC)
delete m_data[i];
m_data[i]=NULL;
}
}
m_data_total=0;
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayObj::CompareArray(const CArrayObj *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i].Compare(array.m_data[i],0)!=0)
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayObj::QuickSort(int beg,int end,const int mode)
{
int i,j;
CObject *p_node;
CObject *t_node;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_node=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i].Compare(p_node,mode)<0)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j].Compare(p_node,mode)>0)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_node=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_node;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j,mode);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayObj::InsertSort(CObject *element)
{
int pos;
//--- check
if(!CheckPointer(element) || m_sort_mode==-1)
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
int mode=m_sort_mode;
pos=QuickSearch(element);
if(m_data[pos].Compare(element,m_sort_mode)>0)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=mode;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::QuickSearch(const CObject *element) const
{
int i,j,m=-1;
CObject *t_node;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m==m_data_total-1)
break;
t_node=m_data[m];
if(t_node.Compare(element,m_sort_mode)==0)
break;
if(t_node.Compare(element,m_sort_mode)>0)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::Search(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos].Compare(element,m_sort_mode)==0)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchGreat(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos].Compare(element,m_sort_mode)<=0)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchLess(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos].Compare(element,m_sort_mode)>=0)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchGreatOrEqual(const CObject *element) const
{
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos].Compare(element,m_sort_mode)>=0)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchLessOrEqual(const CObject *element) const
{
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos].Compare(element,m_sort_mode)<=0)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchFirst(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos].Compare(element,m_sort_mode)==0)
{
while(m_data[pos].Compare(element,m_sort_mode)==0)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayObj::SearchLast(const CObject *element) const
{
int pos;
//--- check
if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1)
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos].Compare(element,m_sort_mode)==0)
{
while(m_data[pos].Compare(element,m_sort_mode)==0)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayObj::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(m_data[i].Save(file_handle)!=true)
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayObj::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
//--- create new element
if(!CreateElement(i))
break;
if(m_data[i].Load(file_handle)!=true)
break;
m_data_total++;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class CWndContainer |
//| Usage: base class of the combined control |
//+------------------------------------------------------------------+
class CWndContainer : public CWnd
{
private:
CArrayObj m_controls; // container of the control
public:
CWndContainer(void);
~CWndContainer(void);
//--- release memory
virtual void Destroy(const int reason=0);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
virtual bool OnMouseEvent(const int x,const int y,const int flags);
//--- access the contents of container
int ControlsTotal(void) const { return(m_controls.Total()); }
CWnd* Control(const int ind) const { return(dynamic_cast<CWnd *>(m_controls.At(ind))); }
virtual CWnd* ControlFind(const long id);
//--- for mouse cursor focus
virtual bool MouseFocusKill(const long id=-1);
//--- fill
bool Add(CWnd *control);
bool Add(CWnd &control);
//--- underflowing
bool Delete(CWnd *control);
bool Delete(CWnd &control);
bool DeleteAll(void);
//--- geometry
virtual bool Move(const int x,const int y);
virtual bool Move(const CPoint &point);
virtual bool Shift(const int dx,const int dy);
//--- ID
virtual long Id(const long id);
long Id(void) const { return(CWnd::Id()); }
//--- state
virtual bool Enable(void);
virtual bool Disable(void);
virtual bool Show(void);
virtual bool Hide(void);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- internal event handlers
virtual bool OnResize(void);
virtual bool OnActivate(void);
virtual bool OnDeactivate(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
bool CWndContainer::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- if an object is being dragged, pass control to the special drag object
if(m_drag_object!=NULL && m_drag_object.OnEvent(id,lparam,dparam,sparam))
return(true);
//--- loop by elements of group
int total=m_controls.Total();
for(int i=total-1;i>=0;i--)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
if(control.OnEvent(id,lparam,dparam,sparam))
return(true);
}
//--- not handled
return(false);
}
//+------------------------------------------------------------------+
//| Common handler of mouse events |
//+------------------------------------------------------------------+
bool CWndContainer::OnMouseEvent(const int x,const int y,const int flags)
{
if(!IS_VISIBLE)
return(false);
//--- if an object is being dragged, pass control to the special drag object
if(m_drag_object!=NULL && m_drag_object.OnMouseEvent(x,y,flags))
return(true);
//--- loop by elements of group
int total=m_controls.Total();
for(int i=total-1;i>=0;i--)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
if(control.OnMouseEvent(x,y,flags))
return(true);
}
//--- call of the method of the parent class
return(CWnd::OnMouseEvent(x,y,flags));
}
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CWndContainer::CWndContainer(void)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CWndContainer::~CWndContainer(void)
{
}
//+------------------------------------------------------------------+
//| Delete group of controls |
//+------------------------------------------------------------------+
void CWndContainer::Destroy(const int reason)
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(0);
//--- check of pointer
if(control==NULL)
continue;
control.Destroy();
m_controls.Delete(0);
}
}
//+------------------------------------------------------------------+
//| Find control by specified ID |
//+------------------------------------------------------------------+
CWnd* CWndContainer::ControlFind(const long id)
{
CWnd *result=CWnd::ControlFind(id);
//---
if(result!=NULL)
return(result);
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
result=control.ControlFind(id);
if(result!=NULL)
break;
}
//--- return the result
return(result);
}
//+------------------------------------------------------------------+
//| Remove the mouse focus from control |
//+------------------------------------------------------------------+
bool CWndContainer::MouseFocusKill(const long id=-1)
{
if(!IS_ACTIVE)
return(false);
Deactivate();
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.MouseFocusKill();
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Add control to the group (by pointer) |
//+------------------------------------------------------------------+
bool CWndContainer::Add(CWnd *control)
{
//--- check of pointer
if(control==NULL)
return(false);
//--- correct the coordinates of added control
control.Shift(Left(),Top());
//--- "projecting" the group flag "visibility" to the added element
if(IS_VISIBLE && control.IsVisible())
{
//--- element will be "visible" only if the group is "visible" and the element is completely "within" this group
control.Visible(Contains(control));
}
else
control.Hide();
//--- "projecting" the group flag "enabled" to the added element
if(!IS_ENABLED)
// control.Enable(); - we can't enable controls by their containers - controls can be disabled on purpose
//else
control.Disable();
//--- adding
return(m_controls.Add(control));
}
//+------------------------------------------------------------------+
//| Add control to the group (by reference) |
//+------------------------------------------------------------------+
bool CWndContainer::Add(CWnd &control)
{
//--- add by pointer
return(Add((CWnd*)GetPointer(control)));
}
//+------------------------------------------------------------------+
//| Delete control from the group (by pointer) |
//+------------------------------------------------------------------+
bool CWndContainer::Delete(CWnd *control)
{
if(control == NULL) return(false);
const int total = m_controls.Total();
for(int i = total - 1; i >= 0; i--)
{
CWnd *pointer = Control(i);
if(pointer == NULL) continue;
if(pointer == control)
{
CWndContainer *container = dynamic_cast<CWndContainer *>(control);
if(container != NULL) container.DeleteAll();
return(m_controls.Delete(i));
}
}
return false;
}
bool CWndContainer::DeleteAll(void)
{
const int total = m_controls.Total();
for(int i = total - 1; i >= 0; i--)
{
CWnd *pointer = Control(i);
if(pointer == NULL) continue;
Delete(pointer);
}
return true;
}
//+------------------------------------------------------------------+
//| Delete control from the group (by reference) |
//+------------------------------------------------------------------+
bool CWndContainer::Delete(CWnd &control)
{
//--- delete by pointer
return(Delete((CWnd*)GetPointer(control)));
}
//+------------------------------------------------------------------+
//| Absolute movement of the controls group |
//+------------------------------------------------------------------+
bool CWndContainer::Move(const int x,const int y)
{
//--- relative movement
return(Shift(x-Left(),y-Top()));
}
//+------------------------------------------------------------------+
//| Absolute movement of the controls group |
//+------------------------------------------------------------------+
bool CWndContainer::Move(const CPoint &point)
{
//--- relative movement
return(Shift(point.x-Left(),point.y-Top()));
}
//+------------------------------------------------------------------+
//| Relative movement of the controls group |
//+------------------------------------------------------------------+
bool CWndContainer::Shift(const int dx,const int dy)
{
if(dx == 0 && dy == 0) return true;
//--- call of the method of the parent class
if(!CWnd::Shift(dx,dy)) return(false);
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
//--- move the group item
control.Shift(dx,dy);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set ID of control |
//+------------------------------------------------------------------+
long CWndContainer::Id(const long id)
{
//--- reserve ID for container
long id_used=1;
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
id_used+=control.Id(id+id_used);
}
m_id=id;
//--- return number of used IDs
return(id_used);
}
//+------------------------------------------------------------------+
//| Enables event handling by the group of controls |
//+------------------------------------------------------------------+
bool CWndContainer::Enable(void)
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Enable();
}
//--- call of the method of the parent class
return(CWnd::Enable());
}
//+------------------------------------------------------------------+
//| Disables event handling by the group of controls |
//+------------------------------------------------------------------+
bool CWndContainer::Disable(void)
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Disable();
}
//--- call of the method of the parent class
return(CWnd::Disable());
}
//+------------------------------------------------------------------+
//| Makes the group of controls visible |
//+------------------------------------------------------------------+
bool CWndContainer::Show(void)
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Show();
}
//--- call of the method of the parent class
return(CWnd::Show());
}
//+------------------------------------------------------------------+
//| Makes the group of controls hidden |
//+------------------------------------------------------------------+
bool CWndContainer::Hide(void)
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Hide();
}
//--- call of the method of the parent class
return(CWnd::Hide());
}
//+------------------------------------------------------------------+
//| Handler of resizing |
//+------------------------------------------------------------------+
bool CWndContainer::OnResize()
{
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
if(!control.Align(Rect()))
return(false);
}
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of activating the group of controls |
//+------------------------------------------------------------------+
bool CWndContainer::OnActivate(void)
{
if(IS_ACTIVE)
return(false);
Activate();
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Activate();
}
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of deactivating the group of controls |
//+------------------------------------------------------------------+
bool CWndContainer::OnDeactivate(void)
{
if(!IS_ACTIVE)
return(false);
Deactivate();
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
control.Deactivate();
}
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Save |
//+------------------------------------------------------------------+
bool CWndContainer::Save(const int file_handle)
{
bool result=true;
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
result&=control.Save(file_handle);
}
//--- result
return(result);
}
//+------------------------------------------------------------------+
//| Load |
//+------------------------------------------------------------------+
bool CWndContainer::Load(const int file_handle)
{
bool result=true;
//--- loop by elements of group
int total=m_controls.Total();
for(int i=0;i<total;i++)
{
CWnd *control=Control(i);
//--- check of pointer
if(control==NULL)
continue;
result&=control.Load(file_handle);
}
//--- result
return(result);
}
//+------------------------------------------------------------------+
//#include "WndClient.mqh"
//+------------------------------------------------------------------+
//| WndClient.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndContainer.mqh"
//#include "Panel.mqh"
//+------------------------------------------------------------------+
//| Panel.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndObj.mqh"
//+------------------------------------------------------------------+
//| WndObj.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "Wnd.mqh"
//+------------------------------------------------------------------+
//| Class CWndObj |
//| Usage: base class to work with chart objects |
//+------------------------------------------------------------------+
class CWndObj : public CWnd
{
private:
//--- flags of object
bool m_undeletable; // "object is not deletable" flag
bool m_unchangeable; // "object is not changeable" flag
bool m_unmoveable; // "object is not movable" flag
protected:
//--- parameters of the chart object
string m_text; // object text
color m_color; // object color
color m_color_background; // object background color
color m_color_border; // object border color
string m_font; // object font
int m_font_size; // object font size
long m_zorder; // Z order
public:
CWndObj(void);
~CWndObj(void);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up the object
string Text(void) const { return(m_text); }
bool Text(const string value);
color Color(void) const { return(m_color); }
bool Color(const color value);
color ColorBackground(void) const { return(m_color_background); }
bool ColorBackground(const color value);
color ColorBorder(void) const { return(m_color_border); }
bool ColorBorder(const color value);
string Font(void) const { return(m_font); }
bool Font(const string value);
int FontSize(void) const { return(m_font_size); }
bool FontSize(const int value);
long ZOrder(void) const { return(m_zorder); }
bool ZOrder(const long value);
protected:
//--- handlers of object events
virtual bool OnObjectCreate(void);
virtual bool OnObjectChange(void);
virtual bool OnObjectDelete(void);
virtual bool OnObjectDrag(void);
//--- handlers of object settings
virtual bool OnSetText(void) { return(true); }
virtual bool OnSetColor(void) { return(true); }
virtual bool OnSetColorBackground(void) { return(true); }
virtual bool OnSetColorBorder(void) { return(true); }
virtual bool OnSetFont(void) { return(true); }
virtual bool OnSetFontSize(void) { return(true); }
virtual bool OnSetZOrder(void) { return(true); }
//--- internal event handlers
virtual bool OnDestroy(void) { return(ObjectDelete(m_chart_id,m_name)); }
virtual bool OnChange(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
bool CWndObj::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
if(m_name==sparam)
{
//--- object name and string parameters are equal
//--- this means that event should be handled
switch(id)
{
case CHARTEVENT_OBJECT_CREATE: return(OnObjectCreate());
case CHARTEVENT_OBJECT_CHANGE: return(OnObjectChange());
case CHARTEVENT_OBJECT_DELETE: return(OnObjectDelete());
case CHARTEVENT_OBJECT_DRAG : return(OnObjectDrag());
}
}
//--- event was not handled
return(CWnd::OnEvent(id,lparam,dparam,sparam));
}
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CWndObj::CWndObj(void) : m_color(clrNONE),
m_color_background(clrNONE),
m_color_border(clrNONE),
m_font(CONTROLS_FONT_NAME),
m_font_size(CONTROLS_FONT_SIZE),
m_zorder(0),
m_undeletable(true),
m_unchangeable(true),
m_unmoveable(true)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CWndObj::~CWndObj(void)
{
}
//+------------------------------------------------------------------+
//| Set the "Text" parameter |
//+------------------------------------------------------------------+
bool CWndObj::Text(const string value)
{
//--- save new value of parameter
m_text=value;
//--- call virtual event handler
return(OnSetText());
}
//+------------------------------------------------------------------+
//| Set the "Color" parameter |
//+------------------------------------------------------------------+
bool CWndObj::Color(const color value)
{
//--- save new value of parameter
m_color=value;
//--- call virtual event handler
return(OnSetColor());
}
//+------------------------------------------------------------------+
//| Setting the "Background color" parameter |
//+------------------------------------------------------------------+
bool CWndObj::ColorBackground(const color value)
{
//--- save new value of parameter
m_color_background=value;
//--- call virtual event handler
return(OnSetColorBackground());
}
//+------------------------------------------------------------------+
//| Set the "Border color" parameter |
//+------------------------------------------------------------------+
bool CWndObj::ColorBorder(const color value)
{
//--- save new value of parameter
m_color_border=value;
//--- call virtual event handler
return(OnSetColorBorder());
}
//+------------------------------------------------------------------+
//| Set the "Font" parameter |
//+------------------------------------------------------------------+
bool CWndObj::Font(const string value)
{
//--- save new value of parameter
m_font=value;
//--- call virtual event handler
return(OnSetFont());
}
//+------------------------------------------------------------------+
//| Set the "Font size" parameter |
//+------------------------------------------------------------------+
bool CWndObj::FontSize(const int value)
{
//--- save new value of parameter
m_font_size=value;
//--- call virtual event handler
return(OnSetFontSize());
}
//+------------------------------------------------------------------+
//| Set the "Z order" parameter |
//+------------------------------------------------------------------+
bool CWndObj::ZOrder(const long value)
{
//--- save new value of parameter
m_zorder=value;
//--- call virtual event handler
return(OnSetZOrder());
}
//+------------------------------------------------------------------+
//| Handler of the "Object creation" event |
//+------------------------------------------------------------------+
bool CWndObj::OnObjectCreate(void)
{
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Object modification" event |
//+------------------------------------------------------------------+
bool CWndObj::OnObjectChange(void)
{
//--- if object is not changeable
if(m_unchangeable)
{
//--- restore position
if(!OnMove())
return(false);
//--- restore size
if(!OnResize())
return(false);
//--- restore settings
if(!OnChange())
return(false);
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Object deletion" event |
//+------------------------------------------------------------------+
bool CWndObj::OnObjectDelete(void)
{
//--- if object is not deletable
if(m_undeletable)
{
//--- restore the object
if(!OnCreate())
return(false);
//--- restore settings
if(!OnChange())
return(false);
//--- restore visibility
return(IS_VISIBLE ? OnShow():OnHide());
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Object dragging" event |
//+------------------------------------------------------------------+
bool CWndObj::OnObjectDrag(void)
{
//--- if object is not movable
if(m_unmoveable)
{
//--- restore position
return(OnMove());
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Set up the object |
//+------------------------------------------------------------------+
bool CWndObj::OnChange(void)
{
//--- set up the chart object according to previously set parameters
if(!OnSetText())
return(false);
if(!OnSetFont())
return(false);
if(!OnSetFontSize())
return(false);
if(!OnSetColor())
return(false);
if(!OnSetColorBackground())
return(false);
if(!OnSetColorBorder())
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| ChartObjectsTxtControls.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//| All text objects. |
//+------------------------------------------------------------------+
//#include "ChartObject.mqh"
//+------------------------------------------------------------------+
//| ChartObject.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include <Object.mqh>
//+------------------------------------------------------------------+
//| Class CChartObject. |
//| Pupose: Base class of chart objects. |
//| Derives from class CObject. |
//+------------------------------------------------------------------+
class CChartObject : public CObject
{
protected:
long m_chart_id; // identifier of chart the object belongs to
int m_window; // number of subwindow (0 - main window)
string m_name; // unique name object name
int m_num_points; // number of anchor points of object
public:
CChartObject(void);
~CChartObject(void);
//--- method of identifying the object
virtual int Type(void) const { return(0x8888); }
//--- methods of access to protected data
long ChartId(void) const { return(m_chart_id); }
int Window(void) const { return(m_window); }
string Name(void) const { return(m_name); }
bool Name(const string name);
int NumPoints(void) const { return(m_num_points); }
//--- methods of filling the object
bool Attach(long chart_id,const string name,const int window,const int points);
bool SetPoint(const int point,const datetime time,const double price) const;
//--- methods of deleting
bool Delete(void);
void Detach(void);
//--- methods of access to properties of the object
datetime Time(const int point) const;
bool Time(const int point,const datetime time) const;
double Price(const int point) const;
bool Price(const int point,const double price) const;
color Color(void) const;
bool Color(const color new_color) const;
ENUM_LINE_STYLE Style(void) const;
bool Style(const ENUM_LINE_STYLE new_style) const;
int Width(void) const;
bool Width(const int new_width) const;
bool Background(void) const;
bool Background(const bool new_back) const;
bool Fill(void) const;
bool Fill(const bool new_fill) const;
long Z_Order(void) const;
bool Z_Order(const long value) const;
bool Selected(void) const;
bool Selected(const bool new_sel) const;
bool Selectable(void) const;
bool Selectable(const bool new_sel) const;
string Description(void) const;
bool Description(const string new_text) const;
string Tooltip(void) const;
bool Tooltip(const string new_text) const;
int Timeframes(void) const;
virtual bool Timeframes(const int timeframes) const;
datetime CreateTime(void) const;
int LevelsCount(void) const;
bool LevelsCount(const int new_count) const;
//--- methods to access the properties of levels of objects
color LevelColor(const int level) const;
bool LevelColor(const int level,const color new_color) const;
ENUM_LINE_STYLE LevelStyle(const int level) const;
bool LevelStyle(const int level,const ENUM_LINE_STYLE new_style) const;
int LevelWidth(const int level) const;
bool LevelWidth(const int level,const int new_width) const;
double LevelValue(const int level) const;
bool LevelValue(const int level,const double new_value) const;
string LevelDescription(const int level) const;
bool LevelDescription(const int level,const string new_text) const;
//--- access methods to the API functions of MQL5
long GetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier=-1) const;
bool GetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier,long &value) const;
bool SetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier,const long value) const;
bool SetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const long value) const;
double GetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier=-1) const;
bool GetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier,double &value) const;
bool SetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier,const double value) const;
bool SetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const double value) const;
string GetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier=-1) const;
bool GetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier,string &value) const;
bool SetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier,const string value) const;
bool SetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const string value) const;
//--- methods of moving
bool ShiftObject(const datetime d_time,const double d_price) const;
bool ShiftPoint(const int point,const datetime d_time,const double d_price) const;
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObject::CChartObject(void)
{
//--- initialize protected data
Detach();
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObject::~CChartObject(void)
{
if(m_chart_id!=-1)
ObjectDelete(m_chart_id,m_name);
}
//+------------------------------------------------------------------+
//| Changing name of the object |
//+------------------------------------------------------------------+
bool CChartObject::Name(const string name)
{
//--- check
if(m_chart_id==-1)
return(false);
//--- change
if(ObjectSetString(m_chart_id,m_name,OBJPROP_NAME,name))
{
m_name=name;
return(true);
}
//--- failure
return(false);
};
//+------------------------------------------------------------------+
//| Attach object |
//+------------------------------------------------------------------+
bool CChartObject::Attach(long chart_id,const string name,const int window,const int points)
{
//--- check
if(ObjectFind(chart_id,name)<0)
return(false);
//--- attach
if(chart_id==0)
chart_id=ChartID();
m_chart_id =chart_id;
m_window =window;
m_name =name;
m_num_points=points;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Setting new coordinates of anchor point of an object |
//+------------------------------------------------------------------+
bool CChartObject::SetPoint(const int point,const datetime time,const double price) const
{
//--- check
if(m_chart_id==-1)
return(false);
if(point>=m_num_points)
return(false);
//--- result
return(ObjectMove(m_chart_id,m_name,point,time,price));
}
//+------------------------------------------------------------------+
//| Delete an object |
//+------------------------------------------------------------------+
bool CChartObject::Delete(void)
{
//--- checki
if(m_chart_id==-1)
return(false);
//--- actions
bool result=ObjectDelete(m_chart_id,m_name);
Detach();
//--- result
return(result);
}
//+------------------------------------------------------------------+
//| Detach object |
//+------------------------------------------------------------------+
void CChartObject::Detach(void)
{
m_chart_id =-1;
m_window =-1;
m_name =NULL;
m_num_points=0;
}
//+------------------------------------------------------------------+
//| Get the time coordinate of the specified anchor point of object |
//+------------------------------------------------------------------+
datetime CChartObject::Time(const int point) const
{
//--- check
if(m_chart_id==-1)
return(0);
if(point>=m_num_points)
return(0);
//--- result
return((datetime)ObjectGetInteger(m_chart_id,m_name,OBJPROP_TIME,point));
}
//+------------------------------------------------------------------+
//| Set the time coordinate of the specified anchor point of object |
//+------------------------------------------------------------------+
bool CChartObject::Time(const int point,const datetime time) const
{
//--- check
if(m_chart_id==-1)
return(false);
if(point>=m_num_points)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_TIME,point,time));
}
//+------------------------------------------------------------------+
//| Get the price coordinate of the specified anchor point of object.|
//+------------------------------------------------------------------+
double CChartObject::Price(const int point) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
if(point>=m_num_points)
return(EMPTY_VALUE);
//--- result
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_PRICE,point));
}
//+------------------------------------------------------------------+
//| Set the price coordinate of the specified anchor point of object.|
//+------------------------------------------------------------------+
bool CChartObject::Price(const int point,const double price) const
{
//--- check
if(m_chart_id==-1)
return(false);
if(point>=m_num_points)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_PRICE,point,price));
}
//+------------------------------------------------------------------+
//| Get object color |
//+------------------------------------------------------------------+
color CChartObject::Color(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_COLOR));
}
//+------------------------------------------------------------------+
//| Set object color |
//+------------------------------------------------------------------+
bool CChartObject::Color(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_COLOR,new_color));
}
//+------------------------------------------------------------------+
//| Get style of line of object |
//+------------------------------------------------------------------+
ENUM_LINE_STYLE CChartObject::Style(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_LINE_STYLE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_STYLE));
}
//+------------------------------------------------------------------+
//| Set style of line of object |
//+------------------------------------------------------------------+
bool CChartObject::Style(const ENUM_LINE_STYLE new_style) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_STYLE,new_style));
}
//+------------------------------------------------------------------+
//| Get width of line of object |
//+------------------------------------------------------------------+
int CChartObject::Width(void) const
{
//--- check
if(m_chart_id==-1)
return(-1);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_WIDTH));
}
//+------------------------------------------------------------------+
//| Set width of line of object |
//+------------------------------------------------------------------+
bool CChartObject::Width(const int new_width) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_WIDTH,new_width));
}
//+------------------------------------------------------------------+
//| Get the "Draw object as background" flag |
//+------------------------------------------------------------------+
bool CChartObject::Background(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BACK));
}
//+------------------------------------------------------------------+
//| Set the "Draw object as background" flag |
//+------------------------------------------------------------------+
bool CChartObject::Background(const bool new_back) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BACK,new_back));
}
//+------------------------------------------------------------------+
//| Get the "Filling" flag |
//+------------------------------------------------------------------+
bool CChartObject::Fill(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_FILL));
}
//+------------------------------------------------------------------+
//| Set the "Filling" flag |
//+------------------------------------------------------------------+
bool CChartObject::Fill(const bool new_fill) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_FILL,new_fill));
}
//+------------------------------------------------------------------+
//| Get the "Z-order" property |
//+------------------------------------------------------------------+
long CChartObject::Z_Order(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return(ObjectGetInteger(m_chart_id,m_name,OBJPROP_ZORDER));
}
//+------------------------------------------------------------------+
//| Set the "Z-order" property |
//+------------------------------------------------------------------+
bool CChartObject::Z_Order(const long value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ZORDER,value));
}
//+------------------------------------------------------------------+
//| Get the "selected" flag |
//+------------------------------------------------------------------+
bool CChartObject::Selected(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_SELECTED));
}
//+------------------------------------------------------------------+
//| Set the "selected" flag |
//+------------------------------------------------------------------+
bool CChartObject::Selected(const bool new_sel) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_SELECTED,new_sel));
}
//+------------------------------------------------------------------+
//| Get the "selectable" flag |
//+------------------------------------------------------------------+
bool CChartObject::Selectable(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_SELECTABLE));
}
//+------------------------------------------------------------------+
//| Set flag the "selectable" flag |
//+------------------------------------------------------------------+
bool CChartObject::Selectable(const bool new_sel) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_SELECTABLE,new_sel));
}
//+------------------------------------------------------------------+
//| Get comment of object |
//+------------------------------------------------------------------+
string CChartObject::Description(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_TEXT));
}
//+------------------------------------------------------------------+
//| Set comment of object |
//+------------------------------------------------------------------+
bool CChartObject::Description(const string new_text) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- tune
if(new_text=="")
return(ObjectSetString(m_chart_id,m_name,OBJPROP_TEXT," "));
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_TEXT,new_text));
}
//+------------------------------------------------------------------+
//| Get tooltip of object |
//+------------------------------------------------------------------+
string CChartObject::Tooltip(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_TOOLTIP));
}
//+------------------------------------------------------------------+
//| Set tooltip of object |
//+------------------------------------------------------------------+
bool CChartObject::Tooltip(const string new_text) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- tune
if(new_text=="")
return(ObjectSetString(m_chart_id,m_name,OBJPROP_TOOLTIP," "));
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_TOOLTIP,new_text));
}
//+------------------------------------------------------------------+
//| Get the "Timeframes" (visibility) flag |
//+------------------------------------------------------------------+
int CChartObject::Timeframes(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_TIMEFRAMES));
}
//+------------------------------------------------------------------+
//| Set the "Timeframes" (visibility) flag |
//+------------------------------------------------------------------+
bool CChartObject::Timeframes(const int timeframes) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_TIMEFRAMES,timeframes));
}
//+------------------------------------------------------------------+
//| Get time of object creation |
//+------------------------------------------------------------------+
datetime CChartObject::CreateTime(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((datetime)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CREATETIME));
}
//+------------------------------------------------------------------+
//| Get number of levels of object |
//+------------------------------------------------------------------+
int CChartObject::LevelsCount(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELS));
}
//+------------------------------------------------------------------+
//| Set number of levels of object |
//+------------------------------------------------------------------+
bool CChartObject::LevelsCount(const int new_count) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELS,new_count));
}
//+------------------------------------------------------------------+
//| Get color of the specified level of object |
//+------------------------------------------------------------------+
color CChartObject::LevelColor(const int level) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
if(level>=LevelsCount())
return(CLR_NONE);
//--- result
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELCOLOR,level));
}
//+------------------------------------------------------------------+
//| Set color of the specified level of object |
//+------------------------------------------------------------------+
bool CChartObject::LevelColor(const int level,const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
if(level>=LevelsCount())
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELCOLOR,level,new_color));
}
//+------------------------------------------------------------------+
//| Get line style of the specified level of object |
//+------------------------------------------------------------------+
ENUM_LINE_STYLE CChartObject::LevelStyle(const int level) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
if(level>=LevelsCount())
return(WRONG_VALUE);
//--- result
return((ENUM_LINE_STYLE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELSTYLE,level));
}
//+------------------------------------------------------------------+
//| Set line style of the specified level of object |
//+------------------------------------------------------------------+
bool CChartObject::LevelStyle(const int level,const ENUM_LINE_STYLE new_style) const
{
//--- check
if(m_chart_id==-1)
return(false);
if(level>=LevelsCount())
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELSTYLE,level,new_style));
}
//+------------------------------------------------------------------+
//| Get line width of the specified level of object |
//+------------------------------------------------------------------+
int CChartObject::LevelWidth(const int level) const
{
//--- check
if(m_chart_id==-1)
return(-1);
if(level>=LevelsCount())
return(-1);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELWIDTH,level));
}
//+------------------------------------------------------------------+
//| Set line width of the specified level of object |
//+------------------------------------------------------------------+
bool CChartObject::LevelWidth(const int level,const int new_width) const
{
//--- check
if(m_chart_id==-1)
return(false);
if(level>=LevelsCount())
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELWIDTH,level,new_width));
}
//+------------------------------------------------------------------+
//| Get value of the specified level of object |
//+------------------------------------------------------------------+
double CChartObject::LevelValue(const int level) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
if(level>=LevelsCount())
return(EMPTY_VALUE);
//--- result
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_LEVELVALUE,level));
}
//+------------------------------------------------------------------+
//| Set value of the specified level of object |
//+------------------------------------------------------------------+
bool CChartObject::LevelValue(const int level,const double new_value) const
{
//--- check
if(m_chart_id==-1)
return(false);
if(level>=LevelsCount())
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_LEVELVALUE,level,new_value));
}
//+------------------------------------------------------------------+
//| Get comment of of the specified level of object |
//+------------------------------------------------------------------+
string CChartObject::LevelDescription(const int level) const
{
//--- check
if(m_chart_id==-1)
return("");
if(level>=LevelsCount())
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_LEVELTEXT,level));
}
//+------------------------------------------------------------------+
//| Set comment to the specified level of object |
//+------------------------------------------------------------------+
bool CChartObject::LevelDescription(const int level,const string new_text) const
{
//--- checking
if(m_chart_id==-1)
return(false);
if(level>=LevelsCount())
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_LEVELTEXT,level,new_text));
}
//+------------------------------------------------------------------+
//| Access function long ObjectGetInteger(...) |
//+------------------------------------------------------------------+
long CChartObject::GetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier) const
{
//--- check
if(m_chart_id==-1)
return(0);
//---
if(modifier==-1)
return(ObjectGetInteger(m_chart_id,m_name,prop_id));
//--- result
return(ObjectGetInteger(m_chart_id,m_name,prop_id,modifier));
}
//+------------------------------------------------------------------+
//| Access function bool ObjectGetInteger(...) |
//+------------------------------------------------------------------+
bool CChartObject::GetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier,long &value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectGetInteger(m_chart_id,m_name,prop_id,modifier,value));
}
//+------------------------------------------------------------------+
//| Access function ObjectSetInteger(.,modifier,.) |
//+------------------------------------------------------------------+
bool CChartObject::SetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier,const long value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,prop_id,modifier,value));
}
//+------------------------------------------------------------------+
//| Access function ObjectSetInteger(...) |
//+------------------------------------------------------------------+
bool CChartObject::SetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const long value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,prop_id,value));
}
//+------------------------------------------------------------------+
//| Access function double ObjectGetDouble(...) |
//+------------------------------------------------------------------+
double CChartObject::GetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//---
if(modifier==-1)
return(ObjectGetDouble(m_chart_id,m_name,prop_id));
//--- result
return(ObjectGetDouble(m_chart_id,m_name,prop_id,modifier));
}
//+------------------------------------------------------------------+
//| Access function bool ObjectGetDouble(...) |
//+------------------------------------------------------------------+
bool CChartObject::GetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier,double &value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectGetDouble(m_chart_id,m_name,prop_id,modifier,value));
}
//+------------------------------------------------------------------+
//| Access function ObjectSetDouble(.,modifier,.) |
//+------------------------------------------------------------------+
bool CChartObject::SetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier,const double value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,prop_id,modifier,value));
}
//+------------------------------------------------------------------+
//| Access function ObjectSetDouble(...) |
//+------------------------------------------------------------------+
bool CChartObject::SetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const double value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,prop_id,value));
}
//+------------------------------------------------------------------+
//| Access function string ObjectGetString (...) |
//+------------------------------------------------------------------+
string CChartObject::GetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier) const
{
//--- check
if(m_chart_id==-1)
return("");
//---
if(modifier==-1)
return(ObjectGetString(m_chart_id,m_name,prop_id));
//--- result
return(ObjectGetString(m_chart_id,m_name,prop_id,modifier));
}
//+------------------------------------------------------------------+
//| Access function bool ObjectGetString(...) |
//+------------------------------------------------------------------+
bool CChartObject::GetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier,string &value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectGetString(m_chart_id,m_name,prop_id,modifier,value));
}
//+------------------------------------------------------------------+
//| Access function ObjectSetString(.,modifier,.) |
//+------------------------------------------------------------------+
bool CChartObject::SetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier,const string value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,prop_id,modifier,value));
}
//+------------------------------------------------------------------+
//| Access function ObjectSetString(...) |
//+------------------------------------------------------------------+
bool CChartObject::SetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const string value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,prop_id,value));
}
//+------------------------------------------------------------------+
//| Relative movement of object |
//+------------------------------------------------------------------+
bool CChartObject::ShiftObject(const datetime d_time,const double d_price) const
{
bool result=true;
int i;
//--- check
if(m_chart_id==-1)
return(false);
//--- move
for(i=0;i<m_num_points;i++)
result&=ShiftPoint(i,d_time,d_price);
//--- result
return(result);
}
//+------------------------------------------------------------------+
//| Relative movement of the specified achor point of object |
//+------------------------------------------------------------------+
bool CChartObject::ShiftPoint(const int point,const datetime d_time,const double d_price) const
{
//--- check
if(m_chart_id==-1)
return(false);
if(point>=m_num_points)
return(false);
//--- move
datetime time=(datetime)ObjectGetInteger(m_chart_id,m_name,OBJPROP_TIME,point);
double price=ObjectGetDouble(m_chart_id,m_name,OBJPROP_PRICE,point);
//--- result
return(ObjectMove(m_chart_id,m_name,point,time+d_time,price+d_price));
}
//+------------------------------------------------------------------+
//| Writing object parameters to file |
//+------------------------------------------------------------------+
bool CChartObject::Save(const int file_handle)
{
int i,len;
int levels;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write start marker - 0xFFFFFFFFFFFFFFFF
if(FileWriteLong(file_handle,-1)!=sizeof(long))
return(false);
//--- write object type
if(FileWriteInteger(file_handle,Type(),INT_VALUE)!=INT_VALUE)
return(false);
//--- write object name
str=ObjectGetString(m_chart_id,m_name,OBJPROP_NAME);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0) if(FileWriteString(file_handle,str,len)!=len)
return(false);
//--- write object color
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_COLOR))!=sizeof(long))
return(false);
//--- write object line style
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_STYLE))!=sizeof(int))
return(false);
//--- write object line width
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_WIDTH))!=sizeof(int))
return(false);
//--- write the property value "Background"
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BACK),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write the property value "Selectable"
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_SELECTABLE),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write the property value "Timeframes"
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_TIMEFRAMES),INT_VALUE)!=sizeof(int))
return(false);
//--- write comment
str=ObjectGetString(m_chart_id,m_name,OBJPROP_TEXT);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0) if(FileWriteString(file_handle,str,len)!=len)
return(false);
//--- write number of points
if(FileWriteInteger(file_handle,m_num_points,INT_VALUE)!=INT_VALUE)
return(false);
//--- write points
for(i=0;i<m_num_points;i++)
{
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_TIME,i))!=sizeof(long))
return(false);
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_PRICE,i))!=sizeof(double))
return(false);
}
//--- write number of levels
levels=(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELS);
if(FileWriteInteger(file_handle,levels,INT_VALUE)!=INT_VALUE)
return(false);
//--- write levels
for(i=0;i<levels;i++)
{
//--- level color
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELCOLOR,i))!=sizeof(long))
return(false);
//--- level line style
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELSTYLE,i))!=sizeof(int))
return(false);
//--- level line width
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELWIDTH,i))!=sizeof(int))
return(false);
//--- level value
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_LEVELVALUE,i))!=sizeof(double))
return(false);
//--- level name
str=ObjectGetString(m_chart_id,m_name,OBJPROP_LEVELTEXT,i);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0) if(FileWriteString(file_handle,str,len)!=len)
return(false);
}
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading object parameters from file |
//+------------------------------------------------------------------+
bool CChartObject::Load(const int file_handle)
{
int i,len,num;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read and check start marker - 0xFFFFFFFFFFFFFFFF
if(FileReadLong(file_handle)!=-1)
return(false);
//--- read and check object type
if(FileReadInteger(file_handle,INT_VALUE)!=Type())
return(false);
//--- read object name
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_NAME,str))
return(false);
//--- read object color
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_COLOR,FileReadLong(file_handle)))
return(false);
//--- read object line style
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_STYLE,FileReadInteger(file_handle)))
return(false);
//--- read object line style
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_WIDTH,FileReadInteger(file_handle)))
return(false);
//--- read the property value "Background"
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_BACK,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read the property value "Selectable"
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_SELECTABLE,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read the property value "Timeframes"
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_TIMEFRAMES,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read comment
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_TEXT,str))
return(false);
//--- read number of point
num=FileReadInteger(file_handle,INT_VALUE);
//--- read points
if(num!=0)
{
for(i=0;i<num;i++)
{
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_TIME,i,FileReadLong(file_handle)))
return(false);
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_PRICE,i,FileReadDouble(file_handle)))
return(false);
}
}
//--- read number of levels
num=FileReadInteger(file_handle,INT_VALUE);
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELS,0,num))
return(false);
//--- read levels
if(num!=0)
{
for(i=0;i<num;i++)
{
//--- level color
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELCOLOR,i,FileReadLong(file_handle)))
return(false);
//--- levelline style
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELSTYLE,i,FileReadInteger(file_handle)))
return(false);
//--- level line width
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELWIDTH,i,FileReadInteger(file_handle)))
return(false);
//--- level value
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_LEVELVALUE,i,FileReadDouble(file_handle)))
return(false);
//--- level name
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_LEVELTEXT,i,str))
return(false);
}
}
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class CChartObjectText. |
//| Purpose: Class of the "Text" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectText : public CChartObject
{
public:
CChartObjectText(void);
~CChartObjectText(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_TEXT); }
//--- methods of access to properties of the object
double Angle(void) const;
bool Angle(const double angle) const;
string Font(void) const;
bool Font(const string font) const;
int FontSize(void) const;
bool FontSize(const int size) const;
ENUM_ANCHOR_POINT Anchor(void) const;
bool Anchor(const ENUM_ANCHOR_POINT anchor) const;
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectText::CChartObjectText(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectText::~CChartObjectText(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Text" |
//+------------------------------------------------------------------+
bool CChartObjectText::Create(long chart_id,const string name,const int window,
const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_TEXT,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get value of the "Angle" property |
//+------------------------------------------------------------------+
double CChartObjectText::Angle(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_ANGLE));
}
//+------------------------------------------------------------------+
//| Set value of the "Angle" property |
//+------------------------------------------------------------------+
bool CChartObjectText::Angle(const double angle) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_ANGLE,angle));
}
//+------------------------------------------------------------------+
//| Get font name |
//+------------------------------------------------------------------+
string CChartObjectText::Font(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_FONT));
}
//+------------------------------------------------------------------+
//| Set font name |
//+------------------------------------------------------------------+
bool CChartObjectText::Font(const string font) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_FONT,font));
}
//+------------------------------------------------------------------+
//| Get font size |
//+------------------------------------------------------------------+
int CChartObjectText::FontSize(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE));
}
//+------------------------------------------------------------------+
//| Set font size |
//+------------------------------------------------------------------+
bool CChartObjectText::FontSize(const int size) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE,size));
}
//+------------------------------------------------------------------+
//| Get anchor point |
//+------------------------------------------------------------------+
ENUM_ANCHOR_POINT CChartObjectText::Anchor(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_ANCHOR_POINT)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ANCHOR));
}
//+------------------------------------------------------------------+
//| Set anchor point |
//+------------------------------------------------------------------+
bool CChartObjectText::Anchor(const ENUM_ANCHOR_POINT anchor) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ANCHOR,anchor));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectText::Save(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObject::Save(file_handle))
return(false);
//--- write value of the "Angle" property
if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_ANGLE))!=sizeof(double))
return(false);
//--- write value of the "Font Name" property
str=ObjectGetString(m_chart_id,m_name,OBJPROP_FONT);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
return(false);
//--- write value of the "Font Size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Anchor Point" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ANCHOR),INT_VALUE)!=sizeof(int))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectText::Load(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObject::Load(file_handle))
return(false);
//--- reading value of the "Angle" property
if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_ANGLE,0,FileReadDouble(file_handle)))
return(false);
//--- read value of the "Font Name" property
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_FONT,str))
return(false);
//--- read value of the "Font Size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_FONTSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Anchor Point" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_ANCHOR,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectLabel. |
//| Purpose: Class of the "Label" object of chart. |
//| Derives from class CChartObjectText. |
//+------------------------------------------------------------------+
class CChartObjectLabel : public CChartObjectText
{
public:
CChartObjectLabel(void);
~CChartObjectLabel(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const int X,const int Y);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_LABEL); }
//--- methods of access to properties of the object
int X_Distance(void) const;
bool X_Distance(const int X) const;
int Y_Distance(void) const;
bool Y_Distance(const int Y) const;
int X_Size(void) const;
int Y_Size(void) const;
ENUM_BASE_CORNER Corner(void) const;
bool Corner(const ENUM_BASE_CORNER corner) const;
//--- change of time/price coordinates is blocked
datetime Time(const int point) const { return(CChartObjectText::Time(point)); }
bool Time(const int point,const datetime time) const { return(false); }
double Price(const int point) const { return(CChartObjectText::Price(point)); }
bool Price(const int point,const double price) const { return(false); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectLabel::CChartObjectLabel(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectLabel::~CChartObjectLabel(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Label" |
//+------------------------------------------------------------------+
bool CChartObjectLabel::Create(long chart_id,const string name,const int window,const int X,const int Y)
{
if(!ObjectCreate(chart_id,name,OBJ_LABEL,window,0,0.0))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
if(!Description(name))
return(false);
if(!X_Distance(X) || !Y_Distance(Y))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get the X-distance |
//+------------------------------------------------------------------+
int CChartObjectLabel::X_Distance(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE));
}
//+------------------------------------------------------------------+
//| Set the X-distance |
//+------------------------------------------------------------------+
bool CChartObjectLabel::X_Distance(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,X));
}
//+------------------------------------------------------------------+
//| Get the Y-distance |
//+------------------------------------------------------------------+
int CChartObjectLabel::Y_Distance(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE));
}
//+------------------------------------------------------------------+
//| Set the Y-distance |
//+------------------------------------------------------------------+
bool CChartObjectLabel::Y_Distance(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,Y));
}
//+------------------------------------------------------------------+
//| Get the X-size |
//+------------------------------------------------------------------+
int CChartObjectLabel::X_Size(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE));
}
//+------------------------------------------------------------------+
//| Get the Y-size |
//+------------------------------------------------------------------+
int CChartObjectLabel::Y_Size(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE));
}
//+------------------------------------------------------------------+
//| Get base corner |
//+------------------------------------------------------------------+
ENUM_BASE_CORNER CChartObjectLabel::Corner(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_BASE_CORNER)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER));
}
//+------------------------------------------------------------------+
//| Set base corner |
//+------------------------------------------------------------------+
bool CChartObjectLabel::Corner(const ENUM_BASE_CORNER corner) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,corner));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectLabel::Save(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectText::Save(file_handle))
return(false);
//--- write value of the "X-distance" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Y-distance" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Corner" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER),INT_VALUE)!=sizeof(int))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectLabel::Load(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectText::Load(file_handle))
return(false);
//--- reading value of the "X-distance" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Y-distance" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Corner" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectEdit. |
//| Purpose: Class of the "Edit" object of chart. |
//| Derives from class CChartObjectLabel. |
//+------------------------------------------------------------------+
class CChartObjectEdit : public CChartObjectLabel
{
public:
CChartObjectEdit(void);
~CChartObjectEdit(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_EDIT); }
//--- methods of access to properties of the object
bool X_Size(const int X) const;
int X_Size(void) const { return(CChartObjectLabel::X_Size()); }
bool Y_Size(const int Y) const;
int Y_Size(void) const { return(CChartObjectLabel::Y_Size()); }
color BackColor(void) const;
bool BackColor(const color new_color) const;
color BorderColor(void) const;
bool BorderColor(const color new_color) const;
bool ReadOnly(void) const;
bool ReadOnly(const bool flag) const;
ENUM_ALIGN_MODE TextAlign(void) const;
bool TextAlign(const ENUM_ALIGN_MODE align) const;
//--- change of angle is blocked
bool Angle(const double angle) const { return(false); }
double Angle(void) const { return(CChartObjectLabel::Angle()); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectEdit::CChartObjectEdit(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectEdit::~CChartObjectEdit(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Edit" |
//+------------------------------------------------------------------+
bool CChartObjectEdit::Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY)
{
if(!ObjectCreate(chart_id,name,(ENUM_OBJECT)Type(),window,0,0,0))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
if(!X_Distance(X) || !Y_Distance(Y))
return(false);
if(!X_Size(sizeX) || !Y_Size(sizeY))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Set X-size |
//+------------------------------------------------------------------+
bool CChartObjectEdit::X_Size(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,X));
}
//+------------------------------------------------------------------+
//| Set Y-size |
//+------------------------------------------------------------------+
bool CChartObjectEdit::Y_Size(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,Y));
}
//+------------------------------------------------------------------+
//| Get background color |
//+------------------------------------------------------------------+
color CChartObjectEdit::BackColor(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR));
}
//+------------------------------------------------------------------+
//| Set background color |
//+------------------------------------------------------------------+
bool CChartObjectEdit::BackColor(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,new_color));
}
//+------------------------------------------------------------------+
//| Get border color |
//+------------------------------------------------------------------+
color CChartObjectEdit::BorderColor(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BORDER_COLOR));
}
//+------------------------------------------------------------------+
//| Set border color |
//+------------------------------------------------------------------+
bool CChartObjectEdit::BorderColor(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BORDER_COLOR,new_color));
}
//+------------------------------------------------------------------+
//| Get the "Read only" property |
//+------------------------------------------------------------------+
bool CChartObjectEdit::ReadOnly(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_READONLY));
}
//+------------------------------------------------------------------+
//| Set the "Read only" property |
//+------------------------------------------------------------------+
bool CChartObjectEdit::ReadOnly(const bool flag) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_READONLY,flag));
}
//+------------------------------------------------------------------+
//| Get the "Align" property |
//+------------------------------------------------------------------+
ENUM_ALIGN_MODE CChartObjectEdit::TextAlign(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((ENUM_ALIGN_MODE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_ALIGN));
}
//+------------------------------------------------------------------+
//| Set the "Align" property |
//+------------------------------------------------------------------+
bool CChartObjectEdit::TextAlign(const ENUM_ALIGN_MODE align) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ALIGN,align));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectEdit::Save(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectLabel::Save(file_handle))
return(false);
//--- write value of the "X-size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Y-size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write background color
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR))!=sizeof(long))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectEdit::Load(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectLabel::Load(file_handle))
return(false);
//--- read value of the "X-size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Y-size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read background color
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,FileReadLong(file_handle)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectButton. |
//| Purpose: Class of the "Button" object of chart. |
//| Derives from class CChartObjectEdit. |
//+------------------------------------------------------------------+
class CChartObjectButton : public CChartObjectEdit
{
public:
CChartObjectButton(void);
~CChartObjectButton(void);
//--- method of identifying the object
virtual int Type(void) const override { return(OBJ_BUTTON); }
//--- methods of access to properties of the object
bool State(void) const;
bool State(const bool state) const;
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectButton::CChartObjectButton(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectButton::~CChartObjectButton(void)
{
}
//+------------------------------------------------------------------+
//| Get state |
//+------------------------------------------------------------------+
bool CChartObjectButton::State(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE));
}
//+------------------------------------------------------------------+
//| Set state |
//+------------------------------------------------------------------+
bool CChartObjectButton::State(const bool state) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,state));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectButton::Save(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectEdit::Save(file_handle))
return(false);
//--- write state
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE))!=sizeof(long))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectButton::Load(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectEdit::Load(file_handle))
return(false);
//--- read state
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,FileReadLong(file_handle)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectRectLabel. |
//| Purpose: Class of the "Rectangle Label" object of chart. |
//| Derives from class CChartObjectLabel. |
//+------------------------------------------------------------------+
class CChartObjectRectLabel : public CChartObjectLabel
{
public:
CChartObjectRectLabel(void);
~CChartObjectRectLabel(void);
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_RECTANGLE_LABEL); }
//--- methods of access to properties of the object
bool X_Size(const int X) const;
int X_Size(void)const { return(CChartObjectLabel::X_Size()); }
bool Y_Size(const int Y) const;
int Y_Size(void)const { return(CChartObjectLabel::Y_Size()); }
color BackColor(void) const;
bool BackColor(const color new_color) const;
ENUM_BORDER_TYPE BorderType(void) const;
bool BorderType(const ENUM_BORDER_TYPE flag) const;
//--- change of angle is blocked
bool Angle(const double angle) const { return(false); }
double Angle(void) const { return(CChartObjectLabel::Angle()); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectRectLabel::CChartObjectRectLabel(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectRectLabel::~CChartObjectRectLabel(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Ractangle Label" |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::Create(long chart_id,const string name,const int window,const int X,const int Y,const int sizeX,const int sizeY)
{
if(!ObjectCreate(chart_id,name,(ENUM_OBJECT)Type(),window,0,0,0))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
if(!X_Distance(X) || !Y_Distance(Y))
return(false);
if(!X_Size(sizeX) || !Y_Size(sizeY))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Set X-size |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::X_Size(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,X));
}
//+------------------------------------------------------------------+
//| Set Y-size |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::Y_Size(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,Y));
}
//+------------------------------------------------------------------+
//| Get background color |
//+------------------------------------------------------------------+
color CChartObjectRectLabel::BackColor(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR));
}
//+------------------------------------------------------------------+
//| Set background color |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::BackColor(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,new_color));
}
//+------------------------------------------------------------------+
//| Get the "Border type" property |
//+------------------------------------------------------------------+
ENUM_BORDER_TYPE CChartObjectRectLabel::BorderType(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((ENUM_BORDER_TYPE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE));
}
//+------------------------------------------------------------------+
//| Set the "Border type" property |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::BorderType(const ENUM_BORDER_TYPE type) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE,type));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::Save(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObjectLabel::Save(file_handle))
return(false);
//--- write value of the "X-size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Y-size" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE),INT_VALUE)!=sizeof(int))
return(false);
//--- write background color
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR))!=sizeof(long))
return(false);
//--- write value of the "Border type" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE),INT_VALUE)!=sizeof(int))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectRectLabel::Load(const int file_handle)
{
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObjectLabel::Load(file_handle))
return(false);
//--- read value of the "X-size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Y-size" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YSIZE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read background color
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_BGCOLOR,FileReadLong(file_handle)))
return(false);
//--- read value of the "Border type" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_BORDER_TYPE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class CPanel |
//| Usage: control that is displayed by |
//| the CChartObjectRectLabel object |
//+------------------------------------------------------------------+
class CPanel : public CWndObj
{
private:
CChartObjectRectLabel m_rectangle; // chart object
//--- parameters of the chart object
ENUM_BORDER_TYPE m_border; // border type
public:
CPanel(void);
~CPanel(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- parameters of the chart object
ENUM_BORDER_TYPE BorderType(void) const { return(m_border); }
bool BorderType(const ENUM_BORDER_TYPE type);
protected:
//--- handlers of object settings
virtual bool OnSetText(void) { return(m_rectangle.Description(m_text)); }
virtual bool OnSetColorBackground(void) { return(m_rectangle.BackColor(m_color_background)); }
virtual bool OnSetColorBorder(void) { return(m_rectangle.Color(m_color_border)); }
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
virtual bool OnResize(void);
virtual bool OnChange(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CPanel::CPanel(void) : m_border(BORDER_FLAT)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CPanel::~CPanel(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CPanel::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_rectangle.Create(chart,name,subwin,x1,y1,Width(),Height()))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Set border type |
//+------------------------------------------------------------------+
bool CPanel::BorderType(const ENUM_BORDER_TYPE type)
{
//--- save new value of parameter
m_border=type;
//--- set up the chart object
return(m_rectangle.BorderType(type));
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CPanel::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_rectangle.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CPanel::OnShow(void)
{
return(m_rectangle.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CPanel::OnHide(void)
{
return(m_rectangle.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CPanel::OnMove(void)
{
//--- position the chart object
return(m_rectangle.X_Distance(m_rect.left) && m_rectangle.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
//| Resize the chart object |
//+------------------------------------------------------------------+
bool CPanel::OnResize(void)
{
//--- resize the chart object
return(m_rectangle.X_Size(m_rect.Width()) && m_rectangle.Y_Size(m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Set up the chart object |
//+------------------------------------------------------------------+
bool CPanel::OnChange(void)
{
//--- set up the chart object
return(CWndObj::OnChange() && m_rectangle.BorderType(m_border));
}
//+------------------------------------------------------------------+
//#include "Scrolls.mqh"
//+------------------------------------------------------------------+
//| Scrolls.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndContainer.mqh"
//#include "Panel.mqh"
//#include "BmpButton.mqh"
//+------------------------------------------------------------------+
//| BmpButton.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndObj.mqh"
//#include <ChartObjects\ChartObjectsBmpControls.mqh>
//+------------------------------------------------------------------+
//| ChartObjectsBmpControls.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//| All objects with "bmp" pictures. |
//+------------------------------------------------------------------+
//#include "ChartObject.mqh"
//+------------------------------------------------------------------+
//| Class CChartObjectBitmap. |
//| Purpose: Class of the "Bitmap" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectBitmap : public CChartObject
{
public:
CChartObjectBitmap(void);
~CChartObjectBitmap(void);
//--- methods of access to properties of the object
string BmpFile(void) const;
bool BmpFile(const string name) const;
int X_Offset(void) const;
bool X_Offset(const int X) const;
int Y_Offset(void) const;
bool Y_Offset(const int Y) const;
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const datetime time,const double price);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_BITMAP); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectBitmap::CChartObjectBitmap(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectBitmap::~CChartObjectBitmap(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Bitmapp" |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::Create(long chart_id,const string name,const int window,const datetime time,const double price)
{
if(!ObjectCreate(chart_id,name,OBJ_BITMAP,window,time,price))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get name of bmp-file |
//+------------------------------------------------------------------+
string CChartObjectBitmap::BmpFile(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE));
}
//+------------------------------------------------------------------+
//| Set name of bmp-file |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::BmpFile(const string name) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,name));
}
//+------------------------------------------------------------------+
//| Get the XOffset property |
//+------------------------------------------------------------------+
int CChartObjectBitmap::X_Offset(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XOFFSET));
}
//+------------------------------------------------------------------+
//| Set the XOffset property |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::X_Offset(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XOFFSET,X));
}
//+------------------------------------------------------------------+
//| Get the YOffset property |
//+------------------------------------------------------------------+
int CChartObjectBitmap::Y_Offset(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YOFFSET));
}
//+------------------------------------------------------------------+
//| Set the YOffset property |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::Y_Offset(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YOFFSET,Y));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::Save(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObject::Save(file_handle))
return(false);
//--- write value of the "name of bmp-file" property
str=ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of object from file |
//+------------------------------------------------------------------+
bool CChartObjectBitmap::Load(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObject::Load(file_handle))
return(false);
//--- read value of the "name of bmp-file" property
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,str))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Class CChartObjectBmpLabel. |
//| Purpose: Class of the "Bitmap label" object of chart. |
//| Derives from class CChartObject. |
//+------------------------------------------------------------------+
class CChartObjectBmpLabel : public CChartObject
{
public:
CChartObjectBmpLabel(void);
~CChartObjectBmpLabel(void);
//--- methods of access to properties of the object
int X_Distance(void) const;
bool X_Distance(const int X) const;
int Y_Distance(void) const;
bool Y_Distance(const int Y) const;
int X_Size(void) const;
int Y_Size(void) const;
ENUM_BASE_CORNER Corner(void) const;
bool Corner(const ENUM_BASE_CORNER corner) const;
string BmpFileOn(void) const;
bool BmpFileOn(const string name) const;
string BmpFileOff(void) const;
bool BmpFileOff(const string name) const;
bool State(void) const;
bool State(const bool state) const;
int X_Offset(void) const;
bool X_Offset(const int X) const;
int Y_Offset(void) const;
bool Y_Offset(const int Y) const;
//--- change of time/price coordinates is blocked
bool Time(const datetime time) const { return(false); }
bool Price(const double price) const { return(false); }
//--- method of creating the object
bool Create(long chart_id,const string name,const int window,const int X,const int Y);
//--- method of identifying the object
virtual int Type(void) const { return(OBJ_BITMAP_LABEL); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartObjectBmpLabel::CChartObjectBmpLabel(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartObjectBmpLabel::~CChartObjectBmpLabel(void)
{
}
//+------------------------------------------------------------------+
//| Create object "Bitmap label" |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Create(long chart_id,const string name,const int window,const int X,const int Y)
{
if(!ObjectCreate(chart_id,name,OBJ_BITMAP_LABEL,window,0,0.0))
return(false);
if(!Attach(chart_id,name,window,1))
return(false);
if(!X_Distance(X) || !Y_Distance(Y))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Get the X-distance property |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::X_Distance(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE));
}
//+------------------------------------------------------------------+
//| Set the X-distance property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::X_Distance(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,X));
}
//+------------------------------------------------------------------+
//| Get the Y-distance property |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::Y_Distance(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE));
}
//+------------------------------------------------------------------+
//| Set the Y-distance property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Y_Distance(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,Y));
}
//+------------------------------------------------------------------+
//| Get the X-size |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::X_Size(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE));
}
//+------------------------------------------------------------------+
//| Get the Y-size |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::Y_Size(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE));
}
//+------------------------------------------------------------------+
//| Get the Corner property |
//+------------------------------------------------------------------+
ENUM_BASE_CORNER CChartObjectBmpLabel::Corner(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_BASE_CORNER)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER));
}
//+------------------------------------------------------------------+
//| Set the Corner property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Corner(const ENUM_BASE_CORNER corner) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,corner));
}
//+------------------------------------------------------------------+
//| Get filename of the "bmp-ON" property |
//+------------------------------------------------------------------+
string CChartObjectBmpLabel::BmpFileOn(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,0));
}
//+------------------------------------------------------------------+
//| Set filename for the "bmp-ON" property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::BmpFileOn(const string name) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,0,name));
}
//+------------------------------------------------------------------+
//| Get filename of the "bmp-OFF" property |
//+------------------------------------------------------------------+
string CChartObjectBmpLabel::BmpFileOff(void) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,1));
}
//+------------------------------------------------------------------+
//| Set filename for the "bmp-OFF" property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::BmpFileOff(const string name) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,1,name));
}
//+------------------------------------------------------------------+
//| Get the State property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::State(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE));
}
//+------------------------------------------------------------------+
//| Set the State property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::State(const bool state) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,state));
}
//+------------------------------------------------------------------+
//| Get the XOffset property |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::X_Offset(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XOFFSET));
}
//+------------------------------------------------------------------+
//| Set the XOffset property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::X_Offset(const int X) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_XOFFSET,X));
}
//+------------------------------------------------------------------+
//| Get the YOffset property |
//+------------------------------------------------------------------+
int CChartObjectBmpLabel::Y_Offset(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YOFFSET));
}
//+------------------------------------------------------------------+
//| Set the YOffset property |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Y_Offset(const int Y) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_YOFFSET,Y));
}
//+------------------------------------------------------------------+
//| Writing parameters of object to file |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Save(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write
if(!CChartObject::Save(file_handle))
return(false);
//--- write value of the "X-distance" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Y-distance" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Corner" property
if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CORNER),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "filename bmp-ON" property
str=ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,0);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
return(false);
//--- write value of the "filename bmp-OFF" property
str=ObjectGetString(m_chart_id,m_name,OBJPROP_BMPFILE,1);
len=StringLen(str);
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
if(len!=0 && FileWriteString(file_handle,str,len)!=len)
return(false);
//--- write state
if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_STATE))!=sizeof(long))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading object parameters from file |
//+------------------------------------------------------------------+
bool CChartObjectBmpLabel::Load(const int file_handle)
{
int len;
string str;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read
if(!CChartObject::Load(file_handle))
return(false);
//--- read value of the "X-distance" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_XDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Y-distance" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_YDISTANCE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of "Corner" property
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_CORNER,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "filename bmp-ON" property
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,0,str))
return(false);
//--- read value of the "filename bmp-OFF" property
len=FileReadInteger(file_handle,INT_VALUE);
str=(len!=0) ? FileReadString(file_handle,len) : "";
if(!ObjectSetString(m_chart_id,m_name,OBJPROP_BMPFILE,1,str))
return(false);
//--- read state
if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_STATE,FileReadLong(file_handle)))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class CBmpButton |
//| Usage: control that is displayed by |
//| the CChartObjectBmpLabel object |
//+------------------------------------------------------------------+
class CBmpButton : public CWndObj
{
private:
CChartObjectBmpLabel m_button; // chart object
//--- parameters of the chart object
int m_border; // border width
string m_bmp_off_name; // name of BMP file for the "OFF" state (default state)
string m_bmp_on_name; // name of BMP file for the "ON" state
string m_bmp_passive_name;
string m_bmp_active_name;
public:
CBmpButton(void);
~CBmpButton(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- parameters of the chart object
int Border(void) const { return(m_border); }
bool Border(const int value);
bool BmpNames(const string off="",const string on="");
string BmpOffName(void) const { return(m_bmp_off_name); }
bool BmpOffName(const string name);
string BmpOnName(void) const { return(m_bmp_on_name); }
bool BmpOnName(const string name);
string BmpPassiveName(void) const { return(m_bmp_passive_name); }
bool BmpPassiveName(const string name);
string BmpActiveName(void) const { return(m_bmp_active_name); }
bool BmpActiveName(const string name);
//--- state
bool Pressed(void) const { return(m_button.State()); }
bool Pressed(const bool pressed) { return(m_button.State(pressed)); }
//--- properties
bool Locking(void) const { return(IS_CAN_LOCK); }
void Locking(const bool locking);
protected:
//--- handlers of object settings
virtual bool OnSetZOrder(void) { return(m_button.Z_Order(m_zorder)); }
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
virtual bool OnChange(void);
//--- ????? ???????????
virtual bool OnActivate(void);
virtual bool OnDeactivate(void);
virtual bool OnMouseDown(void);
virtual bool OnMouseUp(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CBmpButton::CBmpButton(void) : m_border(0),
m_bmp_off_name(NULL),
m_bmp_on_name(NULL),
m_bmp_passive_name(NULL),
m_bmp_active_name(NULL)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CBmpButton::~CBmpButton(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CBmpButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_button.Create(chart,name,subwin,x1,y1))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Set border width |
//+------------------------------------------------------------------+
bool CBmpButton::Border(const int value)
{
//--- save new value of parameter
m_border=value;
//--- set up the chart object
return(m_button.Width(value));
}
//+------------------------------------------------------------------+
//| Set two images at once |
//+------------------------------------------------------------------+
bool CBmpButton::BmpNames(const string off,const string on)
{
//--- save new values of parameters
m_bmp_off_name=off;
m_bmp_on_name =on;
//--- set up the chart object
if(!m_button.BmpFileOff(off))
return(false);
if(!m_button.BmpFileOn(on))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set image for the "OFF" state |
//+------------------------------------------------------------------+
bool CBmpButton::BmpOffName(const string name)
{
//--- save new value of parameter
m_bmp_off_name=name;
//--- set up the chart object
if(!m_button.BmpFileOff(name))
return(false);
//--- set size by image dimensions
Width(m_button.X_Size());
Height(m_button.Y_Size());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set image for the "ON" state |
//+------------------------------------------------------------------+
bool CBmpButton::BmpOnName(const string name)
{
//--- save new value of parameter
m_bmp_on_name=name;
//--- set up the chart object
if(!m_button.BmpFileOn(name))
return(false);
//--- set size by image dimensions
Width(m_button.X_Size());
Height(m_button.Y_Size());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set image for the "OFF" state (passive) |
//+------------------------------------------------------------------+
bool CBmpButton::BmpPassiveName(const string name)
{
//--- save new value of parameter
m_bmp_passive_name=name;
//--- set up the chart object
if(!IS_ACTIVE)
return(BmpOffName(name));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set image for the "OFF" state (active) |
//+------------------------------------------------------------------+
bool CBmpButton::BmpActiveName(const string name)
{
//--- save new value of parameter
m_bmp_active_name=name;
//--- set up the chart object
if(IS_ACTIVE)
return(BmpOffName(name));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Locking flag |
//+------------------------------------------------------------------+
void CBmpButton::Locking(const bool flag)
{
if(flag)
PropFlagsSet(WND_PROP_FLAG_CAN_LOCK);
else
PropFlagsReset(WND_PROP_FLAG_CAN_LOCK);
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CBmpButton::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CBmpButton::OnShow(void)
{
return(m_button.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CBmpButton::OnHide(void)
{
return(m_button.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CBmpButton::OnMove(void)
{
//--- position the chart object
return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
//| Set up the chart object |
//+------------------------------------------------------------------+
bool CBmpButton::OnChange(void)
{
//--- set up the chart object
return(m_button.Width(m_border) && m_button.BmpFileOff(m_bmp_off_name) && m_button.BmpFileOn(m_bmp_on_name));
}
//+------------------------------------------------------------------+
//| Handler of activating the group of controls |
//+------------------------------------------------------------------+
bool CBmpButton::OnActivate(void)
{
if(m_bmp_active_name!=NULL)
BmpOffName(m_bmp_active_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of deactivating the group of controls |
//+------------------------------------------------------------------+
bool CBmpButton::OnDeactivate(void)
{
if(m_bmp_passive_name!=NULL)
BmpOffName(m_bmp_passive_name);
if(!IS_CAN_LOCK)
Pressed(false);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button |
//+------------------------------------------------------------------+
bool CBmpButton::OnMouseDown(void)
{
if(!IS_CAN_LOCK)
Pressed(!Pressed());
//--- call of the method of the parent class
return(CWnd::OnMouseDown());
}
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button |
//+------------------------------------------------------------------+
bool CBmpButton::OnMouseUp(void)
{
//--- depress the button if it is not fixed
if(m_button.State() && !IS_CAN_LOCK)
m_button.State(false);
//--- call of the method of the parent class
return(CWnd::OnMouseUp());
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
#resource "\\Include\\Controls\\res\\Up.bmp"
#resource "\\Include\\Controls\\res\\ThumbVert.bmp"
#resource "\\Include\\Controls\\res\\Down.bmp"
#resource "\\Include\\Controls\\res\\Left.bmp"
#resource "\\Include\\Controls\\res\\ThumbHor.bmp"
#resource "\\Include\\Controls\\res\\Right.bmp"
//+------------------------------------------------------------------+
//| Class CScroll |
//| Usage: base class for scrollbars |
//+------------------------------------------------------------------+
class CScroll : public CWndContainer
{
protected:
//--- dependent controls
CPanel m_back; // the "scrollbar background" object
CBmpButton m_inc; // the "increment button" object ("down" for vertical scrollbar, "right" for horizontal scrollbar)
CBmpButton m_dec; // the "decrement button" object ("up" for vertical scrollbar, "left" for horizontal scrollbar)
CBmpButton m_thumb; // the "scroll box" object
//--- set up
int m_min_pos; // minimum value
int m_max_pos; // maximum value
//--- state
int m_curr_pos; // current value
public:
CScroll(void);
~CScroll(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up
int MinPos(void) const { return(m_min_pos); }
void MinPos(const int value);
int MaxPos(void) const { return(m_max_pos); }
void MaxPos(const int value);
//--- state
int CurrPos(void) const { return(m_curr_pos); }
bool CurrPos(int value);
protected:
//--- create dependent controls
virtual bool CreateBack(void);
virtual bool CreateInc(void) { return(true); }
virtual bool CreateDec(void) { return(true); }
virtual bool CreateThumb(void) { return(true); }
//--- handlers of the dependent controls events
virtual bool OnClickInc(void);
virtual bool OnClickDec(void);
//--- internal event handlers
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnChangePos(void) { return(true); }
//--- handlers of dragging
virtual bool OnThumbDragStart(void) { return(true); }
virtual bool OnThumbDragProcess(void) { return(true); }
virtual bool OnThumbDragEnd(void) { return(true); }
//--- calculate position by coordinate
virtual int CalcPos(const int coord) { return(0); }
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CScroll)
ON_EVENT(ON_CLICK,m_inc,OnClickInc)
ON_EVENT(ON_CLICK,m_dec,OnClickDec)
ON_EVENT(ON_DRAG_START,m_thumb,OnThumbDragStart)
ON_EVENT_PTR(ON_DRAG_PROCESS,m_drag_object,OnThumbDragProcess)
ON_EVENT_PTR(ON_DRAG_END,m_drag_object,OnThumbDragEnd)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CScroll::CScroll(void) : m_curr_pos(0),
m_min_pos(0),
m_max_pos(0)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CScroll::~CScroll(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CScroll::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateBack())
return(false);
if(!CreateInc())
return(false);
if(!CreateDec())
return(false);
if(!CreateThumb())
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create scrollbar background |
//+------------------------------------------------------------------+
bool CScroll::CreateBack(void)
{
//--- create
if(!m_back.Create(m_chart_id,m_name+"Back",m_subwin,0,0,Width(),Height()))
return(false);
if(!m_back.ColorBackground(CONTROLS_SCROLL_COLOR_BG))
return(false);
if(!m_back.ColorBorder(CONTROLS_SCROLL_COLOR_BORDER))
return(false);
if(!Add(m_back))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set current value |
//+------------------------------------------------------------------+
bool CScroll::CurrPos(int value)
{
//--- check value
if(value<m_min_pos)
value=m_min_pos;
if(value>m_max_pos)
value=m_max_pos;
//--- if value was changed
if(m_curr_pos!=value)
{
m_curr_pos=value;
//--- call virtual handler
return(OnChangePos());
}
//--- value has not been changed
return(false);
}
//+------------------------------------------------------------------+
//| Set minimum value |
//+------------------------------------------------------------------+
void CScroll::MinPos(const int value)
{
//--- if value was changed
if(m_min_pos!=value)
{
m_min_pos=value;
//--- adjust the scroll box position
CurrPos(m_curr_pos);
}
}
//+------------------------------------------------------------------+
//| Set maximum value |
//+------------------------------------------------------------------+
void CScroll::MaxPos(const int value)
{
//--- if value was changed
if(m_max_pos!=value)
{
m_max_pos=value;
//--- adjust the scroll box position
CurrPos(m_curr_pos);
}
}
//+------------------------------------------------------------------+
//| Handler of the "Show scrollbar" event |
//+------------------------------------------------------------------+
bool CScroll::OnShow(void)
{
if(m_id==CONTROLS_INVALID_ID)
return(true);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_SHOW,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Hide scrollbar" event |
//+------------------------------------------------------------------+
bool CScroll::OnHide(void)
{
if(m_id==CONTROLS_INVALID_ID)
return(true);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_HIDE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the "increment" button |
//+------------------------------------------------------------------+
bool CScroll::OnClickInc(void)
{
//--- try to increment current value
if(!CurrPos(m_curr_pos+1))
return(true);
//--- if value was changed, send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_SCROLL_INC,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the "decrement" button |
//+------------------------------------------------------------------+
bool CScroll::OnClickDec(void)
{
//--- try to decrement current value
if(!CurrPos(m_curr_pos-1))
return(true);
//--- if value was changed, send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_SCROLL_DEC,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Class CScrollV |
//| Usage: class of vertical scrollbar |
//+------------------------------------------------------------------+
class CScrollV : public CScroll
{
public:
CScrollV(void);
~CScrollV(void);
protected:
//--- create dependent controls
virtual bool CreateInc(void);
virtual bool CreateDec(void);
virtual bool CreateThumb(void);
//--- internal event handlers
virtual bool OnResize(void);
virtual bool OnChangePos(void);
//--- handlers of dragging
virtual bool OnThumbDragStart(void);
virtual bool OnThumbDragProcess(void);
virtual bool OnThumbDragEnd(void);
//--- calculate position by coordinate
virtual int CalcPos(const int coord);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CScrollV::CScrollV(void)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CScrollV::~CScrollV(void)
{
}
//+------------------------------------------------------------------+
//| Create the "Increment" button |
//+------------------------------------------------------------------+
bool CScrollV::CreateInc(void)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=Height()-CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_inc.BmpNames("::Include\\Controls\\res\\Down.bmp"))
return(false);
if(!Add(m_inc))
return(false);
//--- property
m_inc.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Decrement" button |
//+------------------------------------------------------------------+
bool CScrollV::CreateDec(void)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_dec.BmpNames("::Include\\Controls\\res\\Up.bmp"))
return(false);
if(!Add(m_dec))
return(false);
//--- property
m_dec.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create scroll box |
//+------------------------------------------------------------------+
bool CScrollV::CreateThumb(void)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_SCROLL_THUMB_SIZE;
//--- create
if(!m_thumb.Create(m_chart_id,m_name+"Thumb",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_thumb.BmpNames("::Include\\Controls\\res\\ThumbVert.bmp"))
return(false);
if(!Add(m_thumb))
return(false);
m_thumb.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of changing current state |
//+------------------------------------------------------------------+
bool CScrollV::OnChangePos(void)
{
//--- check if scrolling is possible
if(m_max_pos-m_min_pos<=0)
return(Visible(false));
else
if(!Visible(true))
return(false);
//--- calculate new coordinated of the scrollbar
int steps =m_max_pos-m_min_pos; // number of steps to change position
int min_coord=m_dec.Bottom(); // minimum possible coordinate (corresponds to the m_min_pos value)
int max_coord=m_inc.Top()-m_thumb.Height(); // maximum possible coordinate (corresponds to the m_max_pos value)
int new_coord=min_coord+(max_coord-min_coord)*m_curr_pos/steps; // new coordinate
//--- adjust the scroll box position
return(m_thumb.Move(m_thumb.Left(),new_coord));
}
//+------------------------------------------------------------------+
//| Handler of resizing |
//+------------------------------------------------------------------+
bool CScrollV::OnResize(void)
{
//--- can not change the lateral size
if(Width()!=CONTROLS_SCROLL_SIZE)
m_rect.Width(CONTROLS_SCROLL_SIZE);
//--- resize the scrollbar background
if(!m_back.Size(Size()))
return(false);
//--- move the "Increment" button
if(!m_inc.Move(m_inc.Left(),Bottom()-CONTROLS_SCROLL_SIZE))
return(false);
//--- adjust the scroll box position
return(OnChangePos());
}
//+------------------------------------------------------------------+
//| Start dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollV::OnThumbDragStart(void)
{
if(m_drag_object==NULL)
{
m_drag_object=new CDragWnd;
if(m_drag_object==NULL)
return(false);
}
//--- calculate coordinates
int x1=m_thumb.Left()-CONTROLS_DRAG_SPACING;
int y1=m_thumb.Top()-CONTROLS_DRAG_SPACING;
int x2=m_thumb.Right()+CONTROLS_DRAG_SPACING;
int y2=m_thumb.Bottom()+CONTROLS_DRAG_SPACING;
//--- create
m_drag_object.Create(m_chart_id,"",m_subwin,x1,y1,x2,y2);
m_drag_object.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- limits
m_drag_object.Limits(x1,m_dec.Bottom()-CONTROLS_DRAG_SPACING,x2,m_inc.Top()+CONTROLS_DRAG_SPACING);
//--- set mouse params
m_drag_object.MouseX(m_thumb.MouseX());
m_drag_object.MouseY(m_thumb.MouseY());
m_drag_object.MouseFlags(m_thumb.MouseFlags());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Continue dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollV::OnThumbDragProcess(void)
{
//--- checking
if(m_drag_object==NULL)
return(false);
//--- calculate coordinates
int x=m_drag_object.Left()+CONTROLS_DRAG_SPACING;
int y=m_drag_object.Top()+CONTROLS_DRAG_SPACING;
//--- calculate new position
int new_pos=CalcPos(y);
if(new_pos!=m_curr_pos)
{
ushort event_id=(m_curr_pos<new_pos) ? ON_SCROLL_INC : ON_SCROLL_DEC;
m_curr_pos=new_pos;
EventChartCustom(CONTROLS_SELF_MESSAGE,event_id,m_id,0.0,m_name);
}
//--- move thumb
m_thumb.Move(x,y);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| End dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollV::OnThumbDragEnd(void)
{
if(m_drag_object!=NULL)
{
m_thumb.MouseFlags(m_drag_object.MouseFlags());
delete m_drag_object;
m_drag_object=NULL;
}
//--- succeed
return(m_thumb.Pressed(false));
}
//+------------------------------------------------------------------+
//| Calculate position by coordinate |
//+------------------------------------------------------------------+
int CScrollV::CalcPos(const int coord)
{
//--- calculate new position of the scrollbar
int steps =m_max_pos-m_min_pos; // number of steps to change position
int min_coord=m_dec.Bottom(); // minimum possible coordinate (corresponds to the m_min_pos value)
int max_coord=m_inc.Top()-m_thumb.Height(); // maximum possible coordinate (corresponds to the m_max_pos value)
//--- checkeng
if(max_coord==min_coord)
return(0);
if(coord<min_coord || coord>max_coord)
return(m_curr_pos);
//---
int new_pos=(int)MathRound((((double)(coord-min_coord))/(max_coord-min_coord))*steps); // new position
//---
return(new_pos);
}
//+------------------------------------------------------------------+
//| Class CScrollH |
//| Usage: class of horizontal scrollbar |
//+------------------------------------------------------------------+
class CScrollH : public CScroll
{
public:
CScrollH(void);
~CScrollH(void);
protected:
//--- create dependent controls
virtual bool CreateInc(void);
virtual bool CreateDec(void);
virtual bool CreateThumb(void);
//--- internal event handlers
virtual bool OnResize(void);
virtual bool OnChangePos(void);
//--- handlers of dragging
virtual bool OnThumbDragStart(void);
virtual bool OnThumbDragProcess(void);
virtual bool OnThumbDragEnd(void);
//--- calculate position by coordinate
virtual int CalcPos(const int coord);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CScrollH::CScrollH(void)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CScrollH::~CScrollH(void)
{
}
//+------------------------------------------------------------------+
//| Create the "Increment" button |
//+------------------------------------------------------------------+
bool CScrollH::CreateInc(void)
{
//--- calculate coordinates
int x1=Width()-CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_inc.BmpNames("::Include\\Controls\\res\\Right.bmp"))
return(false);
if(!Add(m_inc))
return(false);
//--- property
m_inc.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Decrement" button |
//+------------------------------------------------------------------+
bool CScrollH::CreateDec(void)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_dec.BmpNames("::Include\\Controls\\res\\Left.bmp"))
return(false);
if(!Add(m_dec))
return(false);
//--- property
m_dec.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create scroll box |
//+------------------------------------------------------------------+
bool CScrollH::CreateThumb(void)
{
//--- calculate coordinates
int x1=CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_SCROLL_THUMB_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_thumb.Create(m_chart_id,m_name+"Thumb",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_thumb.BmpNames("::Include\\Controls\\res\\ThumbHor.bmp"))
return(false);
if(!Add(m_thumb))
return(false);
m_thumb.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of changing current state |
//+------------------------------------------------------------------+
bool CScrollH::OnChangePos(void)
{
//--- check if scrolling is possible
if(m_max_pos-m_min_pos<=0)
return(Visible(false));
else
if(!Visible(true))
return(false);
//--- calculate new coordinated of the scrollbar
int steps=m_max_pos-m_min_pos; // number of steps to change position
int min_coord=m_dec.Right(); // minimum possible coordinate (corresponds to the m_min_pos value)
int max_coord=m_inc.Left()-m_thumb.Width(); // maximum possible coordinate (corresponds to the m_max_pos value)
int new_coord=min_coord+(max_coord-min_coord)*m_curr_pos/steps; // new coordinate
//--- adjust the scroll box position
return(m_thumb.Move(new_coord,m_thumb.Top()));
}
//+------------------------------------------------------------------+
//| Handler of resizing |
//+------------------------------------------------------------------+
bool CScrollH::OnResize(void)
{
//--- can not change the lateral size
if(Height()!=CONTROLS_SCROLL_SIZE)
m_rect.Height(CONTROLS_SCROLL_SIZE);
//--- resize the scrollbar background
if(!m_back.Size(Size()))
return(false);
//--- move the "Increment" button
if(!m_inc.Move(Right()-CONTROLS_SCROLL_SIZE,m_inc.Top()))
return(false);
//--- adjust the scroll box position
return(OnChangePos());
}
//+------------------------------------------------------------------+
//| Start dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollH::OnThumbDragStart(void)
{
if(m_drag_object==NULL)
{
m_drag_object=new CDragWnd;
if(m_drag_object==NULL)
return(false);
}
//--- calculate coordinates
int x1=m_thumb.Left()-CONTROLS_DRAG_SPACING;
int y1=m_thumb.Top()-CONTROLS_DRAG_SPACING;
int x2=m_thumb.Right()+CONTROLS_DRAG_SPACING;
int y2=m_thumb.Bottom()+CONTROLS_DRAG_SPACING;
//--- create
m_drag_object.Create(m_chart_id,"",m_subwin,x1,y1,x2,y2);
m_drag_object.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- limits
m_drag_object.Limits(m_dec.Right()-CONTROLS_DRAG_SPACING,y1,m_inc.Left()+CONTROLS_DRAG_SPACING,y2);
//--- set mouse params
m_drag_object.MouseX(m_thumb.MouseX());
m_drag_object.MouseY(m_thumb.MouseY());
m_drag_object.MouseFlags(m_thumb.MouseFlags());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Continue dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollH::OnThumbDragProcess(void)
{
//--- checking
if(m_drag_object==NULL)
return(false);
//--- calculate coordinates
int x=m_drag_object.Left()+CONTROLS_DRAG_SPACING;
int y=m_drag_object.Top()+CONTROLS_DRAG_SPACING;
//--- calculate new position
int new_pos=CalcPos(x);
if(new_pos!=m_curr_pos)
{
ushort event_id=(m_curr_pos<new_pos)?ON_SCROLL_INC:ON_SCROLL_DEC;
m_curr_pos=new_pos;
EventChartCustom(CONTROLS_SELF_MESSAGE,event_id,m_id,0.0,m_name);
}
//--- move thumb
m_thumb.Move(x,y);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| End dragging the "slider" |
//+------------------------------------------------------------------+
bool CScrollH::OnThumbDragEnd(void)
{
if(m_drag_object!=NULL)
{
m_thumb.MouseFlags(m_drag_object.MouseFlags());
delete m_drag_object;
m_drag_object=NULL;
}
//--- succeed
return(m_thumb.Pressed(false));
}
//+------------------------------------------------------------------+
//| Calculate position by coordinate |
//+------------------------------------------------------------------+
int CScrollH::CalcPos(const int coord)
{
//--- calculate new position of the scrollbar
int steps =m_max_pos-m_min_pos; // number of steps to change position
int min_coord=m_dec.Right(); // minimum possible coordinate (corresponds to the m_min_pos value)
int max_coord=m_inc.Left()-m_thumb.Width(); // maximum possible coordinate (corresponds to the m_max_pos value)
//--- checkeng
if(max_coord==min_coord)
return(0);
if(coord<min_coord || coord>max_coord)
return(m_curr_pos);
//---
int new_pos=(int)MathRound((((double)(coord-min_coord))/(max_coord-min_coord))*steps); // new position
//---
return(new_pos);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class CWndClient |
//| Usage: base class to create areas with |
//| the scrollbars |
//+------------------------------------------------------------------+
class CWndClient : public CWndContainer
{
protected:
//--- flags
bool m_v_scrolled; // "vertical scrolling is possible" flag
bool m_h_scrolled; // "horizontal scrolling is possible" flag
//--- dependent controls
CPanel m_background; // the "scrollbar background" object
CScrollV m_scroll_v; // the vertical scrollbar object
CScrollH m_scroll_h; // the horizontal scrollbar object
public:
CWndClient(void);
~CWndClient(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- parameters
virtual bool ColorBackground(const color value) { return(m_background.ColorBackground(value)); }
virtual bool ColorBorder(const color value) { return(m_background.ColorBorder(value)); }
virtual color ColorBackground(void) { return(m_background.ColorBackground()); }
virtual color ColorBorder(void) { return(m_background.ColorBorder()); }
virtual bool BorderType(const ENUM_BORDER_TYPE flag) { return(m_background.BorderType(flag)); }
//--- settings
virtual bool VScrolled(void) { return(m_v_scrolled); }
virtual bool VScrolled(const bool flag);
virtual bool HScrolled(void) { return(m_h_scrolled); }
virtual bool HScrolled(const bool flag);
//--- ID
virtual long Id(const long id);
virtual long Id(void) const { return(CWnd::Id()); }
//--- state
virtual bool Show(void);
protected:
//--- create dependent controls
virtual bool CreateBack(void);
virtual bool CreateScrollV(void);
virtual bool CreateScrollH(void);
//--- internal event handlers
virtual bool OnResize(void);
//--- handlers of the dependent controls events
virtual bool OnVScrollShow(void) { return(true); }
virtual bool OnVScrollHide(void) { return(true); }
virtual bool OnHScrollShow(void) { return(true); }
virtual bool OnHScrollHide(void) { return(true); }
virtual bool OnScrollLineDown(void) { return(true); }
virtual bool OnScrollLineUp(void) { return(true); }
virtual bool OnScrollLineLeft(void) { return(true); }
virtual bool OnScrollLineRight(void) { return(true); }
virtual bool OnClickBackground(void)
{
EventChartCustom(CONTROLS_SELF_MESSAGE, ON_CLICK, m_id, 0.0, m_name);
return true;
}
//--- resize
virtual bool Rebound(const CRect &rect);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CWndClient)
ON_NAMED_EVENT(ON_SHOW,m_scroll_v,OnVScrollShow)
ON_NAMED_EVENT(ON_HIDE,m_scroll_v,OnVScrollHide)
ON_EVENT(ON_SCROLL_DEC,m_scroll_v,OnScrollLineUp)
ON_EVENT(ON_SCROLL_INC,m_scroll_v,OnScrollLineDown)
ON_NAMED_EVENT(ON_SHOW,m_scroll_h,OnHScrollShow)
ON_NAMED_EVENT(ON_HIDE,m_scroll_h,OnHScrollHide)
ON_EVENT(ON_SCROLL_DEC,m_scroll_h,OnScrollLineLeft)
ON_EVENT(ON_SCROLL_INC,m_scroll_h,OnScrollLineRight)
ON_EVENT(ON_CLICK, m_background, OnClickBackground)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CWndClient::CWndClient(void) : m_v_scrolled(false),
m_h_scrolled(false)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CWndClient::~CWndClient(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CWndClient::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call of the method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateBack())
return(false);
if(m_v_scrolled && !CreateScrollV())
return(false);
if(m_h_scrolled && !CreateScrollH())
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create scrollbar background |
//+------------------------------------------------------------------+
bool CWndClient::CreateBack(void)
{
//--- create
if(!m_background.Create(m_chart_id,m_name+"Back",m_subwin,0,0,Width(),Height()))
return(false);
if(!m_background.ColorBorder(CONTROLS_CLIENT_COLOR_BORDER))
return(false);
if(!m_background.ColorBackground(CONTROLS_CLIENT_COLOR_BG))
return(false);
if(!Add(m_background))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create vertical scrollbar |
//+------------------------------------------------------------------+
bool CWndClient::CreateScrollV(void)
{
//--- calculate coordinates
int x1=Width()-CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH;
int x2=Width()-CONTROLS_BORDER_WIDTH;
int y2=Height()-CONTROLS_BORDER_WIDTH;
if(m_h_scrolled) y2-=CONTROLS_SCROLL_SIZE;
//--- create
if(!m_scroll_v.Create(m_chart_id,m_name+"VScroll",m_subwin,x1,y1,x2,y2))
return(false);
if(!Add(m_scroll_v))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create horizontal scrollbar |
//+------------------------------------------------------------------+
bool CWndClient::CreateScrollH(void)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=Height()-CONTROLS_SCROLL_SIZE-CONTROLS_BORDER_WIDTH;
int x2=Width()-CONTROLS_BORDER_WIDTH;
int y2=Height()-CONTROLS_BORDER_WIDTH;
if(m_v_scrolled) x2-=CONTROLS_SCROLL_SIZE;
//--- create
if(!m_scroll_h.Create(m_chart_id,m_name+"HScroll",m_subwin,x1,y1,x2,y2))
return(false);
if(!Add(m_scroll_h))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set up vertical scrollbar |
//+------------------------------------------------------------------+
bool CWndClient::VScrolled(const bool flag)
{
if(m_v_scrolled==flag)
return(true);
//--- there are changes
int d_size=0;
if(flag)
{
//--- create vertical scrollbar
if(!CreateScrollV())
return(false);
//--- need to shorten horizontal scrollbar (if there is one)
d_size=-CONTROLS_SCROLL_SIZE;
}
else
{
//--- delete vertical scrollbar
m_scroll_v.Destroy();
if(!Delete(m_scroll_v))
return(false);
//--- need to lengthen horizontal scrollbar (if there is one)
d_size=CONTROLS_SCROLL_SIZE;
}
m_v_scrolled=flag;
//--- change width of horizontal scrollbar (if there is one)
if(m_h_scrolled)
{
if(!m_scroll_h.Width(m_scroll_h.Width()+d_size))
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set up horizontal scrollbar |
//+------------------------------------------------------------------+
bool CWndClient::HScrolled(const bool flag)
{
if(m_h_scrolled==flag)
return(true);
//--- there are changes
int d_size=0;
if(flag)
{
//--- create horizontal scrollbar
if(!CreateScrollH())
return(false);
//--- need to shorten vertical scrollbar (if there is one)
d_size=-CONTROLS_SCROLL_SIZE;
}
else
{
//--- delete horizontal scrollbar
m_scroll_h.Destroy();
if(!Delete(m_scroll_h))
return(false);
//--- need to lengthen vertical scrollbar (if there is one)
d_size=CONTROLS_SCROLL_SIZE;
}
m_h_scrolled=flag;
//--- change width of vertical scrollbar (if there is one)
if(m_v_scrolled)
{
if(!m_scroll_v.Height(m_scroll_v.Height()+d_size))
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set ID of control |
//+------------------------------------------------------------------+
long CWndClient::Id(const long id)
{
//--- reserve ID for container
long id_used=CWndContainer::Id(id);
//---
if(!m_v_scrolled)
id_used+=m_scroll_v.Id(id+id_used);
if(!m_h_scrolled)
id_used+=m_scroll_h.Id(id+id_used);
//--- return number of used IDs
return(id_used);
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CWndClient::Show(void)
{
//--- call of the method of the parent class
CWndContainer::Show();
//---
if(!m_v_scrolled)
m_scroll_v.Hide();
else
m_scroll_v.Show();
if(!m_h_scrolled)
m_scroll_h.Hide();
else
m_scroll_h.Show();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of resizing |
//+------------------------------------------------------------------+
bool CWndClient::OnResize(void)
{
//--- call of the method of the parent class
if(!CWndContainer::OnResize())
return(false);
//--- resize background
int d_size=0;
m_background.Width(Width());
m_background.Height(Height());
//---
if(m_v_scrolled)
{
//--- move vertical scrollbar
m_scroll_v.Move(Right()-CONTROLS_SCROLL_SIZE,Top());
//--- modify vertical scrollbar
d_size=(m_h_scrolled) ? CONTROLS_SCROLL_SIZE : 0;
m_scroll_v.Height(Height()-d_size);
}
if(m_h_scrolled)
{
//--- move horizontal scrollbar
m_scroll_h.Move(Left(),Bottom()-CONTROLS_SCROLL_SIZE);
//--- modify horizontal scrollbar
d_size=(m_v_scrolled) ? CONTROLS_SCROLL_SIZE : 0;
m_scroll_h.Width(Width()-d_size);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Resize |
//+------------------------------------------------------------------+
bool CWndClient::Rebound(const CRect &rect)
{
m_rect.SetBound(rect);
//--- call virtual event handler
return(OnResize());
}
//+------------------------------------------------------------------+
//#include "Panel.mqh"
//#include "Edit.mqh"
//+------------------------------------------------------------------+
//| Edit.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndObj.mqh"
//#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| Class CEdit |
//| Usage: control that is displayed by |
//| the CChartObjectEdit object |
//+------------------------------------------------------------------+
class CEdit : public CWndObj
{
private:
CChartObjectEdit m_edit; // chart object
//--- parameters of the chart object
bool m_read_only; // "read-only" mode flag
ENUM_ALIGN_MODE m_align_mode; // align mode
public:
CEdit(void);
~CEdit(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- parameters of the chart object
bool ReadOnly(void) const { return(m_read_only); }
bool ReadOnly(const bool flag);
ENUM_ALIGN_MODE TextAlign(void) const { return(m_align_mode); }
bool TextAlign(const ENUM_ALIGN_MODE align);
//--- data access
string Text(void) const { return(m_edit.Description()); }
bool Text(const string value) { return(CWndObj::Text(value)); }
protected:
//--- handlers of object events
virtual bool OnObjectEndEdit(void);
//--- handlers of object settings
virtual bool OnSetText(void) { return(m_edit.Description(m_text)); }
virtual bool OnSetColor(void) { return(m_edit.Color(m_color)); }
virtual bool OnSetColorBackground(void) { return(m_edit.BackColor(m_color_background)); }
virtual bool OnSetColorBorder(void) { return(m_edit.BorderColor(m_color_border)); }
virtual bool OnSetFont(void) { return(m_edit.Font(m_font)); }
virtual bool OnSetFontSize(void) { return(m_edit.FontSize(m_font_size)); }
virtual bool OnSetZOrder(void) { return(m_edit.Z_Order(m_zorder)); }
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
virtual bool OnResize(void);
virtual bool OnChange(void);
virtual bool OnClick(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
bool CEdit::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
if(m_name==sparam && id==CHARTEVENT_OBJECT_ENDEDIT)
return(OnObjectEndEdit());
//--- event was not handled
return(CWndObj::OnEvent(id,lparam,dparam,sparam));
}
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CEdit::CEdit(void) : m_read_only(false),
m_align_mode(ALIGN_LEFT)
{
m_color =CONTROLS_EDIT_COLOR;
m_color_background=CONTROLS_EDIT_COLOR_BG;
m_color_border =CONTROLS_EDIT_COLOR_BORDER;
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CEdit::~CEdit(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CEdit::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_edit.Create(chart,name,subwin,x1,y1,Width(),Height()))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Set parameter |
//+------------------------------------------------------------------+
bool CEdit::ReadOnly(const bool flag)
{
//--- save new value of parameter
m_read_only=flag;
//--- set up the chart object
return(m_edit.ReadOnly(flag));
}
//+------------------------------------------------------------------+
//| Set parameter |
//+------------------------------------------------------------------+
bool CEdit::TextAlign(const ENUM_ALIGN_MODE align)
{
//--- save new value of parameter
m_align_mode=align;
//--- set up the chart object
return(m_edit.TextAlign(align));
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CEdit::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_edit.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CEdit::OnShow(void)
{
return(m_edit.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CEdit::OnHide(void)
{
return(m_edit.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CEdit::OnMove(void)
{
//--- position the chart object
return(m_edit.X_Distance(m_rect.left) && m_edit.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
//| Resize the chart object |
//+------------------------------------------------------------------+
bool CEdit::OnResize(void)
{
//--- resize the chart object
return(m_edit.X_Size(m_rect.Width()) && m_edit.Y_Size(m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Set up the chart object |
//+------------------------------------------------------------------+
bool CEdit::OnChange(void)
{
//--- set up the chart object
return(CWndObj::OnChange() && ReadOnly(m_read_only) && TextAlign(m_align_mode));
}
//+------------------------------------------------------------------+
//| Handler of the "End of editing" event |
//+------------------------------------------------------------------+
bool CEdit::OnObjectEndEdit(void)
{
//--- send the ON_END_EDIT notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_END_EDIT,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "click" event |
//+------------------------------------------------------------------+
bool CEdit::OnClick(void)
{
//--- if editing is enabled, send the ON_START_EDIT notification
if(!m_read_only)
{
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_START_EDIT,m_id,0.0,m_name);
//--- handled
//return(true);
}
//--- else send the ON_CLICK notification
return(CWnd::OnClick());
}
//+------------------------------------------------------------------+
//#include "BmpButton.mqh"
//#include <Charts\Chart.mqh>
//+------------------------------------------------------------------+
//| Chart.mqh |
//| Copyright 2009-2016, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include <Object.mqh>
//+------------------------------------------------------------------+
//| Class CChart. |
//| Purpose: Class of the "Chart" object. |
//| Derives from class CObject. |
//+------------------------------------------------------------------+
class CChart : public CObject
{
protected:
long m_chart_id; // chart identifier
public:
CChart(void);
~CChart(void);
//--- methods of access to protected data
long ChartId(void) const { return(m_chart_id); }
//--- method of identifying the object
virtual int Type(void) const { return(0x1111); }
//--- methods of access to properties of the chart
//--- common properties
ENUM_CHART_MODE Mode(void) const;
bool Mode(const ENUM_CHART_MODE mode) const;
bool Foreground(void) const;
bool Foreground(const bool foreground) const;
bool Shift(void) const;
bool Shift(const bool shift) const;
double ShiftSize(void) const;
bool ShiftSize(double shift) const;
bool AutoScroll(void) const;
bool AutoScroll(const bool auto_scroll) const;
int Scale(void) const;
bool Scale(int scale) const;
bool ScaleFix(void) const;
bool ScaleFix(const bool scale_fix) const;
bool ScaleFix_11(void) const;
bool ScaleFix_11(const bool scale_fix_11) const;
double FixedMax(void) const;
bool FixedMax(const double fixed_max) const;
double FixedMin(void) const;
bool FixedMin(const double fixed_min) const;
bool ScalePPB(void) const;
bool ScalePPB(const bool scale_ppb) const;
double PointsPerBar(void) const;
bool PointsPerBar(const double points_per_bar) const;
//--- show properties
bool ShowOHLC(void) const;
bool ShowOHLC(const bool show) const;
bool ShowLineBid(void) const;
bool ShowLineBid(const bool show) const;
bool ShowLineAsk(void) const;
bool ShowLineAsk(const bool show) const;
bool ShowLastLine(void) const;
bool ShowLastLine(const bool show) const;
bool ShowPeriodSep(void) const;
bool ShowPeriodSep(const bool show) const;
bool ShowGrid(void) const;
bool ShowGrid(const bool show) const;
ENUM_CHART_VOLUME_MODE ShowVolumes(void) const;
bool ShowVolumes(const ENUM_CHART_VOLUME_MODE show) const;
bool ShowObjectDescr(void) const;
bool ShowObjectDescr(const bool show) const;
bool ShowDateScale(const bool show) const;
bool ShowPriceScale(const bool show) const;
//--- color properties
color ColorBackground(void) const;
bool ColorBackground(const color new_color) const;
color ColorForeground(void) const;
bool ColorForeground(const color new_color) const;
color ColorGrid(void) const;
bool ColorGrid(const color new_color) const;
color ColorBarUp(void) const;
bool ColorBarUp(const color new_color) const;
color ColorBarDown(void) const;
bool ColorBarDown(const color new_color) const;
color ColorCandleBull(void) const;
bool ColorCandleBull(const color new_color) const;
color ColorCandleBear(void) const;
bool ColorCandleBear(const color new_color) const;
color ColorChartLine(void) const;
bool ColorChartLine(const color new_color) const;
color ColorVolumes(void) const;
bool ColorVolumes(const color new_color) const;
color ColorLineBid(void) const;
bool ColorLineBid(const color new_color) const;
color ColorLineAsk(void) const;
bool ColorLineAsk(const color new_color) const;
color ColorLineLast(void) const;
bool ColorLineLast(const color new_color) const;
color ColorStopLevels(void) const;
bool ColorStopLevels(const color new_color) const;
//--- other properties
bool BringToTop(void) const;
bool EventObjectCreate(const bool flag=true) const;
bool EventObjectDelete(const bool flag=true) const;
bool EventMouseMove(const bool flag=true) const;
bool MouseScroll(const bool flag=true) const;
//--- methods of access to READ ONLY properties of the chart
int VisibleBars(void) const;
int WindowsTotal(void) const;
bool WindowIsVisible(const int num) const;
int WindowHandle(void) const;
int FirstVisibleBar(void) const;
int WidthInBars(void) const;
int WidthInPixels(void) const;
int HeightInPixels(const int num) const;
int SubwindowY(const int num) const;
double PriceMin(const int num) const;
double PriceMax(const int num) const;
bool IsObject(void) const;
//--- methods of binding chart
void Attach(void) { m_chart_id=ChartID(); }
void Attach(const long chart) { m_chart_id=chart; }
void FirstChart(void) { m_chart_id=ChartFirst(); }
void NextChart(void) { m_chart_id=ChartNext(m_chart_id); }
long Open(const string symbol_name,const ENUM_TIMEFRAMES timeframe);
void Detach(void) { m_chart_id=-1; }
void Close(void);
//--- navigation method
bool Navigate(const ENUM_CHART_POSITION position,const int shift=0) const;
//--- methods of access to the API functions of MQL5
string Symbol(void) const { return(ChartSymbol(m_chart_id)); }
ENUM_TIMEFRAMES Period(void) const { return(ChartPeriod(m_chart_id)); }
void Redraw(void) const { ChartRedraw(m_chart_id); }
long GetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const int sub_window=0) const;
bool GetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const int sub_window,long &value) const;
bool SetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const long value) const;
double GetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const int sub_window=0) const;
bool GetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const int sub_window,double &value) const;
bool SetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const double value) const;
string GetString(const ENUM_CHART_PROPERTY_STRING prop_id) const;
bool GetString(const ENUM_CHART_PROPERTY_STRING prop_id,string &value) const;
bool SetString(const ENUM_CHART_PROPERTY_STRING prop_id,const string value) const;
bool SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period) const;
bool ApplyTemplate(const string filename) const;
bool ScreenShot(const string filename,const int width,const int height,
const ENUM_ALIGN_MODE align_mode=ALIGN_RIGHT) const;
int WindowOnDropped(void) const;
double PriceOnDropped(void) const;
datetime TimeOnDropped(void) const;
int XOnDropped(void) const;
int YOnDropped(void) const;
//--- methods for working with indicators
bool IndicatorAdd(const int subwin,const int handle) const;
bool IndicatorDelete(const int subwin,const string name) const;
int IndicatorsTotal(const int subwin) const;
string IndicatorName(const int subwin,const int index) const;
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChart::CChart(void) : m_chart_id(-1)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChart::~CChart(void)
{
if(m_chart_id!=-1)
Close();
}
//+------------------------------------------------------------------+
//| Opening chart |
//+------------------------------------------------------------------+
long CChart::Open(const string symbol_name,const ENUM_TIMEFRAMES timeframe)
{
m_chart_id=ChartOpen(symbol_name,timeframe);
if(m_chart_id==0)
m_chart_id=-1;
return(m_chart_id);
}
//+------------------------------------------------------------------+
//| Get the type of representation of chart |
//+------------------------------------------------------------------+
ENUM_CHART_MODE CChart::Mode(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_CHART_MODE)ChartGetInteger(m_chart_id,CHART_MODE));
}
//+------------------------------------------------------------------+
//| Set the type of representation chart |
//+------------------------------------------------------------------+
bool CChart::Mode(const ENUM_CHART_MODE mode) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_MODE,mode));
}
//+------------------------------------------------------------------+
//| Get value of the "Foreground" property |
//+------------------------------------------------------------------+
bool CChart::Foreground(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_FOREGROUND));
}
//+------------------------------------------------------------------+
//| Set value of the "Foreground" property |
//+------------------------------------------------------------------+
bool CChart::Foreground(const bool foreground) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_FOREGROUND,foreground));
}
//+------------------------------------------------------------------+
//| Get value of the "Shift" property |
//+------------------------------------------------------------------+
bool CChart::Shift(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SHIFT));
}
//+------------------------------------------------------------------+
//| Set value of the "Shift"property |
//+------------------------------------------------------------------+
bool CChart::Shift(const bool shift) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHIFT,shift));
}
//+------------------------------------------------------------------+
//| Get value of the "ShiftSize" property |
//+------------------------------------------------------------------+
double CChart::ShiftSize(void) const
{
//--- check
if(m_chart_id==-1)
return(DBL_MAX);
//--- result
return(ChartGetDouble(m_chart_id,CHART_SHIFT_SIZE));
}
//+------------------------------------------------------------------+
//| Set value of the "ShiftSize" property |
//+------------------------------------------------------------------+
bool CChart::ShiftSize(double shift) const
{
//--- check
if(m_chart_id==-1)
return(false);
if(shift<10)
shift=10;
if(shift>50)
shift=50;
//--- result
return(ChartSetDouble(m_chart_id,CHART_SHIFT_SIZE,shift));
}
//+------------------------------------------------------------------+
//| Get value of the "AutoScroll" property |
//+------------------------------------------------------------------+
bool CChart::AutoScroll(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_AUTOSCROLL));
}
//+------------------------------------------------------------------+
//| Set value of the "AutoScroll" property |
//+------------------------------------------------------------------+
bool CChart::AutoScroll(const bool auto_scroll) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_AUTOSCROLL,auto_scroll));
}
//+------------------------------------------------------------------+
//| Get value of the "Scale" property |
//+------------------------------------------------------------------+
int CChart::Scale(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ChartGetInteger(m_chart_id,CHART_SCALE));
}
//+------------------------------------------------------------------+
//| Set value of the "Scale" property |
//+------------------------------------------------------------------+
bool CChart::Scale(int shift) const
{
//--- check
if(m_chart_id==-1)
return(false);
if(shift<0)
shift=0;
if(shift>32)
shift=32;
//--- result
return(ChartSetInteger(m_chart_id,CHART_SCALE,shift));
}
//+------------------------------------------------------------------+
//| Get value of the "ScaleFix" property |
//+------------------------------------------------------------------+
bool CChart::ScaleFix(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SCALEFIX));
}
//+------------------------------------------------------------------+
//| Set value of the "ScaleFix" property |
//+------------------------------------------------------------------+
bool CChart::ScaleFix(const bool scale_fix) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SCALEFIX,scale_fix));
}
//+------------------------------------------------------------------+
//| Get value of the "ScaleFix_11" property |
//+------------------------------------------------------------------+
bool CChart::ScaleFix_11(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SCALEFIX_11));
}
//+------------------------------------------------------------------+
//| Set value of the "ScaleFix_11" property |
//+------------------------------------------------------------------+
bool CChart::ScaleFix_11(const bool scale_fix_11) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SCALEFIX_11,scale_fix_11));
}
//+------------------------------------------------------------------+
//| Get value of the "FixedMax" property |
//+------------------------------------------------------------------+
double CChart::FixedMax(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ChartGetDouble(m_chart_id,CHART_FIXED_MAX));
}
//+------------------------------------------------------------------+
//| Set value of the "FixedMax" property |
//+------------------------------------------------------------------+
bool CChart::FixedMax(const double fixed_max) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetDouble(m_chart_id,CHART_FIXED_MAX,fixed_max));
}
//+------------------------------------------------------------------+
//| Get value of the "FixedMin" property |
//+------------------------------------------------------------------+
double CChart::FixedMin(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ChartGetDouble(m_chart_id,CHART_FIXED_MIN));
}
//+------------------------------------------------------------------+
//| Set value of the "FixedMin" property |
//+------------------------------------------------------------------+
bool CChart::FixedMin(const double fixed_min) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetDouble(m_chart_id,CHART_FIXED_MIN,fixed_min));
}
//+------------------------------------------------------------------+
//| Get value of the "ScalePointsPerBar" property |
//+------------------------------------------------------------------+
bool CChart::ScalePPB(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SCALE_PT_PER_BAR));
}
//+------------------------------------------------------------------+
//| Set value of the "ScalePointsPerBar" property |
//+------------------------------------------------------------------+
bool CChart::ScalePPB(const bool scale_ppb) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SCALE_PT_PER_BAR,scale_ppb));
}
//+------------------------------------------------------------------+
//| Get value of the "PointsPerBar" property |
//+------------------------------------------------------------------+
double CChart::PointsPerBar(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ChartGetDouble(m_chart_id,CHART_POINTS_PER_BAR));
}
//+------------------------------------------------------------------+
//| Set value of the "PointsPerBar" property |
//+------------------------------------------------------------------+
bool CChart::PointsPerBar(const double points_per_bar) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetDouble(m_chart_id,CHART_POINTS_PER_BAR,points_per_bar));
}
//+------------------------------------------------------------------+
//| Get value of the "ShowOHLC" property |
//+------------------------------------------------------------------+
bool CChart::ShowOHLC(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SHOW_OHLC));
}
//+------------------------------------------------------------------+
//| Set value of the "ShowOHLC" property |
//+------------------------------------------------------------------+
bool CChart::ShowOHLC(const bool show) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHOW_OHLC,show));
}
//+------------------------------------------------------------------+
//| Get value of the "ShowLineBid" property |
//+------------------------------------------------------------------+
bool CChart::ShowLineBid(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SHOW_BID_LINE));
}
//+------------------------------------------------------------------+
//| Set value of the "ShowLineBid" property |
//+------------------------------------------------------------------+
bool CChart::ShowLineBid(const bool show) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHOW_BID_LINE,show));
}
//+------------------------------------------------------------------+
//| Get value of the "ShowLineAsk" property |
//+------------------------------------------------------------------+
bool CChart::ShowLineAsk(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SHOW_ASK_LINE));
}
//+------------------------------------------------------------------+
//| Set value of the "ShowLineAsk" property |
//+------------------------------------------------------------------+
bool CChart::ShowLineAsk(const bool show) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHOW_ASK_LINE,show));
}
//+------------------------------------------------------------------+
//| Get value of the "ShowLastLine" property |
//+------------------------------------------------------------------+
bool CChart::ShowLastLine(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SHOW_LAST_LINE));
}
//+------------------------------------------------------------------+
//| Set value of the "ShowLastLine" property |
//+------------------------------------------------------------------+
bool CChart::ShowLastLine(const bool show) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHOW_LAST_LINE,show));
}
//+------------------------------------------------------------------+
//| Get value of the "ShowPeriodSep" property |
//+------------------------------------------------------------------+
bool CChart::ShowPeriodSep(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP));
}
//+------------------------------------------------------------------+
//| Set value of the "ShowPeriodSep" property |
//+------------------------------------------------------------------+
bool CChart::ShowPeriodSep(const bool show) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP,show));
}
//+------------------------------------------------------------------+
//| Get value of the "ShowGrid" property |
//+------------------------------------------------------------------+
bool CChart::ShowGrid(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SHOW_GRID));
}
//+------------------------------------------------------------------+
//| Set value of the "ShowGrid" property |
//+------------------------------------------------------------------+
bool CChart::ShowGrid(const bool show) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHOW_GRID,show));
}
//+------------------------------------------------------------------+
//| Get value of the "ShowVolumes" property |
//+------------------------------------------------------------------+
ENUM_CHART_VOLUME_MODE CChart::ShowVolumes(void) const
{
//--- check
if(m_chart_id==-1)
return(WRONG_VALUE);
//--- result
return((ENUM_CHART_VOLUME_MODE)ChartGetInteger(m_chart_id,CHART_SHOW_VOLUMES));
}
//+------------------------------------------------------------------+
//| Set value of the "ShowVolumes" property |
//+------------------------------------------------------------------+
bool CChart::ShowVolumes(const ENUM_CHART_VOLUME_MODE show) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHOW_VOLUMES,show));
}
//+------------------------------------------------------------------+
//| Get value of the "ShowObjectDescr" property |
//+------------------------------------------------------------------+
bool CChart::ShowObjectDescr(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR));
}
//+------------------------------------------------------------------+
//| Set value of the "ShowObjectDescr" property |
//+------------------------------------------------------------------+
bool CChart::ShowObjectDescr(const bool show) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR,show));
}
//+------------------------------------------------------------------+
//| Set value of the "ShowDateScale" property |
//+------------------------------------------------------------------+
bool CChart::ShowDateScale(const bool show) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHOW_DATE_SCALE,show));
}
//+------------------------------------------------------------------+
//| Set value of the "ShowPriceScale" property |
//+------------------------------------------------------------------+
bool CChart::ShowPriceScale(const bool show) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_SHOW_PRICE_SCALE,show));
}
//+------------------------------------------------------------------+
//| Get color value of the "Background" property |
//+------------------------------------------------------------------+
color CChart::ColorBackground(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_BACKGROUND));
}
//+------------------------------------------------------------------+
//| Set color value of the "Background" property |
//+------------------------------------------------------------------+
bool CChart::ColorBackground(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_BACKGROUND,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Foreground" property |
//+------------------------------------------------------------------+
color CChart::ColorForeground(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_FOREGROUND));
}
//+------------------------------------------------------------------+
//| Set color value for the "Foreground" property |
//+------------------------------------------------------------------+
bool CChart::ColorForeground(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_FOREGROUND,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Grid" property |
//+------------------------------------------------------------------+
color CChart::ColorGrid(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_GRID));
}
//+------------------------------------------------------------------+
//| Set color value for the "Grid" property |
//+------------------------------------------------------------------+
bool CChart::ColorGrid(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_GRID,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Bar Up" property |
//+------------------------------------------------------------------+
color CChart::ColorBarUp(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_CHART_UP));
}
//+------------------------------------------------------------------+
//| Set color value of the "Bar Up" property |
//+------------------------------------------------------------------+
bool CChart::ColorBarUp(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_CHART_UP,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Bar Down" property |
//+------------------------------------------------------------------+
color CChart::ColorBarDown(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_CHART_DOWN));
}
//+------------------------------------------------------------------+
//| Set color value of the "Bar Down" property |
//+------------------------------------------------------------------+
bool CChart::ColorBarDown(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_CHART_DOWN,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Candle Bull" property |
//+------------------------------------------------------------------+
color CChart::ColorCandleBull(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_CANDLE_BULL));
}
//+------------------------------------------------------------------+
//| Set color value of the "Candle Bull" property |
//+------------------------------------------------------------------+
bool CChart::ColorCandleBull(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_CANDLE_BULL,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Candle Bear" property |
//+------------------------------------------------------------------+
color CChart::ColorCandleBear(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_CANDLE_BEAR));
}
//+------------------------------------------------------------------+
//| Set color value of the "Candle Bear" property |
//+------------------------------------------------------------------+
bool CChart::ColorCandleBear(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_CANDLE_BEAR,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Chart Line" property |
//+------------------------------------------------------------------+
color CChart::ColorChartLine(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_CHART_LINE));
}
//+------------------------------------------------------------------+
//| Set color value of the "Chart Line" property |
//+------------------------------------------------------------------+
bool CChart::ColorChartLine(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_CHART_LINE,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Volumes" property |
//+------------------------------------------------------------------+
color CChart::ColorVolumes(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_VOLUME));
}
//+------------------------------------------------------------------+
//| Set color value of the "Volumes" property |
//+------------------------------------------------------------------+
bool CChart::ColorVolumes(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_VOLUME,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Line Bid" property |
//+------------------------------------------------------------------+
color CChart::ColorLineBid(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_BID));
}
//+------------------------------------------------------------------+
//| Set color value of the "Line Bid" property |
//+------------------------------------------------------------------+
bool CChart::ColorLineBid(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_BID,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Line Ask" property |
//+------------------------------------------------------------------+
color CChart::ColorLineAsk(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_ASK));
}
//+------------------------------------------------------------------+
//| Set color value of the "Line Ask" property |
//+------------------------------------------------------------------+
bool CChart::ColorLineAsk(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_ASK,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Line Last" property |
//+------------------------------------------------------------------+
color CChart::ColorLineLast(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_LAST));
}
//+------------------------------------------------------------------+
//| Set color value of the "Line Last" property |
//+------------------------------------------------------------------+
bool CChart::ColorLineLast(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_LAST,new_color));
}
//+------------------------------------------------------------------+
//| Get color value of the "Stop Levels" property |
//+------------------------------------------------------------------+
color CChart::ColorStopLevels(void) const
{
//--- check
if(m_chart_id==-1)
return(CLR_NONE);
//--- result
return((color)ChartGetInteger(m_chart_id,CHART_COLOR_STOP_LEVEL));
}
//+------------------------------------------------------------------+
//| Set color value of the "Stop Levels" property |
//+------------------------------------------------------------------+
bool CChart::ColorStopLevels(const color new_color) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_COLOR_STOP_LEVEL,new_color));
}
//+------------------------------------------------------------------+
//| Shows chart always on top |
//+------------------------------------------------------------------+
bool CChart::BringToTop(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_BRING_TO_TOP,true));
}
//+------------------------------------------------------------------+
//| Sets flag to generate event of creating objects |
//+------------------------------------------------------------------+
bool CChart::EventObjectCreate(const bool flag) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_EVENT_OBJECT_CREATE,flag));
}
//+------------------------------------------------------------------+
//| Sets flag to generate event of deleting objects |
//+------------------------------------------------------------------+
bool CChart::EventObjectDelete(const bool flag) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_EVENT_OBJECT_DELETE,flag));
}
//+------------------------------------------------------------------+
//| Sets flag to generate event of moving mouse cursor |
//+------------------------------------------------------------------+
bool CChart::EventMouseMove(const bool flag) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_EVENT_MOUSE_MOVE,flag));
}
//+------------------------------------------------------------------+
//| Sets flag to mouse scrolling |
//+------------------------------------------------------------------+
bool CChart::MouseScroll(const bool flag) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetInteger(m_chart_id,CHART_MOUSE_SCROLL,flag));
}
//+------------------------------------------------------------------+
//| Get value of the "VisibleBars" property |
//+------------------------------------------------------------------+
int CChart::VisibleBars(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ChartGetInteger(m_chart_id,CHART_WIDTH_IN_BARS));
}
//+------------------------------------------------------------------+
//| Get value of the "WindowsTotal" property |
//+------------------------------------------------------------------+
int CChart::WindowsTotal(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ChartGetInteger(m_chart_id,CHART_WINDOWS_TOTAL));
}
//+------------------------------------------------------------------+
//| Get value of the "WindowIsVisible" property |
//+------------------------------------------------------------------+
bool CChart::WindowIsVisible(const int num) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_WINDOW_IS_VISIBLE,num));
}
//+------------------------------------------------------------------+
//| Get value of the "WindowHandle" property |
//+------------------------------------------------------------------+
int CChart::WindowHandle(void) const
{
//--- check
if(m_chart_id==-1)
return(INVALID_HANDLE);
//--- result
return((int)ChartGetInteger(m_chart_id,CHART_WINDOW_HANDLE));
}
//+------------------------------------------------------------------+
//| Get value of the "FirstVisibleBar" property |
//+------------------------------------------------------------------+
int CChart::FirstVisibleBar(void) const
{
//--- check
if(m_chart_id==-1)
return(-1);
//--- result
return((int)ChartGetInteger(m_chart_id,CHART_FIRST_VISIBLE_BAR));
}
//+------------------------------------------------------------------+
//| Get value of the "WidthInBars" property |
//+------------------------------------------------------------------+
int CChart::WidthInBars(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ChartGetInteger(m_chart_id,CHART_WIDTH_IN_BARS));
}
//+------------------------------------------------------------------+
//| Get value of the "WidthInPixels" property |
//+------------------------------------------------------------------+
int CChart::WidthInPixels(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ChartGetInteger(m_chart_id,CHART_WIDTH_IN_PIXELS));
}
//+------------------------------------------------------------------+
//| Get value of the "HeightInPixels" property |
//+------------------------------------------------------------------+
int CChart::HeightInPixels(const int num) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ChartGetInteger(m_chart_id,CHART_HEIGHT_IN_PIXELS,num));
}
//+------------------------------------------------------------------+
//| Get value of the "WindowYDistance" property |
//+------------------------------------------------------------------+
int CChart::SubwindowY(const int num) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return((int)ChartGetInteger(m_chart_id,CHART_WINDOW_YDISTANCE,num));
}
//+------------------------------------------------------------------+
//| Get value of the "PriceMin" property |
//+------------------------------------------------------------------+
double CChart::PriceMin(const int num) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ChartGetDouble(m_chart_id,CHART_PRICE_MIN,num));
}
//+------------------------------------------------------------------+
//| Get value of the "PriceMax" property |
//+------------------------------------------------------------------+
double CChart::PriceMax(const int num) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ChartGetDouble(m_chart_id,CHART_PRICE_MAX,num));
}
//+------------------------------------------------------------------+
//| Get value of the "IsObject" property |
//+------------------------------------------------------------------+
bool CChart::IsObject(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return((bool)ChartGetInteger(m_chart_id,CHART_IS_OBJECT));
}
//+------------------------------------------------------------------+
//| Chart close |
//+------------------------------------------------------------------+
void CChart::Close(void)
{
if(m_chart_id!=-1)
{
ChartClose(m_chart_id);
m_chart_id=-1;
}
}
//+------------------------------------------------------------------+
//| Chart navigation |
//+------------------------------------------------------------------+
bool CChart::Navigate(const ENUM_CHART_POSITION position,const int shift) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartNavigate(m_chart_id,position,shift));
}
//+------------------------------------------------------------------+
//| Access functions long ChartGetInteger(...) |
//+------------------------------------------------------------------+
long CChart::GetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const int subwindow) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return(ChartGetInteger(m_chart_id,prop_id,subwindow));
}
//+------------------------------------------------------------------+
//| Access function bool ChartGetInteger(...) |
//+------------------------------------------------------------------+
bool CChart::GetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const int subwindow,long &value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartGetInteger(m_chart_id,prop_id,subwindow,value));
}
//+------------------------------------------------------------------+
//| Access function ChartSetInteger(...) |
//+------------------------------------------------------------------+
bool CChart::SetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const long value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//---
return(ChartSetInteger(m_chart_id,prop_id,value));
}
//+------------------------------------------------------------------+
//| Access function double ChartGetDouble(...) |
//+------------------------------------------------------------------+
double CChart::GetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const int subwindow) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ChartGetDouble(m_chart_id,prop_id,subwindow));
}
//+------------------------------------------------------------------+
//| Access function bool ChartGetDouble(...) |
//+------------------------------------------------------------------+
bool CChart::GetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const int subwindow,double &value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartGetDouble(m_chart_id,prop_id,subwindow,value));
}
//+------------------------------------------------------------------+
//| Access function ChartSetDouble(...) |
//+------------------------------------------------------------------+
bool CChart::SetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const double value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetDouble(m_chart_id,prop_id,value));
}
//+------------------------------------------------------------------+
//| Access function string ChartGetString(...) |
//+------------------------------------------------------------------+
string CChart::GetString(const ENUM_CHART_PROPERTY_STRING prop_id) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ChartGetString(m_chart_id,prop_id));
}
//+------------------------------------------------------------------+
//| Access functions bool ChartGetString(...) |
//+------------------------------------------------------------------+
bool CChart::GetString(const ENUM_CHART_PROPERTY_STRING prop_id,string &value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartGetString(m_chart_id,prop_id,value));
}
//+------------------------------------------------------------------+
//| Access function ChartSetString(...) |
//+------------------------------------------------------------------+
bool CChart::SetString(const ENUM_CHART_PROPERTY_STRING prop_id,const string value) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetString(m_chart_id,prop_id,value));
}
//+------------------------------------------------------------------+
//| Access function ChartSetSymbolPeriod(...) |
//+------------------------------------------------------------------+
bool CChart::SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartSetSymbolPeriod(m_chart_id,symbol,period));
}
//+------------------------------------------------------------------+
//| Access function ChartApplyTemplate(...) |
//+------------------------------------------------------------------+
bool CChart::ApplyTemplate(const string filename) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartApplyTemplate(m_chart_id,filename));
}
//+------------------------------------------------------------------+
//| Access function ChartScreenShot(...) |
//+------------------------------------------------------------------+
bool CChart::ScreenShot(const string filename,const int width,const int height,const ENUM_ALIGN_MODE align_mode) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartScreenShot(m_chart_id,filename,width,height,align_mode));
}
//+------------------------------------------------------------------+
//| Access function WindowOnDropped() |
//+------------------------------------------------------------------+
int CChart::WindowOnDropped(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return(ChartWindowOnDropped());
}
//+------------------------------------------------------------------+
//| Access function PriceOnDropped() |
//+------------------------------------------------------------------+
double CChart::PriceOnDropped(void) const
{
//--- check
if(m_chart_id==-1)
return(EMPTY_VALUE);
//--- result
return(ChartPriceOnDropped());
}
//+------------------------------------------------------------------+
//| Access function TimeOnDropped() |
//+------------------------------------------------------------------+
datetime CChart::TimeOnDropped(void) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartTimeOnDropped());
}
//+------------------------------------------------------------------+
//| Access functions XOnDropped() |
//+------------------------------------------------------------------+
int CChart::XOnDropped(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return(ChartXOnDropped());
}
//+------------------------------------------------------------------+
//| Access functions YOnDropped() |
//+------------------------------------------------------------------+
int CChart::YOnDropped(void) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return(ChartYOnDropped());
}
//+------------------------------------------------------------------+
//| Adds indicator to chart |
//+------------------------------------------------------------------+
bool CChart::IndicatorAdd(const int subwin,const int handle) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartIndicatorAdd(m_chart_id,subwin,handle));
}
//+------------------------------------------------------------------+
//| Deletes indicator from chart |
//+------------------------------------------------------------------+
bool CChart::IndicatorDelete(const int subwin,const string name) const
{
//--- check
if(m_chart_id==-1)
return(false);
//--- result
return(ChartIndicatorDelete(m_chart_id,subwin,name));
}
//+------------------------------------------------------------------+
//| Gets number of indicators in chart subwindow |
//+------------------------------------------------------------------+
int CChart::IndicatorsTotal(const int subwin) const
{
//--- check
if(m_chart_id==-1)
return(0);
//--- result
return(ChartIndicatorsTotal(m_chart_id,subwin));
}
//+------------------------------------------------------------------+
//| Gets short name of indicator |
//+------------------------------------------------------------------+
string CChart::IndicatorName(const int subwin,const int index) const
{
//--- check
if(m_chart_id==-1)
return("");
//--- result
return(ChartIndicatorName(m_chart_id,subwin,index));
}
//+------------------------------------------------------------------+
//| Writing parameters of chart to file |
//+------------------------------------------------------------------+
bool CChart::Save(const int file_handle)
{
string work_str;
int work_int;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- write start marker - 0xFFFFFFFFFFFFFFFF
if(FileWriteLong(file_handle,-1)!=sizeof(long))
return(false);
//--- write chart type
if(FileWriteInteger(file_handle,Type(),INT_VALUE)!=INT_VALUE)
return(false);
//--- write chart symbol
work_str=Symbol();
work_int=StringLen(work_str);
if(FileWriteInteger(file_handle,work_int,INT_VALUE)!=INT_VALUE)
return(false);
if(work_int!=0) if(FileWriteString(file_handle,work_str,work_int)!=work_int)
return(false);
//--- write period of chart
if(FileWriteInteger(file_handle,Period(),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Mode" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_MODE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "Foreground" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_FOREGROUND),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "Shift" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHIFT),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "ShiftSize" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHIFT),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "AutoScroll" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_AUTOSCROLL),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "Scale" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SCALE),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "ScaleFix" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SCALEFIX),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "ScaleFix_11" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SCALEFIX_11),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "FixedMax" property
if(FileWriteDouble(file_handle,ChartGetDouble(m_chart_id,CHART_FIXED_MAX))!=sizeof(double))
return(false);
//--- write value of the "FixedMin" property
if(FileWriteDouble(file_handle,ChartGetDouble(m_chart_id,CHART_FIXED_MIN))!=sizeof(double))
return(false);
//--- write the "ScalePPB" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SCALE_PT_PER_BAR),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "PointsPerBar" property
if(FileWriteDouble(file_handle,ChartGetDouble(m_chart_id,CHART_POINTS_PER_BAR))!=sizeof(double))
return(false);
//--- write value of the "ShowOHLC" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_OHLC),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "ShowLineBid" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_BID_LINE),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "ShowLineAsk" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_ASK_LINE),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "ShowLastLine" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_LAST_LINE),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "ShowPeriodSep" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "ShowGrid" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_GRID),CHAR_VALUE)!=sizeof(char))
return(false);
//--- write value of the "ShowVolumes" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_VOLUMES),INT_VALUE)!=sizeof(int))
return(false);
//--- write value of the "ShowObjectDescr" property
if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR),CHAR_VALUE)!=sizeof(char))
return(false);
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Reading parameters of chart from file |
//+------------------------------------------------------------------+
bool CChart::Load(const int file_handle)
{
bool resutl=true;
string work_str;
int work_int;
//--- check
if(file_handle==INVALID_HANDLE || m_chart_id==-1)
return(false);
//--- read and checking start marker - 0xFFFFFFFFFFFFFFFF
if(FileReadLong(file_handle)!=-1) return(false);
//--- read and checking chart type
if(FileReadInteger(file_handle,INT_VALUE)!=Type()) return(false);
//--- read chart symbol
work_int=FileReadInteger(file_handle);
if(work_int!=0) work_str=FileReadString(file_handle,work_int);
else work_str="";
//--- read chart period
work_int=FileReadInteger(file_handle);
SetSymbolPeriod(work_str,(ENUM_TIMEFRAMES)work_int);
//--- read value of the "Mode" property
if(!ChartSetInteger(m_chart_id,CHART_MODE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "Foreground" property
if(!ChartSetInteger(m_chart_id,CHART_FOREGROUND,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "Shift" property
if(!ChartSetInteger(m_chart_id,CHART_SHIFT,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "ShiftSize" property
if(!ChartSetInteger(m_chart_id,CHART_SHIFT,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "AutoScroll" property
if(!ChartSetInteger(m_chart_id,CHART_AUTOSCROLL,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "Scale" property
if(!ChartSetInteger(m_chart_id,CHART_SCALE,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "ScaleFix" property
if(!ChartSetInteger(m_chart_id,CHART_SCALEFIX,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "ScaleFix_11" property
if(!ChartSetInteger(m_chart_id,CHART_SCALEFIX_11,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "FixedMax" property
if(!ChartSetDouble(m_chart_id,CHART_FIXED_MAX,FileReadDatetime(file_handle)))
return(false);
//--- read value of the "FixedMin" property
if(!ChartSetDouble(m_chart_id,CHART_FIXED_MIN,FileReadDatetime(file_handle)))
return(false);
//--- read value of the "ScalePPB" property
if(!ChartSetInteger(m_chart_id,CHART_SCALE_PT_PER_BAR,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "PointsPerBar" property
if(!ChartSetDouble(m_chart_id,CHART_POINTS_PER_BAR,FileReadDatetime(file_handle)))
return(false);
//--- read value of the "ShowOHLC" property
if(!ChartSetInteger(m_chart_id,CHART_SHOW_OHLC,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "ShowLineBid" property
if(!ChartSetInteger(m_chart_id,CHART_SHOW_BID_LINE,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "ShowLineAsk" property
if(!ChartSetInteger(m_chart_id,CHART_SHOW_ASK_LINE,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "ShowLastLine" property
if(!ChartSetInteger(m_chart_id,CHART_SHOW_LAST_LINE,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "ShowPeriodSep" property
if(!ChartSetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "ShowGrid" property
if(!ChartSetInteger(m_chart_id,CHART_SHOW_GRID,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- read value of the "ShowVolumes" property
if(!ChartSetInteger(m_chart_id,CHART_SHOW_VOLUMES,FileReadInteger(file_handle,INT_VALUE)))
return(false);
//--- read value of the "ShowObjectDescr" property
if(!ChartSetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR,FileReadInteger(file_handle,CHAR_VALUE)))
return(false);
//--- successful
return(resutl);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
#resource "\\Include\\Controls\\res\\Close.bmp"
#resource "\\Include\\Controls\\res\\Restore.bmp"
#resource "\\Include\\Controls\\res\\Turn.bmp"
//+------------------------------------------------------------------+
//| Class CDialog |
//| Usage: base class to create dialog boxes |
//| and indicator panels |
//+------------------------------------------------------------------+
class CDialog : public CWndContainer
{
protected:
//--- dependent controls
CPanel m_white_border; // the "white border" object
CPanel m_background; // the background object
CEdit m_caption; // the window title object
CBmpButton m_button_close; // the "Close" button object
CWndClient m_client_area; // the client area object
protected:
//--- flags
bool m_panel_flag; // the "panel in a separate window" flag
//--- flags
bool m_minimized; // "create in minimized state" flag
//--- additional areas
CRect m_min_rect; // minimal area coordinates
CRect m_norm_rect; // normal area coordinates
public:
CDialog(void);
~CDialog(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up
string Caption(void) const { return(m_caption.Text()); }
bool Caption(const string text) { return(m_caption.Text(text)); }
//--- fill
bool Add(CWnd *control);
bool Add(CWnd &control);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
virtual bool CreateWhiteBorder(void);
virtual bool CreateBackground(void);
virtual bool CreateCaption(void);
virtual bool CreateButtonClose(void);
virtual bool CreateClientArea(void);
//--- handlers of the dependent controls events
virtual void OnClickCaption(void);
virtual void OnClickButtonClose(void);
//--- access properties of caption
void CaptionAlignment(const int flags,const int left,const int top,const int right,const int bottom)
{ m_caption.Alignment(flags,left,top,right,bottom); }
//--- access properties of client area
bool ClientAreaVisible(const bool visible) { return(m_client_area.Visible(visible)); }
int ClientAreaLeft(void) const { return(m_client_area.Left()); }
int ClientAreaTop(void) const { return(m_client_area.Top()); }
int ClientAreaRight(void) const { return(m_client_area.Right()); }
int ClientAreaBottom(void) const { return(m_client_area.Bottom()); }
int ClientAreaWidth(void) const { return(m_client_area.Width()); }
int ClientAreaHeight(void) const { return(m_client_area.Height()); }
//--- handlers of drag
virtual bool OnDialogDragStart(void);
virtual bool OnDialogDragProcess(void);
virtual bool OnDialogDragEnd(void);
};
//+------------------------------------------------------------------+
//| Common handler of events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CDialog)
ON_EVENT(ON_CLICK,m_button_close,OnClickButtonClose)
ON_EVENT(ON_CLICK,m_caption,OnClickCaption)
ON_EVENT(ON_DRAG_START,m_caption,OnDialogDragStart)
ON_EVENT_PTR(ON_DRAG_PROCESS,m_drag_object,OnDialogDragProcess)
ON_EVENT_PTR(ON_DRAG_END,m_drag_object,OnDialogDragEnd)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CDialog::CDialog(void) : m_panel_flag(false),
m_minimized(false)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CDialog::~CDialog(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!m_panel_flag && !CreateWhiteBorder())
return(false);
if(!CreateBackground())
return(false);
if(!CreateCaption())
return(false);
if(!CreateButtonClose())
return(false);
if(!CreateClientArea())
return(false);
//--- set up additional areas
m_norm_rect.SetBound(m_rect);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Add control to the client area (by pointer) |
//+------------------------------------------------------------------+
bool CDialog::Add(CWnd *control)
{
return(m_client_area.Add(control));
}
//+------------------------------------------------------------------+
//| Add control to the client area (by reference) |
//+------------------------------------------------------------------+
bool CDialog::Add(CWnd &control)
{
return(m_client_area.Add(control));
}
//+------------------------------------------------------------------+
//| Save |
//+------------------------------------------------------------------+
bool CDialog::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//--- save
FileWriteStruct(file_handle,m_norm_rect);
FileWriteInteger(file_handle,m_min_rect.left);
FileWriteInteger(file_handle,m_min_rect.top);
FileWriteInteger(file_handle,m_minimized);
//--- result
return(CWndContainer::Save(file_handle));
}
//+------------------------------------------------------------------+
//| Load |
//+------------------------------------------------------------------+
bool CDialog::Load(const int file_handle)
{
if(file_handle==INVALID_HANDLE)
return(false);
//--- load
if(!FileIsEnding(file_handle))
{
FileReadStruct(file_handle,m_norm_rect);
int left=FileReadInteger(file_handle);
int top=FileReadInteger(file_handle);
m_min_rect.Move(left,top);
m_minimized=FileReadInteger(file_handle);
}
//--- result
return(CWndContainer::Load(file_handle));
}
//+------------------------------------------------------------------+
//| Create "white border" |
//+------------------------------------------------------------------+
bool CDialog::CreateWhiteBorder(void)
{
//--- coordinates
int x1=0;
int y1=0;
int x2=Width();
int y2=Height();
//--- create
if(!m_white_border.Create(m_chart_id,m_name+"Border",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_white_border.ColorBackground(CONTROLS_DIALOG_COLOR_BG))
return(false);
if(!m_white_border.ColorBorder(CONTROLS_DIALOG_COLOR_BORDER_LIGHT))
return(false);
if(!CWndContainer::Add(m_white_border))
return(false);
m_white_border.Alignment(WND_ALIGN_CLIENT,0,0,0,0);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create background |
//+------------------------------------------------------------------+
bool CDialog::CreateBackground(void)
{
int off=(m_panel_flag) ? 0:CONTROLS_BORDER_WIDTH;
//--- coordinates
int x1=off;
int y1=off;
int x2=Width()-off;
int y2=Height()-off;
//--- create
if(!m_background.Create(m_chart_id,m_name+"Back",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_background.ColorBackground(CONTROLS_DIALOG_COLOR_BG))
return(false);
color border=(m_panel_flag) ? CONTROLS_DIALOG_COLOR_BG : CONTROLS_DIALOG_COLOR_BORDER_DARK;
if(!m_background.ColorBorder(border))
return(false);
if(!CWndContainer::Add(m_background))
return(false);
m_background.Alignment(WND_ALIGN_CLIENT,off,off,off,off);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create window title |
//+------------------------------------------------------------------+
bool CDialog::CreateCaption(void)
{
int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH;
//--- coordinates
int x1=off;
int y1=off;
int x2=Width()-off;
int y2=y1+CONTROLS_DIALOG_CAPTION_HEIGHT;
//--- create
if(!m_caption.Create(m_chart_id,m_name+"Caption",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_caption.Color(CONTROLS_DIALOG_COLOR_CAPTION_TEXT))
return(false);
if(!m_caption.ColorBackground(CONTROLS_DIALOG_COLOR_BG))
return(false);
if(!m_caption.ColorBorder(CONTROLS_DIALOG_COLOR_BG))
return(false);
if(!m_caption.ReadOnly(true))
return(false);
if(!m_caption.Text(m_name))
return(false);
if(!CWndContainer::Add(m_caption))
return(false);
m_caption.Alignment(WND_ALIGN_WIDTH,off,0,off,0);
if(!m_panel_flag)
m_caption.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Close" button |
//+------------------------------------------------------------------+
bool CDialog::CreateButtonClose(void)
{
int off=(m_panel_flag) ? 0 : 2*CONTROLS_BORDER_WIDTH;
//--- coordinates
int x1=Width()-off-(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;
//--- create
if(!m_button_close.Create(m_chart_id,m_name+"Close",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button_close.BmpNames("::Include\\Controls\\res\\Close.bmp"))
return(false);
if(!CWndContainer::Add(m_button_close))
return(false);
m_button_close.Alignment(WND_ALIGN_RIGHT,0,0,off+CONTROLS_DIALOG_BUTTON_OFF,0);
//--- change caption
CaptionAlignment(WND_ALIGN_WIDTH,off,0,off+(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF),0);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create client area |
//+------------------------------------------------------------------+
bool CDialog::CreateClientArea(void)
{
int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH;
//--- coordinates
int x1=off+CONTROLS_DIALOG_CLIENT_OFF;
int y1=off+CONTROLS_DIALOG_CAPTION_HEIGHT;
int x2=Width()-(off+CONTROLS_DIALOG_CLIENT_OFF);
int y2=Height()-(off+CONTROLS_DIALOG_CLIENT_OFF);
//--- create
if(!m_client_area.Create(m_chart_id,m_name+"Client",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_client_area.ColorBackground(CONTROLS_DIALOG_COLOR_CLIENT_BG))
return(false);
if(!m_client_area.ColorBorder(CONTROLS_DIALOG_COLOR_CLIENT_BORDER))
return(false);
CWndContainer::Add(m_client_area);
m_client_area.Alignment(WND_ALIGN_CLIENT,x1,y1,x1,x1);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the window title |
//+------------------------------------------------------------------+
void CDialog::OnClickCaption(void)
{
}
//+------------------------------------------------------------------+
//| Handler of click on the "Close" button |
//+------------------------------------------------------------------+
void CDialog::OnClickButtonClose(void)
{
Visible(false);
}
//+------------------------------------------------------------------+
//| Start dragging the dialog box |
//+------------------------------------------------------------------+
bool CDialog::OnDialogDragStart(void)
{
if(m_drag_object==NULL)
{
m_drag_object=new CDragWnd;
if(m_drag_object==NULL)
return(false);
}
//--- calculate coordinates
int x1=Left()-CONTROLS_DRAG_SPACING;
int y1=Top()-CONTROLS_DRAG_SPACING;
int x2=Right()+CONTROLS_DRAG_SPACING;
int y2=Bottom()+CONTROLS_DRAG_SPACING;
//--- create
m_drag_object.Create(m_chart_id,"",m_subwin,x1,y1,x2,y2);
m_drag_object.PropFlags(WND_PROP_FLAG_CAN_DRAG);
//--- constraints
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();
//--- set mouse params
m_drag_object.MouseX(m_caption.MouseX());
m_drag_object.MouseY(m_caption.MouseY());
m_drag_object.MouseFlags(m_caption.MouseFlags());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Continue dragging the dialog box |
//+------------------------------------------------------------------+
bool CDialog::OnDialogDragProcess(void)
{
//--- checking
if(m_drag_object==NULL)
return(false);
//--- calculate coordinates
int x=m_drag_object.Left()+50;
int y=m_drag_object.Top()+50;
//--- move dialog
Move(x,y);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| End dragging the dialog box |
//+------------------------------------------------------------------+
bool CDialog::OnDialogDragEnd(void)
{
if(m_drag_object!=NULL)
{
m_caption.MouseFlags(m_drag_object.MouseFlags());
delete m_drag_object;
m_drag_object=NULL;
}
//--- set up additional areas
if(m_minimized)
m_min_rect.SetBound(m_rect);
else
m_norm_rect.SetBound(m_rect);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Class CAppDialog |
//| Usage: main dialog box of MQL5 application |
//+------------------------------------------------------------------+
class CAppDialog : public CDialog
{
protected:
//--- dependent controls
CBmpButton m_button_minmax; // the "Minimize/Maximize" button object
//--- variables
string m_program_name; // name of program
string m_instance_id; // unique string ID
ENUM_PROGRAM_TYPE m_program_type; // type of program
string m_indicator_name;
int m_deinit_reason;
//--- for mouse
int m_subwin_Yoff; // subwindow Y offset
CWnd* m_focused_wnd; // pointer to object that has mouse focus
CWnd* m_top_wnd; // pointer to object that has priority over mouse events handling
protected:
CChart m_chart; // object to access chart
public:
CAppDialog(void);
~CAppDialog(void);
//--- main application dialog creation and destroy
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 void Destroy(const int reason=REASON_PROGRAM);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- dialog run
virtual bool Run(void);
//--- chart events processing
void ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up
void Minimized(const bool flag) { m_minimized=flag; }
//--- to save/restore state
void IniFileSave(void);
void IniFileLoad(void);
virtual string IniFileName(void) const;
virtual string IniFileExt(void) const { return(".dat"); }
virtual bool Load(const int file_handle);
virtual bool Save(const int file_handle);
int GetInstanceId() const { return (int)StringToInteger(m_instance_id); }
private:
bool CreateCommon(const long chart,const string name,const int subwin);
bool CreateExpert(const int x1,const int y1,const int x2,const int y2);
bool CreateIndicator(const int x1,const int y1,const int x2,const int y2);
protected:
//--- create dependent controls
virtual bool CreateButtonMinMax(void);
//--- handlers of the dependent controls events
virtual void OnClickButtonClose(void);
virtual void OnClickButtonMinMax(void);
//--- external event handlers
virtual void OnAnotherApplicationClose(const long &lparam,const double &dparam,const string &sparam);
//--- methods
virtual bool Rebound(const CRect &rect);
virtual void Minimize(void);
virtual void Maximize(void);
string CreateInstanceId(void);
string ProgramName(void) const { return(m_program_name); }
void SubwinOff(void);
int GetIntegralHeight(void);
};
//+------------------------------------------------------------------+
//| Common handler of events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CAppDialog)
ON_EVENT(ON_CLICK,m_button_minmax,OnClickButtonMinMax)
ON_EXTERNAL_EVENT(ON_APP_CLOSE,OnAnotherApplicationClose)
EVENT_MAP_END(CDialog)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CAppDialog::CAppDialog(void) : m_program_type(WRONG_VALUE),
m_deinit_reason(WRONG_VALUE),
m_subwin_Yoff(0),
m_focused_wnd(NULL),
m_top_wnd(NULL)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CAppDialog::~CAppDialog(void)
{
}
//+------------------------------------------------------------------+
//| Application dialog initialization function |
//+------------------------------------------------------------------+
bool CAppDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
if(!CreateCommon(chart,name,subwin))
return(false);
//---
switch(m_program_type)
{
case PROGRAM_EXPERT:
if(!CreateExpert(x1,y1,x2,y2))
return(false);
break;
case PROGRAM_INDICATOR:
if(!CreateIndicator(x1,y1,x2,y2))
return(false);
break;
default:
Print("CAppDialog: invalid program type");
return(false);
}
//--- Title of dialog window
if(!Caption(m_program_name))
return(false);
//--- create dependent controls
if(!CreateButtonMinMax())
return(false);
//--- get subwindow offset
SubwinOff();
//--- if flag is set, minimize the dialog
if(m_minimized)
Minimize();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Initialize common area |
//+------------------------------------------------------------------+
bool CAppDialog::CreateCommon(const long chart,const string name,const int subwin)
{
//--- save parameters
m_chart_id =chart;
m_name =name;
m_subwin =subwin;
m_program_name =name;
m_deinit_reason=WRONG_VALUE;
//--- get unique ID
m_instance_id=CreateInstanceId();
//--- initialize chart object
m_chart.Attach(chart);
//--- determine type of program
m_program_type=(ENUM_PROGRAM_TYPE)MQL5InfoInteger(MQL5_PROGRAM_TYPE);
//--- specify object and mouse events
if(!m_chart.EventObjectCreate() || !m_chart.EventObjectDelete() || !m_chart.EventMouseMove())
{
Print("CAppDialog: object events specify error");
m_chart.Detach();
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Initialize in Expert Advisor |
//+------------------------------------------------------------------+
bool CAppDialog::CreateExpert(const int x1,const int y1,const int x2,const int y2)
{
//--- EA works only in main window
m_subwin=0;
//--- geometry for the minimized state
m_min_rect.SetBound(CONTROLS_DIALOG_MINIMIZE_LEFT,
CONTROLS_DIALOG_MINIMIZE_TOP,
CONTROLS_DIALOG_MINIMIZE_LEFT+CONTROLS_DIALOG_MINIMIZE_WIDTH,
CONTROLS_DIALOG_MINIMIZE_TOP+CONTROLS_DIALOG_MINIMIZE_HEIGHT);
//--- call method of the parent class
if(!CDialog::Create(m_chart.ChartId(),m_instance_id,m_subwin,x1,y1,x2,y2))
{
Print("CAppDialog: expert dialog create error");
m_chart.Detach();
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Initialize in Indicator |
//+------------------------------------------------------------------+
bool CAppDialog::CreateIndicator(const int x1,const int y1,const int x2,const int y2)
{
int width=m_chart.WidthInPixels();
//--- geometry for the minimized state
m_min_rect.LeftTop(0,0);
m_min_rect.Width(width);
m_min_rect.Height(CONTROLS_DIALOG_MINIMIZE_HEIGHT-2*CONTROLS_BORDER_WIDTH);
//--- determine subwindow
m_subwin=ChartWindowFind();
if(m_subwin==-1)
{
Print("CAppDialog: find subwindow error");
m_chart.Detach();
return(false);
}
//---
int total=ChartIndicatorsTotal(m_chart.ChartId(),m_subwin);
m_indicator_name=ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1);
//--- if subwindow number is 0 (main window), then our program is
//--- not an indicator panel, but is an indicator with built-in settings dialog
//--- dialog of such an indicator should behave as an Expert Advisor dialog
if(m_subwin==0)
return(CreateExpert(x1,y1,x2,y2));
//--- if subwindow number is not 0, then our program is an indicator panel
//--- check if subwindow is not occupied by other indicators
if(total!=1)
{
Print("CAppDialog: subwindow busy");
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
m_chart.Detach();
return(false);
}
//--- resize subwindow by dialog height
if(!IndicatorSetInteger(INDICATOR_HEIGHT,(y2-y1)+1))
{
Print("CAppDialog: subwindow resize error");
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
m_chart.Detach();
return(false);
}
//--- indicator short name
m_indicator_name=m_program_name+IntegerToString(m_subwin);
if(!IndicatorSetString(INDICATOR_SHORTNAME,m_indicator_name))
{
Print("CAppDialog: shortname error");
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
m_chart.Detach();
return(false);
}
//--- set flag
m_panel_flag=true;
//--- call method of the parent class
if(!CDialog::Create(m_chart.ChartId(),m_instance_id,m_subwin,0,0,width,y2-y1))
{
Print("CAppDialog: indicator dialog create error");
ChartIndicatorDelete(m_chart.ChartId(),m_subwin,ChartIndicatorName(m_chart.ChartId(),m_subwin,total-1));
m_chart.Detach();
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Application dialog deinitialization function |
//+------------------------------------------------------------------+
void CAppDialog::Destroy(const int reason)
{
//--- destroyed already?
if(m_deinit_reason!=WRONG_VALUE)
return;
//---
m_deinit_reason=reason;
IniFileSave();
//--- detach chart object from chart
m_chart.Detach();
//--- call parent destroy
CDialog::Destroy();
//---
if(reason==REASON_PROGRAM)
{
if(m_program_type==PROGRAM_EXPERT)
ExpertRemove();
if(m_program_type==PROGRAM_INDICATOR)
ChartIndicatorDelete(m_chart_id,m_subwin,m_indicator_name);
}
//--- send message
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_APP_CLOSE,m_subwin,0.0,m_program_name);
}
//+------------------------------------------------------------------+
//| Calculate subwindow offset |
//+------------------------------------------------------------------+
void CAppDialog::SubwinOff(void)
{
m_subwin_Yoff=m_chart.SubwindowY(m_subwin);
}
//+------------------------------------------------------------------+
//| Create the "Minimize/Maximize" button |
//+------------------------------------------------------------------+
bool CAppDialog::CreateButtonMinMax(void)
{
int off=(m_panel_flag) ? 0:2*CONTROLS_BORDER_WIDTH;
//--- coordinates
int x1=Width()-off-2*(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;
//--- create
if(!m_button_minmax.Create(m_chart_id,m_name+"MinMax",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button_minmax.BmpNames("::Include\\Controls\\res\\Turn.bmp","::Include\\Controls\\res\\Restore.bmp"))
return(false);
if(!CWndContainer::Add(m_button_minmax))
return(false);
m_button_minmax.Locking(true);
m_button_minmax.Alignment(WND_ALIGN_RIGHT,0,0,off+CONTROLS_BUTTON_SIZE+2*CONTROLS_DIALOG_BUTTON_OFF,0);
//--- change caption
CaptionAlignment(WND_ALIGN_WIDTH,off,0,off+2*(CONTROLS_BUTTON_SIZE+CONTROLS_DIALOG_BUTTON_OFF),0);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Charts event processing |
//+------------------------------------------------------------------+
void CAppDialog::ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
int mouse_x=(int)lparam;
int mouse_y=(int)dparam-m_subwin_Yoff;
//--- separate mouse events from others
switch(id)
{
case CHARTEVENT_CHART_CHANGE:
//--- assumed that the CHARTEVENT_CHART_CHANGE event can handle only the application dialog
break;
case CHARTEVENT_OBJECT_CLICK:
//--- we won't handle the CHARTEVENT_OBJECT_CLICK event, as we are working with the CHARTEVENT_MOUSE_MOVE events
return;
case CHARTEVENT_CUSTOM+ON_MOUSE_FOCUS_SET:
//--- the CHARTEVENT_CUSTOM + ON_MOUSE_FOCUS_SET event
if(CheckPointer(m_focused_wnd)!=POINTER_INVALID)
{
//--- if there is an element with focus, try to take its focus away
if(!m_focused_wnd.MouseFocusKill(lparam))
return;
}
m_focused_wnd=ControlFind(lparam);
return;
case CHARTEVENT_CUSTOM+ON_BRING_TO_TOP:
m_top_wnd=ControlFind(lparam);
return;
case CHARTEVENT_MOUSE_MOVE:
//--- the CHARTEVENT_MOUSE_MOVE event
if(CheckPointer(m_top_wnd)!=POINTER_INVALID)
{
//--- if a priority element already exists, pass control to it
if(m_top_wnd.OnMouseEvent(mouse_x,mouse_y,(int)StringToInteger(sparam)))
{
//--- event handled
m_chart.Redraw();
return;
}
}
if(OnMouseEvent(mouse_x,mouse_y,(int)StringToInteger(sparam)))
m_chart.Redraw();
return;
default:
//--- call event processing and redraw chart if event handled
if(OnEvent(id,lparam,dparam,sparam))
m_chart.Redraw();
return;
}
//--- if event was not handled, try to handle the CHARTEVENT_CHART_CHANGE event
if(id==CHARTEVENT_CHART_CHANGE)
{
//--- if subwindow number is not 0, and dialog subwindow has changed its number, then restart
if(m_subwin!=0 && m_subwin!=ChartWindowFind())
{
long fiction=1;
OnAnotherApplicationClose(fiction,dparam,sparam);
}
//--- if subwindow height is less that dialog height, minimize application window (always)
if(MathMax(m_chart.HeightInPixels(m_subwin), GetIntegralHeight())<Height()+CONTROLS_BORDER_WIDTH)
{
m_button_minmax.Pressed(true);
Minimize();
m_chart.Redraw();
}
//--- if chart width is less that dialog width, and subwindow number is not 0, try to modify dialog width
if(m_chart.WidthInPixels()!=Width() && m_subwin!=0)
{
Width(m_chart.WidthInPixels());
m_chart.Redraw();
}
//--- get subwindow offset
SubwinOff();
return;
}
}
int CAppDialog::GetIntegralHeight()
{
long id = ChartFirst();
int height = 0;
bool maximized = false;
do
{
int h = (int)ChartGetInteger(id, CHART_HEIGHT_IN_PIXELS);
height = MathMax(h, height);
maximized |= ChartGetInteger(id, CHART_IS_MAXIMIZED);
id = ChartNext(id);
} while (id != -1);
if(maximized) return height;
return 0;
}
//+------------------------------------------------------------------+
//| Run application |
//+------------------------------------------------------------------+
bool CAppDialog::Run(void)
{
// redraw chart for dialog invalidate
m_chart.Redraw();
// here we begin to assign IDs to controls
if(Id(StringToInteger(m_instance_id) + m_subwin * CONTROLS_MAXIMUM_ID) > CONTROLS_MAXIMUM_ID)
{
Print("CAppDialog: too many objects");
return(false);
}
// succeed
return(true);
}
//+------------------------------------------------------------------+
//| Stop application |
//+------------------------------------------------------------------+
void CAppDialog::OnClickButtonClose(void)
{
//--- destroy application
Destroy();
}
//+------------------------------------------------------------------+
//| Handler of click on the "Minimize/Maximize" button |
//+------------------------------------------------------------------+
void CAppDialog::OnClickButtonMinMax(void)
{
if(m_button_minmax.Pressed())
Minimize();
else
Maximize();
//--- get subwindow offset
SubwinOff();
}
//+------------------------------------------------------------------+
//| Resize |
//+------------------------------------------------------------------+
bool CAppDialog::Rebound(const CRect &rect)
{
if(!Move(rect.LeftTop()))
return(false);
if(!Size(rect.Size()))
return(false);
//--- resize subwindow
if(m_program_type==PROGRAM_INDICATOR && !IndicatorSetInteger(INDICATOR_HEIGHT,rect.Height()+1))
{
Print("CAppDialog: subwindow resize error");
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Minimize dialog window |
//+------------------------------------------------------------------+
void CAppDialog::Minimize(void)
{
//--- set flag
m_minimized=true;
//--- resize
Rebound(m_min_rect);
//--- hide client area
ClientAreaVisible(false);
}
//+------------------------------------------------------------------+
//| Restore dialog window |
//+------------------------------------------------------------------+
void CAppDialog::Maximize(void)
{
//--- reset flag
m_minimized=false;
//--- resize
Rebound(m_norm_rect);
//--- show client area
ClientAreaVisible(true);
}
//+------------------------------------------------------------------+
//| Create unique prefix for object names |
//+------------------------------------------------------------------+
string CAppDialog::CreateInstanceId(void)
{
return(IntegerToString(rand(),5,'0'));
}
//+------------------------------------------------------------------+
//| Handler of the ON_APP_CLOSE external event |
//+------------------------------------------------------------------+
void CAppDialog::OnAnotherApplicationClose(const long &lparam,const double &dparam,const string &sparam)
{
//--- exit if we are in the main window
if(m_subwin==0)
return;
//--- exit if external program was closed in main window
if(lparam==0)
return;
//--- get subwindow offset
SubwinOff();
//--- exit if external program was closed in subwindow with greater number
if(lparam>=m_subwin)
return;
//--- after all the checks we must change the subwindow
//--- get the new number of subwindow
m_subwin=ChartWindowFind();
//--- change short name
m_indicator_name=m_program_name+IntegerToString(m_subwin);
IndicatorSetString(INDICATOR_SHORTNAME,m_indicator_name);
//--- change dialog title
Caption(m_program_name);
//--- reassign IDs
Run();
}
//+------------------------------------------------------------------+
//| Save the current state of the program |
//+------------------------------------------------------------------+
void CAppDialog::IniFileSave(void)
{
string filename=IniFileName()+IniFileExt();
int handle=FileOpen(filename,FILE_WRITE|FILE_BIN|FILE_ANSI);
//---
if(handle!=INVALID_HANDLE)
{
Save(handle);
FileClose(handle);
}
}
//+------------------------------------------------------------------+
//| Read the previous state of the program |
//+------------------------------------------------------------------+
void CAppDialog::IniFileLoad(void)
{
string filename=IniFileName()+IniFileExt();
int handle=FileOpen(filename,FILE_READ|FILE_BIN|FILE_ANSI);
//---
if(handle!=INVALID_HANDLE)
{
Load(handle);
FileClose(handle);
}
}
//+------------------------------------------------------------------+
//| Generate the filename |
//+------------------------------------------------------------------+
string CAppDialog::IniFileName(void) const
{
string name;
//---
name=(m_indicator_name!=NULL) ? m_indicator_name : m_program_name;
//---
name+="_"+Symbol();
name+="_Ini";
//---
return(name);
}
//+------------------------------------------------------------------+
//| Load data |
//+------------------------------------------------------------------+
bool CAppDialog::Load(const int file_handle)
{
if(CDialog::Load(file_handle))
{
if(m_minimized)
{
m_button_minmax.Pressed(true);
Minimize();
}
else
{
m_button_minmax.Pressed(false);
Maximize();
}
int prev_deinit_reason=FileReadInteger(file_handle);
if(prev_deinit_reason==REASON_CHARTCLOSE || prev_deinit_reason==REASON_CLOSE)
{
//--- if the previous time program ended after closing the chart window,
//--- delete object left since the last start of the program
string prev_instance_id=IntegerToString(FileReadInteger(file_handle),5,'0');
if(prev_instance_id!=m_instance_id)
{
long chart_id=m_chart.ChartId();
int total=ObjectsTotal(chart_id,m_subwin);
for(int i=total-1;i>=0;i--)
{
string obj_name=ObjectName(chart_id,i,m_subwin);
if(StringFind(obj_name,prev_instance_id)==0)
ObjectDelete(chart_id,obj_name);
}
}
}
return(true);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Save data |
//+------------------------------------------------------------------+
bool CAppDialog::Save(const int file_handle)
{
if(CDialog::Save(file_handle))
{
FileWriteInteger(file_handle,m_deinit_reason);
FileWriteInteger(file_handle,(int)StringToInteger(m_instance_id));
return(true);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//#include <ControlsPlus/Button.mqh>
//+------------------------------------------------------------------+
//| Button.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndObj.mqh"
//#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| Class CButton |
//| Usage: control that is displayed by |
//| the CChartObjectButton object |
//+------------------------------------------------------------------+
class CButton : public CWndObj
{
protected:
CChartObjectButton m_button; // chart object
bool m_capture;
public:
CButton(void);
~CButton(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- state
bool Pressed(void) const { return(m_button.State()); }
bool Pressed(const bool pressed) { return(m_button.State(pressed)); }
//--- properties
bool Locking(void) const { return(IS_CAN_LOCK); }
void Locking(const bool flag);
protected:
//--- handlers of object settings
virtual bool OnSetText(void) { return(m_button.Description(m_text)); }
virtual bool OnSetColor(void) { return(m_button.Color(m_color)); }
virtual bool OnSetColorBackground(void) { return(m_button.BackColor(m_color_background)); }
virtual bool OnSetColorBorder(void) { return(m_button.BorderColor(m_color_border)); }
virtual bool OnSetFont(void) { return(m_button.Font(m_font)); }
virtual bool OnSetFontSize(void) { return(m_button.FontSize(m_font_size)); }
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
virtual bool OnResize(void);
virtual bool OnMouseDown(void);
virtual bool OnMouseUp(void);
virtual bool OnEnable(void) override;
virtual bool OnDisable(void) override;
virtual bool OnMouseEvent(const int x, const int y, const int flags) override;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CButton::CButton(void)
{
m_color =CONTROLS_BUTTON_COLOR;
m_color_background=CONTROLS_BUTTON_COLOR_BG;
m_color_border =CONTROLS_BUTTON_COLOR_BORDER;
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CButton::~CButton(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_button.Create(chart,name,subwin,x1,y1,Width(),Height()))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Locking flag |
//+------------------------------------------------------------------+
void CButton::Locking(const bool flag)
{
if(flag)
PropFlagsSet(WND_PROP_FLAG_CAN_LOCK);
else
PropFlagsReset(WND_PROP_FLAG_CAN_LOCK);
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CButton::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CButton::OnShow(void)
{
return(m_button.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CButton::OnHide(void)
{
return(m_button.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CButton::OnMove(void)
{
//--- position the chart object
return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
//| Resize the chart object |
//+------------------------------------------------------------------+
bool CButton::OnResize(void)
{
//--- resize the chart object
return(m_button.X_Size(m_rect.Width()) && m_button.Y_Size(m_rect.Height()));
}
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button |
//+------------------------------------------------------------------+
bool CButton::OnMouseDown(void)
{
if(!IS_CAN_LOCK)
Pressed(!Pressed());
//--- call of the method of the parent class
return(CWnd::OnMouseDown());
}
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button |
//+------------------------------------------------------------------+
bool CButton::OnMouseUp(void)
{
//--- depress the button if it is not fixed
if(m_button.State() && !IS_CAN_LOCK)
m_button.State(false);
//--- call of the method of the parent class
return(CWnd::OnMouseUp());
}
//+------------------------------------------------------------------+
bool CButton::OnEnable(void)
{
m_button.Z_Order(0);
m_color = CONTROLS_BUTTON_COLOR;
m_button.Color(m_color);
return(true);
}
bool CButton::OnDisable(void)
{
m_button.Z_Order(-100);
m_color = CONTROLS_BUTTON_COLOR_BORDER;
m_button.Color(m_color);
return(true);
}
bool CButton::OnMouseEvent(const int x, const int y, const int flags) override
{
if(Contains(x, y))
{
m_capture = (flags & MOUSE_LEFT) != 0;
}
else
{
if(m_capture && !IS_CAN_LOCK && Pressed())
{
Pressed(false);
}
m_capture = false;
}
return CWndObj::OnMouseEvent(x, y, flags);
}
//#include <ControlsPlus/Edit.mqh>
//#include <ControlsPlus/CheckBox.mqh>
//+------------------------------------------------------------------+
//| CheckBox.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndContainer.mqh"
//#include "BmpButton.mqh"
//#include "Edit.mqh"
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
#resource "\\Include\\Controls\\res\\CheckBoxOn.bmp"
#resource "\\Include\\Controls\\res\\CheckBoxOff.bmp"
//+------------------------------------------------------------------+
//| Class CCheckBox |
//| Usage: class that implements the "CheckBox" control |
//+------------------------------------------------------------------+
class CCheckBox : public CWndContainer
{
private:
//--- dependent controls
CBmpButton m_button; // button object
CEdit m_label; // label object
//--- data
int m_value; // value
public:
CCheckBox(void);
~CCheckBox(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- settings
string Text(void) const { return(m_label.Text()); }
bool Text(const string value) { return(m_label.Text(value)); }
color Color(void) const { return(m_label.Color()); }
bool Color(const color value) { return(m_label.Color(value)); }
//--- state
bool Checked(void) const { return(m_button.Pressed()); }
bool Checked(const bool flag) { return(m_button.Pressed(flag)); }
//--- data
int Value(void) const { return(m_value); }
void Value(const int value) { m_value=value; }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
virtual bool CreateButton(void);
virtual bool CreateLabel(void);
//--- handlers of the dependent controls events
virtual bool OnClickButton(void);
virtual bool OnClickLabel(void);
// we can't do this with new subclass, because CheckGroup instantiates CheckBox'es
// automatically via ArrayResize of object array (not pointer array),
// so it's impossible to store a derived class pointer there
virtual bool OnResize(void) override;
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CCheckBox)
ON_EVENT(ON_CLICK,m_button,OnClickButton)
ON_EVENT(ON_CLICK,m_label,OnClickLabel)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CCheckBox::CCheckBox(void) : m_value(0)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CCheckBox::~CCheckBox(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CCheckBox::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateButton())
return(false);
if(!CreateLabel())
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create button |
//+------------------------------------------------------------------+
bool CCheckBox::CreateButton(void)
{
//--- calculate coordinates
int x1=CONTROLS_CHECK_BUTTON_X_OFF;
int y1=CONTROLS_CHECK_BUTTON_Y_OFF;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE-CONTROLS_BORDER_WIDTH;
//--- create
if(!m_button.Create(m_chart_id,m_name+"Button",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button.BmpNames("::Include\\Controls\\res\\CheckBoxOff.bmp","::Include\\Controls\\res\\CheckBoxOn.bmp"))
return(false);
if(!Add(m_button))
return(false);
m_button.Locking(true);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create label |
//+------------------------------------------------------------------+
bool CCheckBox::CreateLabel(void)
{
//--- calculate coordinates
int x1=CONTROLS_CHECK_LABEL_X_OFF;
int y1=CONTROLS_CHECK_LABEL_Y_OFF;
int x2=Width();
int y2=Height();
//--- create
if(!m_label.Create(m_chart_id,m_name+"Label",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_label.Text(m_name))
return(false);
if(!Add(m_label))
return(false);
m_label.ReadOnly(true);
m_label.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG);
m_label.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BG);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckBox::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
FileWriteInteger(file_handle,Checked());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckBox::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
if(!FileIsEnding(file_handle))
Checked(FileReadInteger(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CCheckBox::OnClickButton(void)
{
//--- send the "changed state" event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on label |
//+------------------------------------------------------------------+
bool CCheckBox::OnClickLabel(void)
{
//--- change button state
m_button.Pressed(!m_button.Pressed());
//--- return the result of the button click handler
return(OnClickButton());
}
//+------------------------------------------------------------------+
//| Resize the chart object |
//+------------------------------------------------------------------+
bool CCheckBox::OnResize(void)
{
// resize CEdit control, this will trigger OnResize
// for the label chart object (button is always the same size)
m_label.Width(m_rect.Width() - CONTROLS_SCROLL_SIZE - CONTROLS_BORDER_WIDTH);
return true;
}
//#include <Layouts/LayoutDefines.mqh>
// 'cache' is an instance of layout cache
// 'type' should be descendant of Notifiable
#define ON_EVENT_LAYOUT_INDEX(event, cache, controlIndex, handler) if(id == (event + CHARTEVENT_CUSTOM) && lparam == cache.get(controlIndex).Id()) { handler(); return(true); }
#define ON_EVENT_LAYOUT_ARRAY(event, cache) if(id == (event + CHARTEVENT_CUSTOM) && cache.onEvent(event, cache.get(-lparam))) { return true; }
#define ON_EVENT_LAYOUT_CTRL_ANY(event, cache, type, anything) if(id == (event + CHARTEVENT_CUSTOM)) {type *ptr = dynamic_cast<type *>(cache.get(-lparam)); if(ptr != NULL && ptr.onEvent(event, anything)) { return true; }}
#define ON_EVENT_LAYOUT_CTRL_DLG(event, cache, type) if(id == (event + CHARTEVENT_CUSTOM)) {type *ptr = dynamic_cast<type *>(cache.get(-lparam)); if(ptr != NULL && ptr.onEvent(event, &this)) { return true; }}
#define ON_EVENT_RAW(event, handler) if(id == event) { handler(lparam, dparam, sparam); return(true); }
#define ON_LAYOUT_REFRESH 99 // "panic" event id
#define PRT(A) Print(#A, " ", (A))
//#include <Layouts/Box.mqh>
//+------------------------------------------------------------------+
//| Box.mqh |
//| Enrico Lambino |
//| www.mql5.com/en/users/iceron|
//+------------------------------------------------------------------+
#property copyright "Enrico Lambino"
#property link "www.mql5.com/en/users/iceron"
//#include <ControlsPlus/WndClient.mqh>
//#define CLASS_LAYOUT 999
#define WND_ALIGN_CONTENT 128
#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,
VERTICAL_ALIGN_STACK
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
enum HORIZONTAL_ALIGN
{
HORIZONTAL_ALIGN_CENTER,
HORIZONTAL_ALIGN_CENTER_NOSIDES,
HORIZONTAL_ALIGN_LEFT,
HORIZONTAL_ALIGN_RIGHT,
HORIZONTAL_ALIGN_STACK
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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();
virtual void AdjustFlexControls(void);
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);
}
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(0),
m_padding_bottom(0),
m_padding_left(0),
m_padding_right(0),
m_total_x(0),
m_total_y(0)
{
m_min_size.cx = 0;
m_min_size.cy = 0;
RTTI;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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)
{
AdjustFlexControls();
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);
CBox *box = dynamic_cast<CBox *>(control);
//if(control.Type() == CLASS_LAYOUT)
if(box)
{
box.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;
// there is a potential problem here: nested boxes can be aligned in such way
// that they share the same width/height without interference
// for example, in horizontal box one can have 2 subboxes aligned on top
// and bottom sides, so they both fit the parent width, but the algorithm
// will calculate common width as a sum of the subboxes
// we need to check alignment flags
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 / (MathMax(m_controls_total, 2) - 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;
if(m_horizontal_align == HORIZONTAL_ALIGN_STACK)
{
x_space = 0;
}
}
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 / (MathMax(m_controls_total, 2) - 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;
if(m_vertical_align == VERTICAL_ALIGN_STACK)
{
y_space = 0;
}
}
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);
control.Show();
CBox *container = dynamic_cast<CBox *>(control);
if(container != NULL)
{
container.Pack();
}
if(j < ControlsTotal() - 1)
Shift(GetPointer(control), x, y, x_space, y_space);
}
return (true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void 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;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBox::Padding(const int padding)
{
m_padding_top = padding;
m_padding_right = padding;
m_padding_bottom = padding;
m_padding_left = padding;
}
//+------------------------------------------------------------------+
void CBox::AdjustFlexControls(void)
{
// the following is an example of automatic resize
// makes sense only, if controls support dynamic resize
if((m_align_flags & WND_ALIGN_CONTENT) != 0)
{
if(m_layout_style == LAYOUT_STYLE_HORIZONTAL)
{
// if LAYOUT_STYLE_HORIZONTAL should refine auto-widths of nesting controls
int resizable = 0;
int consts = 0;
int total = 0;
int margins = 0;
for(int i = 0; i < ControlsTotal(); i++)
{
CWnd *control = Control(i);
if(control == NULL) continue;
if(control == &m_background) continue;
total++;
if((control.Alignment() & (WND_ALIGN_LEFT | WND_ALIGN_RIGHT)) == 0)
{
resizable++;
}
else
{
consts += control.Width();
}
CRect r = control.Margins();
margins += (r.left + r.right);
}
if(resizable > 0 && total > 0)
{
margins /= total;
int borders = (CONTROLS_BORDER_WIDTH + margins) * 2 * total;
int w = (this.Width() - consts - borders) / resizable;
for(int i = 0; i < ControlsTotal(); i++)
{
CWnd *control = Control(i);
if(control == NULL) continue;
if(control == &m_background) continue;
if((control.Alignment() & (WND_ALIGN_LEFT | WND_ALIGN_RIGHT)) == 0)
{
control.Width(w);
}
}
}
}
else if(m_layout_style == LAYOUT_STYLE_VERTICAL)
{
// if LAYOUT_STYLE_VERTICAL should refine auto-heights of nesting controls
int resizable = 0;
int consts = 0;
int total = 0;
int margins = 0;
for(int i = 0; i < ControlsTotal(); i++)
{
CWnd *control = Control(i);
if(control == NULL) continue;
if(control == &m_background) continue;
total++;
if((control.Alignment() & (WND_ALIGN_TOP | WND_ALIGN_BOTTOM)) == 0)
{
resizable++;
}
else
{
consts += control.Height();
}
CRect r = control.Margins();
margins += (r.top + r.bottom);
}
if(resizable > 0 && total > 0)
{
margins /= total;
int borders = (CONTROLS_BORDER_WIDTH + margins) * 2 * total;
int h = (this.Height() - consts - borders) / resizable;
for(int i = 0; i < ControlsTotal(); i++)
{
CWnd *control = Control(i);
if(control == NULL) continue;
if(control == &m_background) continue;
if((control.Alignment() & (WND_ALIGN_TOP | WND_ALIGN_BOTTOM)) == 0)
{
control.Height(h);
}
}
}
}
}
}
class CBoxH: public CBox
{
public:
CBoxH()
{
RTTI;
m_layout_style = LAYOUT_STYLE_HORIZONTAL;
}
};
class CBoxV: public CBox
{
public:
CBoxV()
{
RTTI;
m_layout_style = LAYOUT_STYLE_VERTICAL;
}
};
//#include <Layouts/ComboBoxResizable.mqh>
//+------------------------------------------------------------------+
//| ComboBoxResizable.mqh |
//| Copyright (c) 2019, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//+------------------------------------------------------------------+
//#include <ControlsPlus/ComboBox.mqh>
//+------------------------------------------------------------------+
//| ComboBox.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndContainer.mqh"
//#include "Edit.mqh"
//#include "BmpButton.mqh"
//#include "ListView.mqh"
//+------------------------------------------------------------------+
//| ListView.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndClient.mqh"
//#include "Edit.mqh"
//#include <Arrays\ArrayString.mqh>
//+------------------------------------------------------------------+
//| ArrayString.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayString. |
//| Purpose: Class of dynamic array of variables of string type. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayString : public CArray
{
protected:
string m_data[]; // data array
public:
CArrayString(void);
~CArrayString(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_STRING); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const string element);
bool AddArray(const string &src[]);
bool AddArray(const CArrayString *src);
bool Insert(const string element,const int pos);
bool InsertArray(const string &src[],const int pos);
bool InsertArray(const CArrayString *src,const int pos);
bool AssignArray(const string &src[]);
bool AssignArray(const CArrayString *src);
//--- method of access to the array
string At(const int index) const;
string operator[](const int index) const { return(At(index)); }
//--- methods of changing
bool Update(const int index,const string element);
bool Shift(const int index,const int shift);
//--- methods of deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const string &array[]) const;
bool CompareArray(const CArrayString *array) const;
//--- methods for working with the sorted array
bool InsertSort(const string element);
int Search(const string element) const;
int SearchGreat(const string element) const;
int SearchLess(const string element) const;
int SearchGreatOrEqual(const string element) const;
int SearchLessOrEqual(const string element) const;
int SearchFirst(const string element) const;
int SearchLast(const string element) const;
int SearchLinear(const string element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const string element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayString::CArrayString(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayString::~CArrayString(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayString::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayString::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayString::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayString::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayString::Add(const string element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayString::AddArray(const string &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayString::AddArray(const CArrayString *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayString::Insert(const string element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayString::InsertArray(const string &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayString::InsertArray(const CArrayString *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayString::AssignArray(const string &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayString::AssignArray(const CArrayString *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
string CArrayString::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return("");
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayString::Update(const int index,const string element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayString::Shift(const int index,const int shift)
{
string tmp_string;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_string=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_string;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayString::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayString::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayString::CompareArray(const string &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayString::CompareArray(const CArrayString *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayString::QuickSort(int beg,int end,const int mode)
{
int i,j;
string p_string;
string t_string;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_string=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_string)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_string)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_string=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_string;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayString::InsertSort(const string element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayString::SearchLinear(const string element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::QuickSearch(const string element) const
{
int i,j,m=-1;
string t_string;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_string=m_data[m];
if(t_string==element)
break;
if(t_string>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::Search(const string element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchGreat(const string element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchLess(const string element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchGreatOrEqual(const string element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchLessOrEqual(const string element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchFirst(const string element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayString::SearchLast(const string element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayString::Save(const int file_handle)
{
int i=0,len;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
{
len=StringLen(m_data[i]);
//--- write string length
if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE)
return(false);
//--- write string
if(len!=0) if(FileWriteString(file_handle,m_data[i],len)!=len)
break;
}
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayString::Load(const int file_handle)
{
int i=0,num,len;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
//--- read string length
len=FileReadInteger(file_handle,INT_VALUE);
//--- read string
if(len!=0)
m_data[i]=FileReadString(file_handle,len);
else
m_data[i]="";
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
//#include <Arrays\ArrayLong.mqh>
//+------------------------------------------------------------------+
//| ArrayLong.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayLong. |
//| Purpose: Class of dynamic array of variables |
//| of long or ulong type. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayLong : public CArray
{
protected:
long m_data[]; // data array
public:
CArrayLong(void);
~CArrayLong(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_LONG); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const long element);
bool AddArray(const long &src[]);
bool AddArray(const CArrayLong *src);
bool Insert(const long element,const int pos);
bool InsertArray(const long &src[],const int pos);
bool InsertArray(const CArrayLong *src,const int pos);
bool AssignArray(const long &src[]);
bool AssignArray(const CArrayLong *src);
//--- method of access to the array
long At(const int index) const;
long operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods change
bool Update(const int index,const long element);
bool Shift(const int index,const int shift);
//--- methods for deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for compare arrays
bool CompareArray(const long &array[]) const;
bool CompareArray(const CArrayLong *array) const;
//--- methods for working with the sorted array
bool InsertSort(const long element);
int Search(const long element) const;
int SearchGreat(const long element) const;
int SearchLess(const long element) const;
int SearchGreatOrEqual(const long element) const;
int SearchLessOrEqual(const long element) const;
int SearchFirst(const long element) const;
int SearchLast(const long element) const;
int SearchLinear(const long element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const long element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayLong::CArrayLong(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayLong::~CArrayLong(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayLong::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayLong::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayLong::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayLong::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayLong::Add(const long element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayLong::AddArray(const long &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayLong::AddArray(const CArrayLong *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayLong::Insert(const long element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayLong::InsertArray(const long &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayLong::InsertArray(const CArrayLong *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayLong::AssignArray(const long &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayLong::AssignArray(const CArrayLong *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
long CArrayLong::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(LONG_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayLong::Update(const int index,const long element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayLong::Shift(const int index,const int shift)
{
long tmp_long;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_long=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_long;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayLong::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayLong::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayLong::CompareArray(const long &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayLong::CompareArray(const CArrayLong *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayLong::QuickSort(int beg,int end,const int mode)
{
int i,j;
long p_long,t_long;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_long=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_long)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_long)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_long=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_long;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayLong::InsertSort(const long element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- search position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayLong::SearchLinear(const long element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::QuickSearch(const long element) const
{
int i,j,m=-1;
long t_long;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_long=m_data[m];
if(t_long==element)
break;
if(t_long>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::Search(const long element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchGreat(const long element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchLess(const long element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchGreatOrEqual(const long element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchLessOrEqual(const long element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchFirst(const long element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayLong::SearchLast(const long element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayLong::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteLong(file_handle,m_data[i])!=sizeof(long))
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayLong::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=FileReadLong(file_handle);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class CListView |
//| Usage: display lists |
//+------------------------------------------------------------------+
class CListView : public CWndClient
{
protected:
//--- dependent controls
CEdit m_rows[]; // array of the row objects
//--- set up
int m_offset; // index of first visible row in array of rows
int m_total_view; // number of visible rows
int m_item_height; // height of visible row
bool m_height_variable;
//--- data
CArrayString m_strings; // array of rows
CArrayLong m_values; // array of values
int m_current; // index of current row in array of rows
bool m_color_mode;
public:
CListView(void);
~CListView(void);
//--- create
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 void Destroy(const int reason=0);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up
bool TotalView(const int value);
//--- fill
virtual bool AddItem(const string item,const long value=-1);
//--- data
virtual bool ItemAdd(const string item,const long value=-1);
virtual bool ItemInsert(const int index,const string item,const long value=-1);
virtual bool ItemUpdate(const int index,const string item,const long value=-1);
virtual bool ItemDelete(const int index);
virtual bool ItemsClear(void);
//--- data
int Current(void) { return(m_current); }
string Select(void) { return(m_strings.At(m_current)); }
bool Select(const int index);
bool SelectByText(const string text);
bool SelectByValue(const long value);
//--- data (read only)
long Value(void) { return(m_values.At(m_current)); }
int Count(void) const { return m_strings.Total(); }
//--- state
virtual bool Show(void);
void SetColorMode(const bool c){ m_color_mode = c; }
protected:
//--- create dependent controls
bool CreateRow(const int index);
//--- event handlers
virtual bool OnResize(void);
//--- handlers of the dependent controls events
virtual bool OnVScrollShow(void);
virtual bool OnVScrollHide(void);
virtual bool OnScrollLineDown(void);
virtual bool OnScrollLineUp(void);
virtual bool OnItemClick(const int index);
//--- redraw
virtual bool Redraw(void);
virtual bool RowState(const int index,const bool select);
bool CheckView(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CListView)
ON_INDEXED_EVENT(ON_CLICK,m_rows,OnItemClick)
EVENT_MAP_END(CWndClient)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CListView::CListView(void) : m_offset(0),
m_total_view(0),
m_item_height(CONTROLS_LIST_ITEM_HEIGHT),
m_current(CONTROLS_INVALID_INDEX),
m_height_variable(false),
m_color_mode(false)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CListView::~CListView(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CListView::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
int y=y2;
//--- if the number of visible rows is previously determined, adjust the vertical size
if(!TotalView((y2-y1)/m_item_height))
y=m_item_height+y1+2*CONTROLS_BORDER_WIDTH;
//--- check the number of visible rows
if(m_total_view<1)
return(false);
//--- call method of the parent class
if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y))
return(false);
//--- set up
if(!m_background.ColorBackground(CONTROLS_LIST_COLOR_BG))
return(false);
if(!m_background.ColorBorder(CONTROLS_LIST_COLOR_BORDER))
return(false);
//--- create dependent controls
ArrayResize(m_rows,m_total_view);
for(int i=0;i<m_total_view;i++)
{
if(!CreateRow(i))
return(false);
if(m_height_variable && i>0)
m_rows[i].Hide();
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Delete group of controls |
//+------------------------------------------------------------------+
void CListView::Destroy(const int reason)
{
//--- call of the method of the parent class
CWndClient::Destroy(reason);
//--- clear items
m_strings.Clear();
m_values.Clear();
//---
m_offset =0;
m_total_view=0;
}
//+------------------------------------------------------------------+
//| Set parameter |
//+------------------------------------------------------------------+
bool CListView::TotalView(const int value)
{
//--- if parameter is not equal to 0, modifications are not possible
if(m_total_view!=0)
{
m_height_variable=true;
return(false);
}
//--- save value
m_total_view=value;
//--- parameter has been changed
return(true);
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CListView::Show(void)
{
//--- call of the method of the parent class
CWndClient::Show();
//--- number of items
int total=m_strings.Total();
//---
if(total==0)
total=1;
//---
if(m_height_variable && total<m_total_view)
for(int i=total;i<m_total_view;i++)
m_rows[i].Hide();
for(int i = m_total_view; i < ArraySize(m_rows); i++)
m_rows[i].Hide();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create "row" |
//+------------------------------------------------------------------+
bool CListView::CreateRow(const int index)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH+m_item_height*index;
int x2=Width()-2*CONTROLS_BORDER_WIDTH;
int y2=y1+m_item_height;
//--- create
if(!m_rows[index].Create(m_chart_id,m_name+"Item"+IntegerToString(index),m_subwin,x1,y1,x2,y2))
return(false);
if(!m_rows[index].Text(""))
return(false);
if(!m_rows[index].ReadOnly(true))
return(false);
if(!RowState(index,false))
return(false);
if(!Add(m_rows[index]))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Add item (row) |
//+------------------------------------------------------------------+
bool CListView::AddItem(const string item,const long value)
{
//--- method left for compatibility with previous version
return(ItemAdd(item,value));
}
//+------------------------------------------------------------------+
//| Add item (row) |
//+------------------------------------------------------------------+
bool CListView::ItemAdd(const string item,const long value)
{
//--- add
if(!m_strings.Add(item))
return(false);
if(!m_values.Add((value != -1)?value:m_values.Total()))
return(false);
//--- number of items
int total=m_strings.Total();
//--- exit if number of items does not exceed the size of visible area
if(total<m_total_view+1)
{
if(m_height_variable && total!=1)
{
Height(total*m_item_height+2*CONTROLS_BORDER_WIDTH);
if(IS_VISIBLE)
m_rows[total-1].Show();
}
return(Redraw());
}
//--- if number of items exceeded the size of visible area
if(total==m_total_view+1)
{
//--- enable vertical scrollbar
if(!VScrolled(true))
return(false);
//--- and immediately make it invisible (if needed)
if(IS_VISIBLE && !OnVScrollShow())
return(false);
}
//--- set up the scrollbar
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Insert item (row) |
//+------------------------------------------------------------------+
bool CListView::ItemInsert(const int index,const string item,const long value)
{
//--- insert
if(!m_strings.Insert(item,index))
return(false);
if(!m_values.Insert(value,index))
return(false);
//--- number of items
int total=m_strings.Total();
//--- exit if number of items does not exceed the size of visible area
if(total<m_total_view+1)
{
if(m_height_variable && total!=1)
{
Height(total*m_item_height+2*CONTROLS_BORDER_WIDTH);
if(IS_VISIBLE)
m_rows[total-1].Show();
}
return(Redraw());
}
//--- if number of items exceeded the size of visible area
if(total==m_total_view+1)
{
//--- enable vertical scrollbar
if(!VScrolled(true))
return(false);
//--- and immediately make it invisible (if needed)
if(IS_VISIBLE && !OnVScrollShow())
return(false);
}
//--- set up the scrollbar
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Update item (row) |
//+------------------------------------------------------------------+
bool CListView::ItemUpdate(const int index,const string item,const long value)
{
//--- update
if(!m_strings.Update(index,item))
return(false);
if(!m_values.Update(index,value))
return(false);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Delete item (row) |
//+------------------------------------------------------------------+
bool CListView::ItemDelete(const int index)
{
//--- delete
if(!m_strings.Delete(index))
return(false);
if(!m_values.Delete(index))
return(false);
//--- number of items
int total=m_strings.Total();
//--- exit if number of items does not exceed the size of visible area
if(total<m_total_view)
{
if(m_height_variable && total!=0)
{
Height(total*m_item_height+2*CONTROLS_BORDER_WIDTH);
m_rows[total].Hide();
}
return(Redraw());
}
//--- if number of items exceeded the size of visible area
if(total==m_total_view)
{
//--- disable vertical scrollbar
if(!VScrolled(false))
return(false);
//--- and immediately make it unvisible
if(!OnVScrollHide())
return(false);
}
//--- set up the scrollbar
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Delete all items |
//+------------------------------------------------------------------+
bool CListView::ItemsClear(void)
{
m_offset=0;
m_current = CONTROLS_INVALID_INDEX;
//--- clear
if(!m_strings.Shutdown())
return(false);
if(!m_values.Shutdown())
return(false);
//---
if(m_height_variable)
{
Height(m_item_height+2*CONTROLS_BORDER_WIDTH);
for(int i=1;i<m_total_view;i++)
m_rows[i].Hide();
}
//--- disable vertical scrollbar
m_scroll_v.CurrPos(0);
if(!VScrolled(false))
return(false);
//--- and immediately make it unvisible (if needed)
if(!OnVScrollHide())
return(false);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Sett current item |
//+------------------------------------------------------------------+
bool CListView::Select(const int index)
{
//--- check index
if(index>=m_strings.Total())
return(false);
if(index<0 && index!=CONTROLS_INVALID_INDEX)
return(false);
//--- unselect
if(m_current!=CONTROLS_INVALID_INDEX)
RowState(m_current-m_offset,false);
//--- select
if(index!=CONTROLS_INVALID_INDEX)
RowState(index-m_offset,true);
//--- save value
m_current=index;
//--- succeed
return(CheckView());
}
//+------------------------------------------------------------------+
//| Set current item (by text) |
//+------------------------------------------------------------------+
bool CListView::SelectByText(const string text)
{
//--- find text
int index=m_strings.SearchLinear(text);
//--- if text is not found, exit without changing the selection
if(index==CONTROLS_INVALID_INDEX)
return(false);
//--- change selection
return(Select(index));
}
//+------------------------------------------------------------------+
//| Set current item (by value) |
//+------------------------------------------------------------------+
bool CListView::SelectByValue(const long value)
{
//--- find value
int index=m_values.SearchLinear(value);
//--- if value is not found, exit without changing the selection
if(index==CONTROLS_INVALID_INDEX)
return(false);
//--- change selection
return(Select(index));
}
//+------------------------------------------------------------------+
//| Redraw |
//+------------------------------------------------------------------+
bool CListView::Redraw(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- copy text
if(!m_rows[i].Text(m_strings.At(i+m_offset)))
return(false);
//--- select
if(!RowState(i,(m_current==i+m_offset)))
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Change state |
//+------------------------------------------------------------------+
bool CListView::RowState(const int index,const bool select)
{
//--- check index
if(index<0 || index>=ArraySize(m_rows))
return(true);
//--- determine colors
color text_color=(select) ? CONTROLS_LISTITEM_COLOR_TEXT_SEL : CONTROLS_LISTITEM_COLOR_TEXT;
color back_color=(select) ? CONTROLS_LISTITEM_COLOR_BG_SEL : CONTROLS_LISTITEM_COLOR_BG;
//--- get pointer
CEdit *item=GetPointer(m_rows[index]);
//--- recolor the "row"
return(item.Color(text_color) && item.ColorBackground(m_color_mode ? (m_offset + index > 0 ? (color)m_values.At(m_offset + index) : back_color) : back_color) && item.ColorBorder(back_color));
}
//+------------------------------------------------------------------+
//| Check visibility of selected row |
//+------------------------------------------------------------------+
bool CListView::CheckView(void)
{
//--- check visibility
if(m_current>=m_offset && m_current<m_offset+m_total_view)
return(true);
//--- selected row is not visible
if(m_current != CONTROLS_INVALID_INDEX)
{
int total=m_strings.Total();
m_offset=(total-m_current>m_total_view) ? m_current : total-m_total_view;
//--- adjust the scrollbar
m_scroll_v.CurrPos(m_offset);
}
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of resizing |
//+------------------------------------------------------------------+
bool CListView::OnResize(void)
{
//--- call of the method of the parent class
if(!CWndClient::OnResize())
return(false);
//--- set up the size of "row"
if(VScrolled())
OnVScrollShow();
else
OnVScrollHide();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Show vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CListView::OnVScrollShow(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to shown vertical scrollbar
m_rows[i].Width(Width()-(CONTROLS_SCROLL_SIZE+CONTROLS_BORDER_WIDTH));
}
//--- check visibility
if(!IS_VISIBLE)
{
m_scroll_v.Visible(false);
return(true);
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Hide vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CListView::OnVScrollHide(void)
{
//--- check visibility
if(!IS_VISIBLE)
return(true);
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to hidden vertical scroll bar
m_rows[i].Width(Width()-2*CONTROLS_BORDER_WIDTH);
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll up for one row" event |
//+------------------------------------------------------------------+
bool CListView::OnScrollLineUp(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll down for one row" event |
//+------------------------------------------------------------------+
bool CListView::OnScrollLineDown(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of click on row |
//+------------------------------------------------------------------+
bool CListView::OnItemClick(const int index)
{
//--- select "row"
Select(index+m_offset);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
//--- Can not place the same file into resource twice
#resource "\\Include\\Controls\\res\\DropOn.bmp" // image file
#resource "\\Include\\Controls\\res\\DropOff.bmp" // image file
//+------------------------------------------------------------------+
//| Class CComboBox |
//| Usage: drop-down list |
//+------------------------------------------------------------------+
class CComboBox : public CWndContainer
{
protected:
//--- dependent controls
CEdit m_edit; // the entry field object
CBmpButton m_drop; // the button object
CListView m_list; // the drop-down list object
//--- set up
int m_item_height; // height of visible row
int m_view_items; // number of visible rows in the drop-down list
public:
CComboBox(void);
~CComboBox(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- fill
bool AddItem(const string item,const long value=-1);
//--- set up
void ListViewItems(const int value) { m_view_items=value; }
//--- data
virtual bool ItemAdd(const string item,const long value=-1) { return(m_list.ItemAdd(item,value)); }
virtual bool ItemInsert(const int index,const string item,const long value=-1) { return(m_list.ItemInsert(index,item,value)); }
virtual bool ItemUpdate(const int index,const string item,const long value=-1) { return(m_list.ItemUpdate(index,item,value)); }
virtual bool ItemDelete(const int index) { return(m_list.ItemDelete(index)); }
virtual bool ItemsClear(void) { return(m_list.ItemsClear()); }
//--- data
string Select(void) { return(m_edit.Text()); }
bool Select(const int index);
bool SelectByText(const string text);
bool SelectByValue(const long value);
//--- data (read only)
long Value(void) { return(m_list.Value()); }
//--- state
virtual bool Show(void);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
virtual bool CreateEdit(void);
virtual bool CreateButton(void);
virtual bool CreateList(void);
//--- handlers of the dependent controls events
virtual bool OnClickEdit(void);
virtual bool OnClickButton(void);
virtual bool OnChangeList(void);
virtual bool OnEnable(void) override;
virtual bool OnDisable(void) override;
//--- show drop-down list
bool ListShow(void);
bool ListHide(void);
void CheckListHide(const int id,int x,int y);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CComboBox)
ON_EVENT(ON_CLICK,m_edit,OnClickEdit)
ON_EVENT(ON_CLICK,m_drop,OnClickButton)
ON_EVENT(ON_CHANGE,m_list,OnChangeList)
CheckListHide(id,(int)lparam,(int)dparam);
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CComboBox::CComboBox(void) : m_item_height(CONTROLS_COMBO_ITEM_HEIGHT),
m_view_items(CONTROLS_COMBO_ITEMS_VIEW)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CComboBox::~CComboBox(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CComboBox::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- check height
if(y2-y1<CONTROLS_COMBO_MIN_HEIGHT)
return(false);
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateEdit())
return(false);
if(!CreateButton())
return(false);
if(!CreateList())
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create main entry field |
//+------------------------------------------------------------------+
bool CComboBox::CreateEdit(void)
{
//--- create
if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,0,0,Width(),Height()))
return(false);
if(!m_edit.Text(""))
return(false);
if(!m_edit.ReadOnly(true))
return(false);
if(!Add(m_edit))
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create button |
//+------------------------------------------------------------------+
bool CComboBox::CreateButton(void)
{
//--- right align button (try to make equal offsets from top and bottom)
int x1=Width()-(CONTROLS_BUTTON_SIZE+CONTROLS_COMBO_BUTTON_X_OFF);
int y1=(Height()-CONTROLS_BUTTON_SIZE)/2;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_drop.Create(m_chart_id,m_name+"Drop",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_drop.BmpNames("::Include\\Controls\\res\\DropOff.bmp","::Include\\Controls\\res\\DropOn.bmp"))
return(false);
if(!Add(m_drop))
return(false);
m_drop.Locking(true);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create drop-down list |
//+------------------------------------------------------------------+
bool CComboBox::CreateList(void)
{
//--- create
if(m_list.TotalView(m_view_items))
{
if(!m_list.Create(m_chart_id,m_name+"List",m_subwin,0,Height(),Width(),0))
return(false);
if(!Add(m_list))
return(false);
m_list.Hide();
}
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Add item (row) |
//+------------------------------------------------------------------+
bool CComboBox::AddItem(const string item,const long value)
{
//--- add item to list
return(m_list.AddItem(item,value));
}
//+------------------------------------------------------------------+
//| Select item |
//+------------------------------------------------------------------+
bool CComboBox::Select(const int index)
{
if(!m_list.Select(index))
return(false);
//--- call the handler
return(OnChangeList());
}
//+------------------------------------------------------------------+
//| Select item (by text) |
//+------------------------------------------------------------------+
bool CComboBox::SelectByText(const string text)
{
if(!m_list.SelectByText(text))
return(false);
//--- call the handler
return(OnChangeList());
}
//+------------------------------------------------------------------+
//| Select item (by value) |
//+------------------------------------------------------------------+
bool CComboBox::SelectByValue(const long value)
{
if(!m_list.SelectByValue(value))
return(false);
//--- call the handler
return(OnChangeList());
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CComboBox::Show(void)
{
m_edit.Show();
if(IS_ENABLED)
{
m_drop.Show();
}
else
{
m_drop.Hide();
m_edit.Color(CONTROLS_EDIT_COLOR_BORDER);
}
m_list.Hide();
//--- call of the method of the parent class
return(CWnd::Show());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CComboBox::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
FileWriteLong(file_handle,Value());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CComboBox::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
if(!FileIsEnding(file_handle))
SelectByValue(FileReadLong(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on main entry field |
//+------------------------------------------------------------------+
bool CComboBox::OnClickEdit(void)
{
//--- change button state
if(!m_drop.Pressed(!m_drop.Pressed()))
return(false);
//--- call the click on button handler
return(OnClickButton());
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CComboBox::OnClickButton(void)
{
//--- show or hide the drop-down list depending on the button state
return((m_drop.Pressed()) ? ListShow() : ListHide());
}
//+------------------------------------------------------------------+
//| Handler of click on drop-down list |
//+------------------------------------------------------------------+
bool CComboBox::OnChangeList(void)
{
string text=m_list.Select();
//--- hide the list, depress the button
ListHide();
m_drop.Pressed(false);
//--- set text in the main entry field
m_edit.Text(text);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Show the drop-down list |
//+------------------------------------------------------------------+
bool CComboBox::ListShow(void)
{
BringToTop();
//--- show the list
return(m_list.Show());
}
//+------------------------------------------------------------------+
//| Hide drop-down list |
//+------------------------------------------------------------------+
bool CComboBox::ListHide(void)
{
//--- hide the list
return(m_list.Hide());
}
//+------------------------------------------------------------------+
//| Hide the drop-down element if necessary |
//+------------------------------------------------------------------+
void CComboBox::CheckListHide(const int id,int x,int y)
{
//--- check event ID
if(id!=CHARTEVENT_CLICK)
return;
//--- check visibility of the drop-down element
if(!m_list.IsVisible())
return;
//--- check mouse cursor's position
y-=(int)ChartGetInteger(m_chart_id,CHART_WINDOW_YDISTANCE,m_subwin);
if(!m_edit.Contains(x,y) && !m_list.Contains(x,y))
{
m_drop.Pressed(false);
m_list.Hide();
}
}
//+------------------------------------------------------------------+
bool CComboBox::OnEnable(void)
{
//m_drop.ZOrder(0);
m_drop.Show();
m_edit.Color(CONTROLS_EDIT_COLOR);
return(true);
}
bool CComboBox::OnDisable(void)
{
//m_drop.ZOrder(-100);
m_drop.Hide();
m_edit.Color(CONTROLS_EDIT_COLOR_BORDER);
return(true);
}
class ComboBoxResizable: public CComboBox
{
public:
ComboBoxResizable()
{
RTTI;
}
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)
//#include <Layouts/RadioGroupResizable.mqh>
//#include <ControlsPlus/RadioGroup.mqh>
//+------------------------------------------------------------------+
//| RadioGroup.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndClient.mqh"
//#include "RadioButton.mqh"
//+------------------------------------------------------------------+
//| RadioButton.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndContainer.mqh"
//#include "BmpButton.mqh"
//#include "Edit.mqh"
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
#resource "\\Include\\Controls\\res\\RadioButtonOn.bmp"
#resource "\\Include\\Controls\\res\\RadioButtonOff.bmp"
//+------------------------------------------------------------------+
//| Class CRadioButton |
//| Usage: class that implements the "RadioButton" control |
//+------------------------------------------------------------------+
class CRadioButton : public CWndContainer
{
private:
//--- dependent controls
CBmpButton m_button; // button object
CEdit m_label; // label object
public:
CRadioButton(void);
~CRadioButton(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- settings
string Text(void) const { return(m_label.Text()); }
bool Text(const string value) { return(m_label.Text(value)); }
color Color(void) const { return(m_label.Color()); }
bool Color(const color value) { return(m_label.Color(value)); }
//--- state
bool State(void) const { return(m_button.Pressed()); }
bool State(const bool flag) { return(m_button.Pressed(flag)); }
protected:
//--- create dependent controls
virtual bool CreateButton(void);
virtual bool CreateLabel(void);
//--- handlers of the dependent controls events
virtual bool OnClickButton(void);
virtual bool OnClickLabel(void);
// we can't do this with new subclass, because RadioGroup instantiates RadioButton's
// automatically via ArrayResize of object array (not pointer array),
// so it's impossible to store a derived class pointer there
virtual bool OnResize(void) override;
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CRadioButton)
ON_EVENT(ON_CLICK,m_button,OnClickButton)
ON_EVENT(ON_CLICK,m_label,OnClickLabel)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CRadioButton::CRadioButton(void)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CRadioButton::~CRadioButton(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CRadioButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateButton())
return(false);
if(!CreateLabel())
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create button |
//+------------------------------------------------------------------+
bool CRadioButton::CreateButton(void)
{
//--- calculate coordinates
int x1=CONTROLS_RADIO_BUTTON_X_OFF;
int y1=CONTROLS_RADIO_BUTTON_Y_OFF;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE-CONTROLS_BORDER_WIDTH;
//--- create
if(!m_button.Create(m_chart_id,m_name+"Button",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_button.BmpNames("::Include\\Controls\\res\\RadioButtonOff.bmp","::Include\\Controls\\res\\RadioButtonOn.bmp"))
return(false);
if(!Add(m_button))
return(false);
m_button.Locking(true);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create label |
//+------------------------------------------------------------------+
bool CRadioButton::CreateLabel(void)
{
//--- calculate coordinates
int x1=CONTROLS_RADIO_LABEL_X_OFF;
int y1=CONTROLS_RADIO_LABEL_Y_OFF;
int x2=Width();
int y2=Height();
//--- create
if(!m_label.Create(m_chart_id,m_name+"Label",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_label.Text(m_name))
return(false);
if(!Add(m_label))
return(false);
m_label.ReadOnly(true);
m_label.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG);
m_label.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BG);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CRadioButton::OnClickButton(void)
{
//--- if button is in the "turned off" state, turn it on again and complete the handling
//--- this is due to that radio button can not be turned off by clicking on it (it can be only turned on)
if(!m_button.Pressed())
{
//--- turn on the radio button
if(!m_button.Pressed(true))
return(false);
}
//--- send the "changed state" event
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on label |
//+------------------------------------------------------------------+
bool CRadioButton::OnClickLabel(void)
{
//--- if button is in the "turned on" state, simply complete the handling
//--- this is due to that radio button can not be turned off by clicking on it (it can be only turned on)
if(m_button.Pressed())
return(true);
//--- turn on the radio button
m_button.Pressed(true);
//--- return the result of the button click handler
return(OnClickButton());
}
//+------------------------------------------------------------------+
//| Resize the chart object |
//+------------------------------------------------------------------+
bool CRadioButton::OnResize(void)
{
// resize CEdit control, this will trigger OnResize
// for the label chart object (button is always the same size)
m_label.Width(m_rect.Width() - CONTROLS_SCROLL_SIZE - CONTROLS_BORDER_WIDTH);
return true;
}
//#include <Arrays\ArrayString.mqh>
//#include <Arrays\ArrayLong.mqh>
//+------------------------------------------------------------------+
//| Class CRadioGroup |
//| Usage: view and edit radio buttons |
//+------------------------------------------------------------------+
class CRadioGroup : public CWndClient
{
protected:
//--- dependent controls
CRadioButton m_rows[]; // array of the row objects
//--- set up
int m_offset; // index of first visible row in array of rows
int m_total_view; // number of visible rows
int m_item_height; // height of visible row
//--- data
CArrayString m_strings; // array of rows
CArrayLong m_values; // array of values
int m_current; // index of current row in array of rows
public:
CRadioGroup(void);
~CRadioGroup(void);
//--- create
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 void Destroy(const int reason=0);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- fill
virtual bool AddItem(const string item,const long value=0);
//--- data
long Value(void) const { return(m_values.At(m_current)); }
bool Value(const long value);
bool ValueCheck(long value) const;
//--- state
virtual bool Show(void);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
bool CreateButton(const int index);
//--- handlers of the dependent controls events
virtual bool OnVScrollShow(void);
virtual bool OnVScrollHide(void);
virtual bool OnScrollLineDown(void);
virtual bool OnScrollLineUp(void);
virtual bool OnChangeItem(const int row_index);
//--- redraw
virtual bool Redraw(void);
bool RowState(const int index,const bool select);
void Select(const int index);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CRadioGroup)
ON_INDEXED_EVENT(ON_CHANGE,m_rows,OnChangeItem)
EVENT_MAP_END(CWndClient)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CRadioGroup::CRadioGroup(void) : m_offset(0),
m_total_view(0),
m_item_height(CONTROLS_LIST_ITEM_HEIGHT),
m_current(CONTROLS_INVALID_INDEX)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CRadioGroup::~CRadioGroup(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CRadioGroup::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- determine the number of visible rows
m_total_view=(y2-y1)/m_item_height;
//--- check the number of visible rows
if(m_total_view<1)
return(false);
//--- call method of the parent class
if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- set up
if(!m_background.ColorBackground(CONTROLS_RADIOGROUP_COLOR_BG))
return(false);
if(!m_background.ColorBorder(CONTROLS_RADIOGROUP_COLOR_BORDER))
return(false);
//--- create dependent controls
ArrayResize(m_rows,m_total_view);
for(int i=0;i<m_total_view;i++)
if(!CreateButton(i))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Delete group of controls |
//+------------------------------------------------------------------+
void CRadioGroup::Destroy(const int reason)
{
//--- call of the method of the parent class
CWndClient::Destroy(reason);
//--- clear items
m_strings.Clear();
m_values.Clear();
}
//+------------------------------------------------------------------+
//| Create "row" |
//+------------------------------------------------------------------+
bool CRadioGroup::CreateButton(const int index)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH+m_item_height*index;
int x2=Width()-CONTROLS_BORDER_WIDTH;
int y2=y1+m_item_height;
//--- create
if(!m_rows[index].Create(m_chart_id,m_name+"Item"+IntegerToString(index),m_subwin,x1,y1,x2,y2))
return(false);
if(!m_rows[index].Text(""))
return(false);
if(!Add(m_rows[index]))
return(false);
m_rows[index].Hide();
//---
return(true);
}
//+------------------------------------------------------------------+
//| Add item (row) |
//+------------------------------------------------------------------+
bool CRadioGroup::AddItem(const string item,const long value)
{
//--- check value
if(value!=0 && !ValueCheck(value))
return(false);
//--- add
if(!m_strings.Add(item))
return(false);
if(!m_values.Add(value))
return(false);
//--- number of items
int total=m_strings.Total();
//--- exit if number of items does not exceed the size of visible area
if(total<m_total_view+1)
{
if(IS_VISIBLE && total!=0)
m_rows[total-1].Show();
return(Redraw());
}
//--- if number of items exceeded the size of visible area
if(total==m_total_view+1)
{
//--- enable vertical scrollbar
if(!VScrolled(true))
return(false);
//--- and immediately make it invisible (if needed)
if(!IS_VISIBLE)
m_scroll_v.Visible(false);
}
//--- set up the scrollbar
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRadioGroup::Value(const long value)
{
//--- ???????? ?????? ?????????????? ? ??????
int total=m_values.Total();
//---
for(int i=0;i<total;i++)
if(m_values.At(i)==value)
Select(i+m_offset);
//---
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRadioGroup::ValueCheck(long value) const
{
//--- ??????????? ???????? ?? ?????? ??????????? ??? ????????????
int total=m_values.Total();
//---
for(int i=0;i<total;i++)
if(m_values.At(i)==value)
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Makes the group visible |
//+------------------------------------------------------------------+
bool CRadioGroup::Show(void)
{
// call of the method of the parent class
if(!CWndClient::Show())
return(false);
// loop by rows
int total = m_values.Total();
for(int i = total; i < m_total_view; i++)
m_rows[i].Hide();
for(int i = m_total_view; i < ArraySize(m_rows); i++)
m_rows[i].Hide();
// handled
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRadioGroup::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
FileWriteLong(file_handle,Value());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CRadioGroup::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
if(!FileIsEnding(file_handle))
Value(FileReadLong(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Sett current item |
//+------------------------------------------------------------------+
void CRadioGroup::Select(const int index)
{
//--- disable the "ON" state
if(m_current!=-1)
RowState(m_current-m_offset,false);
//--- enable the "ON" state
if(index!=-1)
RowState(index-m_offset,true);
//--- save value
m_current=index;
}
//+------------------------------------------------------------------+
//| Redraw |
//+------------------------------------------------------------------+
bool CRadioGroup::Redraw(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- copy text
if(!m_rows[i].Text(m_strings.At(i+m_offset)))
return(false);
//--- select
if(!RowState(i,(m_current==i+m_offset)))
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Change state |
//+------------------------------------------------------------------+
bool CRadioGroup::RowState(const int index,const bool select)
{
//--- check index
if(index<0 || index>=ArraySize(m_rows))
return(true);
//--- change state
return(m_rows[index].State(select));
}
//+------------------------------------------------------------------+
//| Handler of the "Show vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CRadioGroup::OnVScrollShow(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to shown vertical scrollbar
m_rows[i].Width(Width()-(CONTROLS_SCROLL_SIZE+2*CONTROLS_BORDER_WIDTH+1));
}
//--- check visibility
if(!IS_VISIBLE)
{
m_scroll_v.Visible(false);
return(true);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Hide vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CRadioGroup::OnVScrollHide(void)
{
//--- check visibility
if(!IS_VISIBLE)
return(true);
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to hidden vertical scroll bar
m_rows[i].Width(Width()-2*CONTROLS_BORDER_WIDTH-1);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll up for one row" event |
//+------------------------------------------------------------------+
bool CRadioGroup::OnScrollLineUp(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll down for one row" event |
//+------------------------------------------------------------------+
bool CRadioGroup::OnScrollLineDown(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of changing a "row" state |
//+------------------------------------------------------------------+
bool CRadioGroup::OnChangeItem(const int row_index)
{
//--- select "row"
Select(row_index+m_offset);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//#include "GroupTemplate.mqh"
//+------------------------------------------------------------------+
//| GroupTemplate.mqh |
//| Copyright (c) 2020, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//| Core CheckGroupResizable, RadioGroupResizable, ListViewResizable |
//+------------------------------------------------------------------+
template<typename T>
class GroupTemplate: public T // T = CCheckGroup, CRadioGroup, CListView
{
protected:
int WIDTH_ADJUSTMENT;
public:
GroupTemplate(): WIDTH_ADJUSTMENT(0)
{
RTTI;
}
protected:
virtual bool isSelected(const int index) = 0;
virtual bool createElement(const int index) = 0;
virtual bool Redraw(void) override
{
for(int i = 0; i < ArraySize(m_rows); i++)
{
if(i + m_offset < m_strings.Total() && i < m_total_view)
{
m_rows[i].Show();
CRect r;
r.left = Left() + CONTROLS_BORDER_WIDTH;
r.top = Top() + CONTROLS_BORDER_WIDTH + m_item_height * i;
r.right = Right() - 2*CONTROLS_BORDER_WIDTH - 1 /*- WIDTH_ADJUSTMENT*/ - (m_scroll_v.IsVisible() ? CONTROLS_SCROLL_SIZE : 0);
r.bottom = r.top + m_item_height;
m_rows[i].Move(r.left, r.top);
m_rows[i].Size(r.right - r.left, r.bottom - r.top);
m_rows[i].Text(m_strings[i + m_offset]);
RowState(i, isSelected(i + m_offset));
}
else
{
m_rows[i].Hide();
}
}
return true;
}
virtual bool OnResize(void) override
{
if(!IsVisible()) return true;
int new_total_view = (Height() - 2 * CONTROLS_BORDER_WIDTH) / m_item_height;
// if minimized/hidden
if(new_total_view < 0) return T::OnResize();
const int n = ArraySize(m_rows);
if(new_total_view > n // first time expanding
&& n < m_strings.Total())
{
const int m = MathMin(m_strings.Total(), new_total_view);
ArrayResize(m_rows, m);
for(int i = n; i < m; i++)
{
if(!createElement(i)) return(false);
m_rows[i].Show();
m_rows[i].Id(rand() | (rand() << 32));
}
m_total_view = m;
m_scroll_v.MaxPos(m_strings.Total() - m_total_view + m_offset);
}
else
if(new_total_view < m_total_view)
{
for(int i = new_total_view; i < n; i++)
{
m_rows[i].Hide();
}
m_total_view = new_total_view;
m_scroll_v.MaxPos(m_strings.Total() - m_total_view + m_offset);
}
else
if(new_total_view > m_total_view
&& new_total_view <= n) // second time expanding
{
for(int i = m_total_view; i < new_total_view; i++)
{
m_rows[i].Show();
}
m_total_view = new_total_view;
m_scroll_v.MaxPos(m_strings.Total() - m_total_view + m_offset);
}
Redraw();
return T::OnResize();
}
};
class RadioGroupResizable: public GroupTemplate<CRadioGroup>
{
public:
RadioGroupResizable()
{
RTTI;
WIDTH_ADJUSTMENT = CONTROLS_BUTTON_SIZE;
}
protected:
virtual bool isSelected(const int index) override
{
return m_current == index;
}
virtual bool createElement(const int index) override
{
return CreateButton(index);
}
};
//#include <Layouts/CheckGroupResizable.mqh>
//#include <ControlsPlus/CheckGroup.mqh>
//+------------------------------------------------------------------+
//| CheckGroup.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndClient.mqh"
//#include "CheckBox.mqh"
//#include <Arrays\ArrayString.mqh>
//#include <Arrays\ArrayLong.mqh>
//#include <Arrays\ArrayInt.mqh>
//+------------------------------------------------------------------+
//| ArrayInt.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "Array.mqh"
//+------------------------------------------------------------------+
//| Class CArrayInt. |
//| Puprose: Class of dynamic array of variables |
//| of int or uint type. |
//| Derives from class CArray. |
//+------------------------------------------------------------------+
class CArrayInt : public CArray
{
protected:
int m_data[]; // data array
public:
CArrayInt(void);
~CArrayInt(void);
//--- method of identifying the object
virtual int Type(void) const { return(TYPE_INT); }
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- methods of managing dynamic memory
bool Reserve(const int size);
bool Resize(const int size);
bool Shutdown(void);
//--- methods of filling the array
bool Add(const int element);
bool AddArray(const int &src[]);
bool AddArray(const CArrayInt *src);
bool Insert(const int element,const int pos);
bool InsertArray(const int &src[],const int pos);
bool InsertArray(const CArrayInt *src,const int pos);
bool AssignArray(const int &src[]);
bool AssignArray(const CArrayInt *src);
//--- method of access to the array
int At(const int index) const;
int operator[](const int index) const { return(At(index)); }
//--- methods of searching for minimum and maximum
int Minimum(const int start,const int count) const { return(CArray::Minimum(m_data,start,count)); }
int Maximum(const int start,const int count) const { return(CArray::Maximum(m_data,start,count)); }
//--- methods of changing
bool Update(const int index,const int element);
bool Shift(const int index,const int shift);
//--- methods of deleting
bool Delete(const int index);
bool DeleteRange(int from,int to);
//--- methods for comparing arrays
bool CompareArray(const int &array[]) const;
bool CompareArray(const CArrayInt *array) const;
//--- methods for working with the sorted array
bool InsertSort(const int element);
int Search(const int element) const;
int SearchGreat(const int element) const;
int SearchLess(const int element) const;
int SearchGreatOrEqual(const int element) const;
int SearchLessOrEqual(const int element) const;
int SearchFirst(const int element) const;
int SearchLast(const int element) const;
int SearchLinear(const int element) const;
protected:
virtual void QuickSort(int beg,int end,const int mode=0);
int QuickSearch(const int element) const;
int MemMove(const int dest,const int src,int count);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CArrayInt::CArrayInt(void)
{
//--- initialize protected data
m_data_max=ArraySize(m_data);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CArrayInt::~CArrayInt(void)
{
if(m_data_max!=0)
Shutdown();
}
//+------------------------------------------------------------------+
//| Moving the memory within a single array |
//+------------------------------------------------------------------+
int CArrayInt::MemMove(const int dest,const int src,int count)
{
int i;
//--- check parameters
if(dest<0 || src<0 || count<0)
return(-1);
//--- check count
if(src+count>m_data_total)
count=m_data_total-src;
if(count<0)
return(-1);
//--- no need to copy
if(dest==src || count==0)
return(dest);
//--- check data total
if(dest+count>m_data_total)
{
if(m_data_max<dest+count)
return(-1);
m_data_total=dest+count;
}
//--- copy
if(dest<src)
{
//--- copy from left to right
for(i=0;i<count;i++)
m_data[dest+i]=m_data[src+i];
}
else
{
//--- copy from right to left
for(i=count-1;i>=0;i--)
m_data[dest+i]=m_data[src+i];
}
//--- successful
return(dest);
}
//+------------------------------------------------------------------+
//| Request for more memory in an array. Checks if the requested |
//| number of free elements already exists; allocates additional |
//| memory with a given step |
//+------------------------------------------------------------------+
bool CArrayInt::Reserve(const int size)
{
int new_size;
//--- check
if(size<=0)
return(false);
//--- resize array
if(Available()<size)
{
new_size=m_data_max+m_step_resize*(1+(size-Available())/m_step_resize);
if(new_size<0)
//--- overflow occurred when calculating new_size
return(false);
if((m_data_max=ArrayResize(m_data,new_size))==-1)
m_data_max=ArraySize(m_data);
}
//--- result
return(Available()>=size);
}
//+------------------------------------------------------------------+
//| Resizing (with removal of elements on the right) |
//+------------------------------------------------------------------+
bool CArrayInt::Resize(const int size)
{
int new_size;
//--- check
if(size<0)
return(false);
//--- resize array
new_size=m_step_resize*(1+size/m_step_resize);
if(m_data_max!=new_size)
{
if((m_data_max=ArrayResize(m_data,new_size))==-1)
{
m_data_max=ArraySize(m_data);
return(false);
}
}
if(m_data_total>size)
m_data_total=size;
//--- result
return(m_data_max==new_size);
}
//+------------------------------------------------------------------+
//| Complete cleaning of the array with the release of memory |
//+------------------------------------------------------------------+
bool CArrayInt::Shutdown(void)
{
//--- check
if(m_data_max==0)
return(true);
//--- clean
if(ArrayResize(m_data,0)==-1)
return(false);
m_data_total=0;
m_data_max=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array |
//+------------------------------------------------------------------+
bool CArrayInt::Add(const int element)
{
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- add
m_data[m_data_total++]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayInt::AddArray(const int &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding an element to the end of the array from another array |
//+------------------------------------------------------------------+
bool CArrayInt::AddArray(const CArrayInt *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- add
for(int i=0;i<num;i++)
m_data[m_data_total++]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting an element in the specified position |
//+------------------------------------------------------------------+
bool CArrayInt::Insert(const int element,const int pos)
{
//--- check/reserve elements of array
if(pos<0 || !Reserve(1))
return(false);
//--- insert
m_data_total++;
if(pos<m_data_total-1)
{
if(MemMove(pos+1,pos,m_data_total-pos-1)<0)
return(false);
m_data[pos]=element;
}
else
m_data[m_data_total-1]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayInt::InsertArray(const int &src[],const int pos)
{
int num=ArraySize(src);
//--- check/reserve elements of array
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Inserting elements in the specified position |
//+------------------------------------------------------------------+
bool CArrayInt::InsertArray(const CArrayInt *src,const int pos)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.Total();
if(!Reserve(num))
return(false);
//--- insert
if(MemMove(num+pos,pos,m_data_total-pos)<0)
return(false);
for(int i=0;i<num;i++)
m_data[i+pos]=src.m_data[i];
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayInt::AssignArray(const int &src[])
{
int num=ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src[i];
m_data_total++;
}
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CArrayInt::AssignArray(const CArrayInt *src)
{
int num;
//--- check
if(!CheckPointer(src))
return(false);
//--- check/reserve elements of array
num=src.m_data_total;
Clear();
if(m_data_max<num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i=0;i<num;i++)
{
m_data[i]=src.m_data[i];
m_data_total++;
}
m_sort_mode=src.SortMode();
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Access to data in the specified position |
//+------------------------------------------------------------------+
int CArrayInt::At(const int index) const
{
//--- check
if(index<0 || index>=m_data_total)
return(INT_MAX);
//--- result
return(m_data[index]);
}
//+------------------------------------------------------------------+
//| Updating element in the specified position |
//+------------------------------------------------------------------+
bool CArrayInt::Update(const int index,const int element)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- update
m_data[index]=element;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Moving element from the specified position |
//| on the specified shift |
//+------------------------------------------------------------------+
bool CArrayInt::Shift(const int index,const int shift)
{
int tmp_int;
//--- check
if(index<0 || index+shift<0 || index+shift>=m_data_total)
return(false);
if(shift==0)
return(true);
//--- move
tmp_int=m_data[index];
if(shift>0)
{
if(MemMove(index,index+1,shift)<0)
return(false);
}
else
{
if(MemMove(index+shift+1,index+shift,-shift)<0)
return(false);
}
m_data[index+shift]=tmp_int;
m_sort_mode=-1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting element from the specified position |
//+------------------------------------------------------------------+
bool CArrayInt::Delete(const int index)
{
//--- check
if(index<0 || index>=m_data_total)
return(false);
//--- delete
if(index<m_data_total-1 && MemMove(index,index+1,m_data_total-index-1)<0)
return(false);
m_data_total--;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Deleting range of elements |
//+------------------------------------------------------------------+
bool CArrayInt::DeleteRange(int from,int to)
{
//--- check
if(from<0 || to<0)
return(false);
if(from>to || from>=m_data_total)
return(false);
//--- delete
if(to>=m_data_total-1)
to=m_data_total-1;
if(MemMove(from,to+1,m_data_total-to-1)<0)
return(false);
m_data_total-=to-from+1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayInt::CompareArray(const int &array[]) const
{
//--- compare
if(m_data_total!=ArraySize(array))
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Equality comparison of two arrays |
//+------------------------------------------------------------------+
bool CArrayInt::CompareArray(const CArrayInt *array) const
{
//--- check
if(!CheckPointer(array))
return(false);
//--- compare
if(m_data_total!=array.m_data_total)
return(false);
for(int i=0;i<m_data_total;i++)
if(m_data[i]!=array.m_data[i])
return(false);
//--- equal
return(true);
}
//+------------------------------------------------------------------+
//| Method QuickSort |
//+------------------------------------------------------------------+
void CArrayInt::QuickSort(int beg,int end,const int mode)
{
int i,j;
int p_int,t_int;
//--- check
if(beg<0 || end<0)
return;
//--- sort
i=beg;
j=end;
while(i<end)
{
//--- ">>1" is quick division by 2
p_int=m_data[(beg+end)>>1];
while(i<j)
{
while(m_data[i]<p_int)
{
//--- control the output of the array bounds
if(i==m_data_total-1)
break;
i++;
}
while(m_data[j]>p_int)
{
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
if(i<=j)
{
t_int=m_data[i];
m_data[i++]=m_data[j];
m_data[j]=t_int;
//--- control the output of the array bounds
if(j==0)
break;
j--;
}
}
if(beg<j)
QuickSort(beg,j);
beg=i;
j=end;
}
}
//+------------------------------------------------------------------+
//| Inserting element in a sorted array |
//+------------------------------------------------------------------+
bool CArrayInt::InsertSort(const int element)
{
int pos;
//--- check
if(!IsSorted())
return(false);
//--- check/reserve elements of array
if(!Reserve(1))
return(false);
//--- if the array is empty, add an element
if(m_data_total==0)
{
m_data[m_data_total++]=element;
return(true);
}
//--- find position and insert
pos=QuickSearch(element);
if(m_data[pos]>element)
Insert(element,pos);
else
Insert(element,pos+1);
//--- restore the sorting flag after Insert(...)
m_sort_mode=0;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Search of position of element in a array |
//+------------------------------------------------------------------+
int CArrayInt::SearchLinear(const int element) const
{
//--- check
if(m_data_total==0)
return(-1);
//---
for(int i=0;i<m_data_total;i++)
if(m_data[i]==element)
return(i);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Quick search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::QuickSearch(const int element) const
{
int i,j,m=-1;
int t_int;
//--- search
i=0;
j=m_data_total-1;
while(j>=i)
{
//--- ">>1" is quick division by 2
m=(j+i)>>1;
if(m<0 || m>=m_data_total)
break;
t_int=m_data[m];
if(t_int==element)
break;
if(t_int>element)
j=m-1;
else
i=m+1;
}
//--- position
return(m);
}
//+------------------------------------------------------------------+
//| Search of position of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::Search(const int element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than |
//| specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchGreat(const int element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]<=element)
if(++pos==m_data_total)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than |
//| specified in the sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchLess(const int element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
while(m_data[pos]>=element)
if(pos--==0)
return(-1);
//--- position
return(pos);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is greater than or |
//| equal to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchGreatOrEqual(const int element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos<m_data_total;pos++)
if(m_data[pos]>=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Search position of the first element which is less than or equal |
//| to the specified in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchLessOrEqual(const int element) const
{
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
for(int pos=QuickSearch(element);pos>=0;pos--)
if(m_data[pos]<=element)
return(pos);
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of first appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchFirst(const int element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(pos--==0)
break;
return(pos+1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Find position of last appearance of element in a sorted array |
//+------------------------------------------------------------------+
int CArrayInt::SearchLast(const int element) const
{
int pos;
//--- check
if(m_data_total==0 || !IsSorted())
return(-1);
//--- search
pos=QuickSearch(element);
if(m_data[pos]==element)
{
while(m_data[pos]==element)
if(++pos==m_data_total)
break;
return(pos-1);
}
//--- not found
return(-1);
}
//+------------------------------------------------------------------+
//| Writing array to file |
//+------------------------------------------------------------------+
bool CArrayInt::Save(const int file_handle)
{
int i=0;
//--- check
if(!CArray::Save(file_handle))
return(false);
//--- write array length
if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE)
return(false);
//--- write array
for(i=0;i<m_data_total;i++)
if(FileWriteInteger(file_handle,m_data[i],INT_VALUE)!=INT_VALUE)
break;
//--- result
return(i==m_data_total);
}
//+------------------------------------------------------------------+
//| Reading array from file |
//+------------------------------------------------------------------+
bool CArrayInt::Load(const int file_handle)
{
int i=0,num;
//--- check
if(!CArray::Load(file_handle))
return(false);
//--- read array length
num=FileReadInteger(file_handle,INT_VALUE);
//--- read array
Clear();
if(num!=0)
{
if(!Reserve(num))
return(false);
for(i=0;i<num;i++)
{
m_data[i]=FileReadInteger(file_handle,INT_VALUE);
m_data_total++;
if(FileIsEnding(file_handle))
break;
}
}
m_sort_mode=-1;
//--- result
return(m_data_total==num);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class CCheckGroup |
//| Usage: view and edit group of flags |
//+------------------------------------------------------------------+
class CCheckGroup : public CWndClient
{
protected:
//--- dependent controls
CCheckBox m_rows[]; // array of the row objects
//--- set up
int m_offset; // index of first visible row in array of rows
int m_total_view; // number of visible rows
int m_item_height; // height of visible row
//--- data
CArrayString m_strings; // array of rows
CArrayLong m_values; // array of values
CArrayInt m_states; // array of states
long m_value; // current value
int m_current; // index of current row in array of rows
public:
CCheckGroup(void);
~CCheckGroup(void);
//--- create
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 void Destroy(const int reason=0);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- fill
virtual bool AddItem(const string item,const long value=0);
//--- data
long Value(void) const;
bool Value(const long value);
int Check(const int idx) const;
bool Check(const int idx,const int value);
//--- state
virtual bool Show(void);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
bool CreateButton(const int index);
//--- handlers of the dependent controls events
virtual bool OnVScrollShow(void);
virtual bool OnVScrollHide(void);
virtual bool OnScrollLineDown(void);
virtual bool OnScrollLineUp(void);
virtual bool OnChangeItem(const int row_index);
//--- redraw
virtual bool Redraw(void);
bool RowState(const int index,const bool select);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CCheckGroup)
ON_INDEXED_EVENT(ON_CHANGE,m_rows,OnChangeItem)
EVENT_MAP_END(CWndClient)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CCheckGroup::CCheckGroup(void) : m_offset(0),
m_total_view(0),
m_item_height(CONTROLS_LIST_ITEM_HEIGHT),
m_current(CONTROLS_INVALID_INDEX),
m_value(0)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CCheckGroup::~CCheckGroup(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CCheckGroup::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- determine the number of visible rows
m_total_view=(y2-y1)/m_item_height;
//--- check the number of visible rows
if(m_total_view<1)
return(false);
//--- call method of the parent class
if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- set up
if(!m_background.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG))
return(false);
if(!m_background.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BORDER))
return(false);
//--- create dependent controls
ArrayResize(m_rows,m_total_view);
for(int i=0;i<m_total_view;i++)
if(!CreateButton(i))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Delete group of controls |
//+------------------------------------------------------------------+
void CCheckGroup::Destroy(const int reason)
{
//--- call of the method of the parent class
CWndClient::Destroy(reason);
//--- clear items
m_strings.Clear();
m_values.Clear();
m_states.Clear();
}
//+------------------------------------------------------------------+
//| Create "row" |
//+------------------------------------------------------------------+
bool CCheckGroup::CreateButton(const int index)
{
//--- calculate coordinates
int x1=CONTROLS_BORDER_WIDTH;
int y1=CONTROLS_BORDER_WIDTH+m_item_height*index;
int x2=Width()-CONTROLS_BORDER_WIDTH;
int y2=y1+m_item_height;
//--- create
if(!m_rows[index].Create(m_chart_id,m_name+"Item"+IntegerToString(index),m_subwin,x1,y1,x2,y2))
return(false);
if(!m_rows[index].Text(""))
return(false);
if(!Add(m_rows[index]))
return(false);
m_rows[index].Hide();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Add item (row) |
//+------------------------------------------------------------------+
bool CCheckGroup::AddItem(const string item,const long value)
{
//--- add
if(!m_strings.Add(item))
return(false);
if(!m_values.Add(value))
return(false);
if(!m_states.Add(0))
return(false);
//--- number of items
int total=m_strings.Total();
//--- exit if number of items does not exceed the size of visible area
if(total<m_total_view+1)
{
if(IS_VISIBLE && total!=0)
m_rows[total-1].Show();
return(Redraw());
}
//--- if number of items exceeded the size of visible area
if(total==m_total_view+1)
{
//--- enable vertical scrollbar
if(!VScrolled(true))
return(false);
//--- and immediately make it invisible (if needed)
if(!IS_VISIBLE)
m_scroll_v.Visible(false);
}
//--- set up the scrollbar
m_scroll_v.MaxPos(m_strings.Total()-m_total_view);
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
long CCheckGroup::Value(void) const
{
return(m_value);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckGroup::Value(const long value)
{
m_value=value;
//---
return(Redraw());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CCheckGroup::Check(const int idx) const
{
//--- check
if(idx>=m_values.Total())
return(0);
//---
return(m_states[idx]);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckGroup::Check(const int idx,const int value)
{
//--- check
if(idx>=m_values.Total())
return(false);
//---
bool res=(m_states.Update(idx,value) && Redraw());
//--- change value
if(res && idx<64)
{
if(m_rows[idx].Checked())
Value(m_value|m_values.At(idx));
else
Value(m_value&(~m_values.At(idx)));
}
//---
return(res);
}
//+------------------------------------------------------------------+
//| Makes the group visible |
//+------------------------------------------------------------------+
bool CCheckGroup::Show(void)
{
// call of the method of the parent class
if(!CWndClient::Show())
return(false);
// loop by rows
int total = m_values.Total();
for(int i = total; i < m_total_view; i++)
m_rows[i].Hide();
for(int i = m_total_view; i < ArraySize(m_rows); i++)
m_rows[i].Hide();
// handled
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckGroup::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
FileWriteLong(file_handle,Value());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CCheckGroup::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
if(!FileIsEnding(file_handle))
Value(FileReadLong(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Redraw |
//+------------------------------------------------------------------+
bool CCheckGroup::Redraw(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- copy text
if(!m_rows[i].Text(m_strings[i+m_offset]))
return(false);
//--- select
if(!RowState(i,m_states[i+m_offset]!=0))
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Change state |
//+------------------------------------------------------------------+
bool CCheckGroup::RowState(const int index,const bool select)
{
//--- check index
if(index<0 || index>=ArraySize(m_rows))
return(true);
//--- change state
return(m_rows[index].Checked(select));
}
//+------------------------------------------------------------------+
//| Handler of the "Show vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CCheckGroup::OnVScrollShow(void)
{
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to shown vertical scrollbar
m_rows[i].Width(Width()-(CONTROLS_SCROLL_SIZE+2*CONTROLS_BORDER_WIDTH+1));
}
//--- check visibility
if(!IS_VISIBLE)
{
m_scroll_v.Visible(false);
return(true);
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Hide vertical scrollbar" event |
//+------------------------------------------------------------------+
bool CCheckGroup::OnVScrollHide(void)
{
//--- check visibility
if(!IS_VISIBLE)
return(true);
//--- loop by "rows"
for(int i=0;i<m_total_view;i++)
{
//--- resize "rows" according to hidden vertical scroll bar
m_rows[i].Width(Width()-2*CONTROLS_BORDER_WIDTH-1);
}
//--- event is handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll up for one row" event |
//+------------------------------------------------------------------+
bool CCheckGroup::OnScrollLineUp(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of the "Scroll down for one row" event |
//+------------------------------------------------------------------+
bool CCheckGroup::OnScrollLineDown(void)
{
//--- get new offset
m_offset=m_scroll_v.CurrPos();
//--- redraw
return(Redraw());
}
//+------------------------------------------------------------------+
//| Handler of changing a "row" state |
//+------------------------------------------------------------------+
bool CCheckGroup::OnChangeItem(const int row_index)
{
//--- change value
m_states.Update(row_index+m_offset,m_rows[row_index].Checked());
if(row_index+m_offset<64)
{
if(m_rows[row_index].Checked())
Value(m_value|m_values.At(row_index+m_offset));
else
Value(m_value&(~m_values.At(row_index+m_offset)));
}
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//#include "GroupTemplate.mqh"
class CheckGroupResizable: public GroupTemplate<CCheckGroup>
{
public:
CheckGroupResizable()
{
RTTI;
WIDTH_ADJUSTMENT = CONTROLS_BUTTON_SIZE;
}
protected:
virtual bool isSelected(const int index) override
{
return m_states[index] != 0;
}
virtual bool createElement(const int index) override
{
return CreateButton(index);
}
};
//#include <Layouts/ListViewResizable.mqh>
//#include <ControlsPlus/ListView.mqh>
//#include "GroupTemplate.mqh"
class ListViewResizable: public GroupTemplate<CListView>
{
public:
ListViewResizable()
{
RTTI;
}
void forceVScroll()
{
// make sure the scroll is shown
// (it may remain hidden in some cases due to a bug in SCL)
m_scroll_v.Show();
}
void adjustVSize()
{
OnResize(); // adjust number of rows (objects)
}
protected:
virtual bool isSelected(const int index) override
{
return m_current == index;
}
virtual bool createElement(const int index) override
{
return CreateRow(index);
}
};
//#include <Layouts/AppDialogResizable.mqh>
//+------------------------------------------------------------------+
//| AppDialogResizable.mqh |
//| Copyright (c) 2019-2021, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//+------------------------------------------------------------------+
//#include <ControlsPlus/Dialog.mqh>
//#include <ControlsPlus/Button.mqh>
#resource "\\Include\\Layouts\\png\\Expand2.csv"
#resource "\\Include\\Layouts\\png\\size6.csv"
#resource "\\Include\\Layouts\\png\\size10.csv"
class AppDialogResizable: 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;
static int s_contained;
static int s_index;
int m_contained;
int m_myid;
// 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;
virtual bool Save(const int handle) override;
virtual bool Load(const int handle) 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 restore = false) {};
public:
AppDialogResizable(): m_maximized(false), m_sizing(false), m_contained(0) { RTTI; }
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; }
};
static int AppDialogResizable::s_contained = 0;
static int AppDialogResizable::s_index = 0;
void AppDialogResizable::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
if(id == CHARTEVENT_CHART_CHANGE)
{
if(OnChartChange(lparam, dparam, sparam)) return;
}
else if(id == CHARTEVENT_MOUSE_MOVE)
{
const bool c = Contains((int)lparam, (int)dparam);
const bool scroll = !c && (m_drag_object == NULL);
if(!scroll) s_contained |= m_myid;
else s_contained &= ~m_myid;
//if((TerminalInfoInteger(TERMINAL_KEYSTATE_CAPSLOCK) & 1) != 0)
//{
// printf("chscrl %s %s [%x] %x %x", this.Name(), (scroll ? "true" : "false"), m_myid, m_contained, s_contained);
//}
if(s_contained != m_contained)
{
ChartSetInteger(ChartID(), CHART_MOUSE_SCROLL, !s_contained);
m_contained = s_contained;
}
}
CAppDialog::ChartEvent(id, lparam, dparam, sparam);
}
EVENT_MAP_BEGIN(AppDialogResizable)
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 AppDialogResizable::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;
}
m_myid = 1 << s_index;
s_index++;
return true;
}
bool AppDialogResizable::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("::Include\\Layouts\\png\\Expand2.csv", "::Include\\Controls\\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 AppDialogResizable::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("::Include\\Layouts\\png\\size6.csv", "::Include\\Layouts\\png\\size10.csv")) 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 AppDialogResizable::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 AppDialogResizable::OnClickButtonSizeFixMe(void)
{
if(m_minimized)
{
Destroy();
}
}
void AppDialogResizable::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 AppDialogResizable::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(true);
}
void AppDialogResizable::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 AppDialogResizable::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 AppDialogResizable::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);
}
if(!m_minimized)
{
SelfAdjustment();
}
}
bool AppDialogResizable::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 AppDialogResizable::OnDialogDragStart(void)
{
if(m_maximized) return false;
return CAppDialog::OnDialogDragStart();
}
//+------------------------------------------------------------------+
//| Continue dragging the dialog box |
//+------------------------------------------------------------------+
bool AppDialogResizable::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 AppDialogResizable::OnDialogDragEnd(void)
{
m_contained = 0;
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;
}
bool AppDialogResizable::Save(const int handle) override
{
FileWriteInteger(handle, m_maximized);
return CAppDialog::Save(handle);
}
bool AppDialogResizable::Load(const int handle) override
{
m_maximized = (bool)FileReadInteger(handle);
return CAppDialog::Load(handle);
}
//#include <Layouts/LayoutMonitors.mqh>
//+------------------------------------------------------------------+
//| LayoutMonitors.mqh |
//| Copyright (c) 2020, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//| GUI Layout declarative language |
//| (MQL5 standard library controls support) |
//| https://www.mql5.com/ru/articles/7795/ |
//+------------------------------------------------------------------+
class StateMonitor
{
public:
virtual void notify(void *sender) = 0;
};
class Publisher
{
public:
virtual void subscribe(StateMonitor *ptr) = 0;
virtual void unsubscribe(StateMonitor *ptr) = 0;
};
template<typename V>
class ValuePublisher: public Publisher
{
protected:
string _rtti;
V value;
StateMonitor *dependencies[];
public:
ValuePublisher()
{
RTTI;
}
V operator~(void) const
{
return value;
}
void operator=(const V &v)
{
value = v;
for(int i = 0; i < ArraySize(dependencies); i++)
{
dependencies[i].notify(&this);
}
}
void operator=(V v)
{
value = v;
for(int i = 0; i < ArraySize(dependencies); i++)
{
dependencies[i].notify(&this);
}
}
virtual void subscribe(StateMonitor *ptr) override
{
const int n = ArraySize(dependencies);
ArrayResize(dependencies, n + 1);
dependencies[n] = ptr;
}
virtual void unsubscribe(StateMonitor *ptr) override
{
const int n = ArraySize(dependencies);
bool found = false;
for(int i = 0, j = 0; i < n; i++, j++)
{
if(i != j)
{
dependencies[j] = dependencies[i];
}
else
if(dependencies[i] == ptr)
{
j--;
found = true;
}
}
if(found)
{
ArrayResize(dependencies, n - 1);
}
}
};
template<typename V>
class StdValue: public ValuePublisher<V>
{
protected:
CWnd *provider;
public:
StdValue()
{
RTTI;
}
void bind(CWnd *ptr)
{
provider = ptr;
}
CWnd *backlink() const
{
return provider;
}
};
template<typename C>
class EnableStateMonitorBase: public StateMonitor
{
protected:
Publisher *sources[];
C *control;
public:
EnableStateMonitorBase(): control(NULL) {}
virtual void attach(C *c)
{
control = c;
for(int i = 0; i < ArraySize(sources); i++)
{
if(control)
{
sources[i].subscribe(&this);
}
else
{
sources[i].unsubscribe(&this);
}
}
}
virtual bool isEnabled(void) = 0;
};
class EnableStateMonitor: public EnableStateMonitorBase<CWnd>
{
public:
EnableStateMonitor() {}
void notify(void *sender) override
{
if(control)
{
if(isEnabled())
{
control.Enable();
}
else
{
control.Disable();
}
}
}
};
template<typename C>
class Notifiable: public C
{
public:
virtual bool onEvent(const int event, void *parent) { return false; };
};
template<typename C,typename V>
class PlainTypeNotifiable: public Notifiable<C>
{
public:
virtual V value() = 0;
};
template<typename C, typename V>
class NotifiableProperty: public PlainTypeNotifiable<C,V>
{
protected:
StdValue<V> *property;
public:
NotifiableProperty()
{
RTTI;
}
void bind(StdValue<V> *prop)
{
property = prop;
property.bind(&this);
property = value();
}
virtual bool onEvent(const int event, void *parent) override
{
if(event == ON_CHANGE || event == ON_END_EDIT)
{
property = value();
return true;
}
return false;
};
};
//#include <Layouts/LayoutStdLib.mqh>
//+------------------------------------------------------------------+
//| LayoutStdLib.mqh |
//| Copyright (c) 2020, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//| GUI Layout declarative language |
//| (MQL5 standard library controls support) |
//| https://www.mql5.com/ru/articles/7734/ |
//| https://www.mql5.com/ru/articles/7795/ |
//+------------------------------------------------------------------+
//#include <ControlsPlus/Wnd.mqh>
//#include <ControlsPlus/WndObj.mqh>
//#include <ControlsPlus/WndClient.mqh>
//#include <ControlsPlus/WndContainer.mqh>
//#include <ControlsPlus/Dialog.mqh>
//#include <ControlsPlus/Button.mqh>
//#include <ControlsPlus/Edit.mqh>
//#include <ControlsPlus/SpinEdit.mqh>
//+------------------------------------------------------------------+
//| SpinEdit.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndContainer.mqh"
//#include "Edit.mqh"
//#include "BmpButton.mqh"
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
#resource "\\Include\\Controls\\res\\SpinInc.bmp"
#resource "\\Include\\Controls\\res\\SpinDec.bmp"
//+------------------------------------------------------------------+
//| Class CSpinEdit |
//| Usage: class that implements the "Up-Down" control |
//+------------------------------------------------------------------+
class CSpinEdit : public CWndContainer
{
protected:
//--- dependent controls
CEdit m_edit; // the entry field object
CBmpButton m_inc; // the "Increment button" object
CBmpButton m_dec; // the "Decrement button" object
//--- adjusted parameters
int m_min_value; // minimum value
int m_max_value; // maximum value
//--- state
int m_value; // current value
bool m_can_drag;
int m_prev_x;
public:
CSpinEdit(void);
~CSpinEdit(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- set up
int MinValue(void) const { return(m_min_value); }
void MinValue(const int value);
int MaxValue(void) const { return(m_max_value); }
void MaxValue(const int value);
//--- state
int Value(void) const { return(m_value); }
bool Value(int value);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
virtual bool CreateEdit(void);
virtual bool CreateInc(void);
virtual bool CreateDec(void);
//--- handlers of the dependent controls events
virtual bool OnClickInc(void);
virtual bool OnClickDec(void);
virtual bool OnClickEdit(void);
//--- internal event handlers
virtual bool OnChangeValue(void);
virtual bool OnMouseEvent(const int x, const int y, const int flags) override;
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CSpinEdit)
ON_EVENT(ON_CLICK,m_inc,OnClickInc)
ON_EVENT(ON_CLICK,m_dec,OnClickDec)
ON_EVENT(ON_CLICK, m_edit, OnClickEdit)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CSpinEdit::CSpinEdit(void) : m_min_value(0),
m_max_value(0),
m_value(0),
m_can_drag(false)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CSpinEdit::~CSpinEdit(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CSpinEdit::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- check height
if(y2-y1<CONTROLS_SPIN_MIN_HEIGHT)
return(false);
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateEdit())
return(false);
if(!CreateInc())
return(false);
if(!CreateDec())
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set current value |
//+------------------------------------------------------------------+
bool CSpinEdit::Value(int value)
{
//--- check value
if(value<m_min_value)
value=m_min_value;
if(value>m_max_value)
value=m_max_value;
//--- if value was changed
if(m_value!=value)
{
m_value=value;
//--- call virtual handler
return(OnChangeValue());
}
//--- value has not been changed
return(false);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CSpinEdit::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
FileWriteInteger(file_handle,m_value);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CSpinEdit::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//---
if(!FileIsEnding(file_handle))
Value(FileReadInteger(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set minimum value |
//+------------------------------------------------------------------+
void CSpinEdit::MinValue(const int value)
{
//--- if value was changed
if(m_min_value!=value)
{
m_min_value=value;
//--- adjust the edit value
Value(m_value);
}
}
//+------------------------------------------------------------------+
//| Set maximum value |
//+------------------------------------------------------------------+
void CSpinEdit::MaxValue(const int value)
{
//--- if value was changed
if(m_max_value!=value)
{
m_max_value=value;
//--- adjust the edit value
Value(m_value);
}
}
//+------------------------------------------------------------------+
//| Create the edit field |
//+------------------------------------------------------------------+
bool CSpinEdit::CreateEdit(void)
{
//--- create
if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,0,0,Width(),Height()))
return(false);
if(!m_edit.Text(""))
return(false);
if(!m_edit.ReadOnly(true))
return(false);
if(!Add(m_edit))
return(false);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Increment" button |
//+------------------------------------------------------------------+
bool CSpinEdit::CreateInc(void)
{
//--- right align button (try to make equal offsets from top and bottom)
int x1=Width()-(CONTROLS_BUTTON_SIZE+CONTROLS_SPIN_BUTTON_X_OFF);
int y1=(Height()-2*CONTROLS_SPIN_BUTTON_SIZE)/2;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_SPIN_BUTTON_SIZE;
//--- create
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_inc.BmpNames("::Include\\Controls\\res\\SpinInc.bmp"))
return(false);
if(!Add(m_inc))
return(false);
//--- property
m_inc.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Create the "Decrement" button |
//+------------------------------------------------------------------+
bool CSpinEdit::CreateDec(void)
{
//--- right align button (try to make equal offsets from top and bottom)
int x1=Width()-(CONTROLS_BUTTON_SIZE+CONTROLS_SPIN_BUTTON_X_OFF);
int y1=(Height()-2*CONTROLS_SPIN_BUTTON_SIZE)/2+CONTROLS_SPIN_BUTTON_SIZE;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_SPIN_BUTTON_SIZE;
//--- create
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_dec.BmpNames("::Include\\Controls\\res\\SpinDec.bmp"))
return(false);
if(!Add(m_dec))
return(false);
//--- property
m_dec.PropFlags(WND_PROP_FLAG_CLICKS_BY_PRESS);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on the "increment" button |
//+------------------------------------------------------------------+
bool CSpinEdit::OnClickInc(void)
{
//--- try to increment current value
return(Value(m_value+1));
}
//+------------------------------------------------------------------+
//| Handler of click on the "decrement" button |
//+------------------------------------------------------------------+
bool CSpinEdit::OnClickDec(void)
{
//--- try to decrement current value
return(Value(m_value-1));
}
bool CSpinEdit::OnClickEdit(void)
{
EventChartCustom(CONTROLS_SELF_MESSAGE, ON_CLICK, m_id, 0.0, m_name);
return true;
}
//+------------------------------------------------------------------+
//| Handler of changing current state |
//+------------------------------------------------------------------+
bool CSpinEdit::OnChangeValue(void)
{
//--- copy text to the edit field edit
m_edit.Text(IntegerToString(m_value));
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
bool CSpinEdit::OnMouseEvent(const int x, const int y, const int flags) override
{
if(Contains(x, y))
{
// Comment(x, " ", y, " ", flags, " ", m_mouse_flags, " ", m_can_drag);
if((flags & MOUSE_LEFT) != 0)
{
if(m_mouse_flags <= 0)
{
m_can_drag = true;
}
if(m_prev_x != x && m_can_drag)
{
if(m_mouse_flags == flags)
{
Value(m_value + (x - m_prev_x));
ChartRedraw();
}
m_prev_x = x;
}
}
else
{
m_can_drag = false;
}
}
else
{
m_can_drag = false;
}
m_mouse_flags = flags;
return CWndContainer::OnMouseEvent(x, y, flags);
}
//#include <ControlsPlus/DatePicker.mqh>
//+------------------------------------------------------------------+
//| DatePicker.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndContainer.mqh"
//#include "Edit.mqh"
//#include "BmpButton.mqh"
//#include "DateDropList.mqh"
//+------------------------------------------------------------------+
//| DateDropList.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndContainer.mqh"
//#include "BmpButton.mqh"
//#include "Picture.mqh"
//+------------------------------------------------------------------+
//| Picture.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "WndObj.mqh"
//#include <ChartObjects\ChartObjectsBmpControls.mqh>
//+------------------------------------------------------------------+
//| Class CPicture |
//| Note: image displayed by |
//| the CChartObjectBmpLabel object |
//+------------------------------------------------------------------+
class CPicture : public CWndObj
{
private:
CChartObjectBmpLabel m_picture; // chart object
//--- parameters of the chart object
int m_border; // border width
string m_bmp_name; // filename
public:
CPicture(void);
~CPicture(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- parameters of the chart object
int Border(void) const { return(m_border); }
bool Border(const int value);
string BmpName(void) const { return(m_bmp_name); }
bool BmpName(const string name);
protected:
//--- internal event handlers
virtual bool OnCreate(void);
virtual bool OnShow(void);
virtual bool OnHide(void);
virtual bool OnMove(void);
virtual bool OnChange(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CPicture::CPicture(void) : m_border(0),
m_bmp_name(NULL)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CPicture::~CPicture(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CPicture::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create the chart object
if(!m_picture.Create(chart,name,subwin,x1,y1))
return(false);
//--- call the settings handler
return(OnChange());
}
//+------------------------------------------------------------------+
//| Set border width |
//+------------------------------------------------------------------+
bool CPicture::Border(const int value)
{
//--- save new value of parameter
m_border=value;
//--- set up the chart object
return(m_picture.Width(value));
}
//+------------------------------------------------------------------+
//| Set image |
//+------------------------------------------------------------------+
bool CPicture::BmpName(const string name)
{
//--- save new value of parameter
m_bmp_name=name;
//--- set up the chart object
return(m_picture.BmpFileOn(name));
}
//+------------------------------------------------------------------+
//| Create object on chart |
//+------------------------------------------------------------------+
bool CPicture::OnCreate(void)
{
//--- create the chart object by previously set parameters
return(m_picture.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top));
}
//+------------------------------------------------------------------+
//| Display object on chart |
//+------------------------------------------------------------------+
bool CPicture::OnShow(void)
{
return(m_picture.Timeframes(OBJ_ALL_PERIODS));
}
//+------------------------------------------------------------------+
//| Hide object from chart |
//+------------------------------------------------------------------+
bool CPicture::OnHide(void)
{
return(m_picture.Timeframes(OBJ_NO_PERIODS));
}
//+------------------------------------------------------------------+
//| Absolute movement of the chart object |
//+------------------------------------------------------------------+
bool CPicture::OnMove(void)
{
//--- position the chart object
return(m_picture.X_Distance(m_rect.left) && m_picture.Y_Distance(m_rect.top));
}
//+------------------------------------------------------------------+
//| Set up the chart object |
//+------------------------------------------------------------------+
bool CPicture::OnChange(void)
{
//--- set up the chart object
return(m_picture.Width(m_border) && m_picture.BmpFileOn(m_bmp_name));
}
//+------------------------------------------------------------------+
//#include <Canvas\Canvas.mqh>
//+------------------------------------------------------------------+
//| Canvas.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include <Files\FileBin.mqh>
//+------------------------------------------------------------------+
//| FileBin.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include "File.mqh"
//+------------------------------------------------------------------+
//| File.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//#include <Object.mqh>
//+------------------------------------------------------------------+
//| Class CFile. |
//| Purpose: Base class of file operations. |
//| Derives from class CObject. |
//+------------------------------------------------------------------+
class CFile : public CObject
{
protected:
int m_handle; // handle of file
string m_name; // name of opened file
int m_flags; // flags of opened file
public:
CFile(void);
~CFile(void);
//--- methods of access to protected data
int Handle(void) const { return(m_handle); };
string FileName(void) const { return(m_name); };
int Flags(void) const { return(m_flags); };
void SetUnicode(const bool unicode);
void SetCommon(const bool common);
//--- general methods for working with files
int Open(const string file_name,int open_flags,const short delimiter='\t');
void Close(void);
void Delete(void);
ulong Size(void);
ulong Tell(void);
void Seek(const long offset,const ENUM_FILE_POSITION origin);
void Flush(void);
bool IsEnding(void);
bool IsLineEnding(void);
//--- general methods for working with files
void Delete(const string file_name,const int common_flag=0);
bool IsExist(const string file_name,const int common_flag=0);
bool Copy(const string src_name,const int common_flag,const string dst_name,const int mode_flags);
bool Move(const string src_name,const int common_flag,const string dst_name,const int mode_flags);
//--- general methods of working with folders
bool FolderCreate(const string folder_name);
bool FolderDelete(const string folder_name);
bool FolderClean(const string folder_name);
//--- general methods of finding files
long FileFindFirst(const string file_filter,string &returned_filename);
bool FileFindNext(const long search_handle,string &returned_filename);
void FileFindClose(const long search_handle);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CFile::CFile(void) : m_handle(INVALID_HANDLE),
m_name(""),
m_flags(FILE_ANSI)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CFile::~CFile(void)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
Close();
}
//+------------------------------------------------------------------+
//| Set the FILE_UNICODE flag |
//+------------------------------------------------------------------+
void CFile::SetUnicode(const bool unicode)
{
//--- check handle
if(m_handle==INVALID_HANDLE)
{
if(unicode)
m_flags|=FILE_UNICODE;
else
m_flags&=~FILE_UNICODE;
}
}
//+------------------------------------------------------------------+
//| Set the "Common Folder" flag |
//+------------------------------------------------------------------+
void CFile::SetCommon(const bool common)
{
//--- check handle
if(m_handle==INVALID_HANDLE)
{
if(common)
m_flags|=FILE_COMMON;
else
m_flags&=~FILE_COMMON;
}
}
//+------------------------------------------------------------------+
//| Open the file |
//+------------------------------------------------------------------+
int CFile::Open(const string file_name,int open_flags,const short delimiter)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
Close();
//--- action
if((open_flags &(FILE_BIN|FILE_CSV))==0)
open_flags|=FILE_TXT;
//--- open
m_handle=FileOpen(file_name,open_flags|m_flags,delimiter);
if(m_handle!=INVALID_HANDLE)
{
//--- store options of the opened file
m_flags|=open_flags;
m_name=file_name;
}
//--- result
return(m_handle);
}
//+------------------------------------------------------------------+
//| Close the file |
//+------------------------------------------------------------------+
void CFile::Close(void)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
//--- closing the file and resetting all the variables to the initial state
FileClose(m_handle);
m_handle=INVALID_HANDLE;
m_name="";
//--- reset all flags except the text
m_flags&=FILE_ANSI|FILE_UNICODE;
}
}
//+------------------------------------------------------------------+
//| Deleting an open file |
//+------------------------------------------------------------------+
void CFile::Delete(void)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
string file_name=m_name;
int common_flag=m_flags&FILE_COMMON;
//--- close before deleting
Close();
//--- delete
FileDelete(file_name,common_flag);
}
}
//+------------------------------------------------------------------+
//| Get size of opened file |
//+------------------------------------------------------------------+
ulong CFile::Size(void)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileSize(m_handle));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Get current position of pointer in file |
//+------------------------------------------------------------------+
ulong CFile::Tell(void)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileTell(m_handle));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Set position of pointer in file |
//+------------------------------------------------------------------+
void CFile::Seek(const long offset,const ENUM_FILE_POSITION origin)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
FileSeek(m_handle,offset,origin);
}
//+------------------------------------------------------------------+
//| Flush data from the file buffer of input-output to disk |
//+------------------------------------------------------------------+
void CFile::Flush(void)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
FileFlush(m_handle);
}
//+------------------------------------------------------------------+
//| Detect the end of file |
//+------------------------------------------------------------------+
bool CFile::IsEnding(void)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileIsEnding(m_handle));
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Detect the end of string |
//+------------------------------------------------------------------+
bool CFile::IsLineEnding(void)
{
//--- checking
if(m_handle!=INVALID_HANDLE)
if((m_flags&FILE_BIN)==0)
return(FileIsLineEnding(m_handle));
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Deleting a file |
//+------------------------------------------------------------------+
void CFile::Delete(const string file_name,const int common_flag)
{
//--- checking
if(file_name==m_name)
{
int flag=m_flags&FILE_COMMON;
if(flag==common_flag)
Close();
}
//--- delete
FileDelete(file_name,common_flag);
}
//+------------------------------------------------------------------+
//| Check if file exists |
//+------------------------------------------------------------------+
bool CFile::IsExist(const string file_name,const int common_flag)
{
return(FileIsExist(file_name,common_flag));
}
//+------------------------------------------------------------------+
//| Copying file |
//+------------------------------------------------------------------+
bool CFile::Copy(const string src_name,const int common_flag,const string dst_name,const int mode_flags)
{
return(FileCopy(src_name,common_flag,dst_name,mode_flags));
}
//+------------------------------------------------------------------+
//| Move/rename file |
//+------------------------------------------------------------------+
bool CFile::Move(const string src_name,const int common_flag,const string dst_name,const int mode_flags)
{
return(FileMove(src_name,common_flag,dst_name,mode_flags));
}
//+------------------------------------------------------------------+
//| Create folder |
//+------------------------------------------------------------------+
bool CFile::FolderCreate(const string folder_name)
{
return(::FolderCreate(folder_name,m_flags));
}
//+------------------------------------------------------------------+
//| Delete folder |
//+------------------------------------------------------------------+
bool CFile::FolderDelete(const string folder_name)
{
return(::FolderDelete(folder_name,m_flags));
}
//+------------------------------------------------------------------+
//| Clean folder |
//+------------------------------------------------------------------+
bool CFile::FolderClean(const string folder_name)
{
return(::FolderClean(folder_name,m_flags));
}
//+------------------------------------------------------------------+
//| Start search of files |
//+------------------------------------------------------------------+
long CFile::FileFindFirst(const string file_filter,string &returned_filename)
{
return(::FileFindFirst(file_filter,returned_filename,m_flags));
}
//+------------------------------------------------------------------+
//| Continue search of files |
//+------------------------------------------------------------------+
bool CFile::FileFindNext(const long search_handle,string &returned_filename)
{
return(::FileFindNext(search_handle,returned_filename));
}
//+------------------------------------------------------------------+
//| End search of files |
//+------------------------------------------------------------------+
void CFile::FileFindClose(const long search_handle)
{
::FileFindClose(search_handle);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class CFileBin |
//| Purpose: Class of operations with binary files |
//| Derives from class CFile |
//+------------------------------------------------------------------+
class CFileBin : public CFile
{
public:
CFileBin(void);
~CFileBin(void);
//--- methods for working with files
int Open(const string file_name,const int open_flags);
//--- methods for writing data
uint WriteChar(const char value);
uint WriteShort(const short value);
uint WriteInteger(const int value);
uint WriteLong(const long value);
uint WriteFloat(const float value);
uint WriteDouble(const double value);
uint WriteString(const string value);
uint WriteString(const string value,const int size);
uint WriteCharArray(const char &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
uint WriteShortArray(const short& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
uint WriteIntegerArray(const int& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
uint WriteLongArray(const long &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
uint WriteFloatArray(const float &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
uint WriteDoubleArray(const double &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
template<typename T>
uint WriteArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
template<typename T>
uint WriteStruct(T &data);
bool WriteObject(CObject *object);
template<typename T>
uint WriteEnum(const T value) { return(WriteInteger((int)value)); }
//--- methods for reading data
bool ReadChar(char &value);
bool ReadShort(short &value);
bool ReadInteger(int &value);
bool ReadLong(long &value);
bool ReadFloat(float &value);
bool ReadDouble(double &value);
bool ReadString(string &value);
bool ReadString(string &value,const int size);
uint ReadCharArray(char &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
uint ReadShortArray(short& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
uint ReadIntegerArray(int& array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
uint ReadLongArray(long &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
uint ReadFloatArray(float &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
uint ReadDoubleArray(double &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
template<typename T>
uint ReadArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);
template<typename T>
uint ReadStruct(T &data);
bool ReadObject(CObject *object);
template<typename T>
bool ReadEnum(T &value);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CFileBin::CFileBin(void)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CFileBin::~CFileBin(void)
{
}
//+------------------------------------------------------------------+
//| Opening a binary file |
//+------------------------------------------------------------------+
int CFileBin::Open(const string file_name,const int open_flags)
{
return(CFile::Open(file_name,open_flags|FILE_BIN));
}
//+------------------------------------------------------------------+
//| Write a variable of char or uchar type |
//+------------------------------------------------------------------+
uint CFileBin::WriteChar(const char value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteInteger(m_handle,value,sizeof(char)));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write a variable of short or ushort type |
//+------------------------------------------------------------------+
uint CFileBin::WriteShort(const short value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteInteger(m_handle,value,sizeof(short)));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write a variable of int or uint type |
//+------------------------------------------------------------------+
uint CFileBin::WriteInteger(const int value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteInteger(m_handle,value,sizeof(int)));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write a variable of long or ulong type |
//+------------------------------------------------------------------+
uint CFileBin::WriteLong(const long value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteLong(m_handle,value));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write a variable of float type |
//+------------------------------------------------------------------+
uint CFileBin::WriteFloat(const float value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteFloat(m_handle,value));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write a variable of double type |
//+------------------------------------------------------------------+
uint CFileBin::WriteDouble(const double value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteDouble(m_handle,value));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write a variable of string type |
//+------------------------------------------------------------------+
uint CFileBin::WriteString(const string value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
//--- size of string
int size=StringLen(value);
//--- write
if(FileWriteInteger(m_handle,size)==sizeof(int))
return(FileWriteString(m_handle,value,size));
}
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write a part of string |
//+------------------------------------------------------------------+
uint CFileBin::WriteString(const string value,const int size)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteString(m_handle,value,size));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write array variables of type char or uchar |
//+------------------------------------------------------------------+
uint CFileBin::WriteCharArray(const char &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write an array of variables of short or ushort type |
//+------------------------------------------------------------------+
uint CFileBin::WriteShortArray(const short &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write an array of variables of int or uint type |
//+------------------------------------------------------------------+
uint CFileBin::WriteIntegerArray(const int &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write an array of variables of long or ulong type |
//+------------------------------------------------------------------+
uint CFileBin::WriteLongArray(const long &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write an array of variables of float type |
//+------------------------------------------------------------------+
uint CFileBin::WriteFloatArray(const float &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write an array of variables of double type |
//+------------------------------------------------------------------+
uint CFileBin::WriteDoubleArray(const double &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write an array of variables of any type |
//+------------------------------------------------------------------+
template<typename T>
uint CFileBin::WriteArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write an structure |
//+------------------------------------------------------------------+
template<typename T>
uint CFileBin::WriteStruct(T &data)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileWriteStruct(m_handle,data));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Write data of an instance of the CObject class |
//+------------------------------------------------------------------+
bool CFileBin::WriteObject(CObject *object)
{
//--- check handle & object
if(m_handle!=INVALID_HANDLE)
if(CheckPointer(object))
return(object.Save(m_handle));
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Read a variable of char or uchar type |
//+------------------------------------------------------------------+
bool CFileBin::ReadChar(char &value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
ResetLastError();
value=(char)FileReadInteger(m_handle,sizeof(char));
return(GetLastError()==0);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Read a variable of short or ushort type |
//+------------------------------------------------------------------+
bool CFileBin::ReadShort(short &value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
ResetLastError();
value=(short)FileReadInteger(m_handle,sizeof(short));
return(GetLastError()==0);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Read a variable of int or uint type |
//+------------------------------------------------------------------+
bool CFileBin::ReadInteger(int &value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
ResetLastError();
value=FileReadInteger(m_handle,sizeof(int));
return(GetLastError()==0);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Read a variable of long or ulong type |
//+------------------------------------------------------------------+
bool CFileBin::ReadLong(long &value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
ResetLastError();
value=FileReadLong(m_handle);
return(GetLastError()==0);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Read a variable of float type |
//+------------------------------------------------------------------+
bool CFileBin::ReadFloat(float &value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
ResetLastError();
value=FileReadFloat(m_handle);
return(GetLastError()==0);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Read a variable of double type |
//+------------------------------------------------------------------+
bool CFileBin::ReadDouble(double &value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
ResetLastError();
value=FileReadDouble(m_handle);
return(GetLastError()==0);
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Read a variable of string type |
//+------------------------------------------------------------------+
bool CFileBin::ReadString(string &value)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
ResetLastError();
int size=FileReadInteger(m_handle);
if(GetLastError()==0)
{
value=FileReadString(m_handle,size);
return(size==StringLen(value));
}
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Read a part of string |
//+------------------------------------------------------------------+
bool CFileBin::ReadString(string &value,const int size)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
{
value=FileReadString(m_handle,size);
return(size==StringLen(value));
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Read an array of variables of char or uchar type |
//+------------------------------------------------------------------+
uint CFileBin::ReadCharArray(char &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileReadArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Read an array of variables of short or ushort type |
//+------------------------------------------------------------------+
uint CFileBin::ReadShortArray(short &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileReadArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Read an array of variables of int or uint type |
//+------------------------------------------------------------------+
uint CFileBin::ReadIntegerArray(int &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileReadArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Read an array of variables of long or ulong type |
//+------------------------------------------------------------------+
uint CFileBin::ReadLongArray(long &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileReadArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Read an array of variables of float type |
//+------------------------------------------------------------------+
uint CFileBin::ReadFloatArray(float &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileReadArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Read an array of variables of double type |
//+------------------------------------------------------------------+
uint CFileBin::ReadDoubleArray(double &array[],const int start_item,const int items_count)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileReadArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Read an array of variables of any type |
//+------------------------------------------------------------------+
template<typename T>
uint CFileBin::ReadArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileReadArray(m_handle,array,start_item,items_count));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Read an structure |
//+------------------------------------------------------------------+
template<typename T>
uint CFileBin::ReadStruct(T &data)
{
//--- check handle
if(m_handle!=INVALID_HANDLE)
return(FileReadStruct(m_handle,data));
//--- failure
return(0);
}
//+------------------------------------------------------------------+
//| Read data of an instance of the CObject class |
//+------------------------------------------------------------------+
bool CFileBin::ReadObject(CObject *object)
{
//--- check handle & object
if(m_handle!=INVALID_HANDLE)
if(CheckPointer(object))
return(object.Load(m_handle));
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Read a variable of an enumeration type |
//+------------------------------------------------------------------+
template<typename T>
bool CFileBin::ReadEnum(T &value)
{
int val;
if(!ReadInteger(val))
return(false);
//---
value=(T)val;
return(true);
}
//+------------------------------------------------------------------+
//#include <Controls\Rect.mqh>
#define SIGN(i) ((i<0) ? -1 : 1)
//+------------------------------------------------------------------+
//| Macro to generate color |
//+------------------------------------------------------------------+
#define XRGB(r,g,b) (0xFF000000|(uchar(r)<<16)|(uchar(g)<<8)|uchar(b))
#define ARGB(a,r,g,b) ((uchar(a)<<24)|(uchar(r)<<16)|(uchar(g)<<8)|uchar(b))
#define TRGB(a,rgb) ((uchar(a)<<24)|(rgb))
#define GETRGB(clr) ((clr)&0xFFFFFF)
#define GETRGBA(clr) uchar((clr)>>24)
#define GETRGBR(clr) uchar((clr)>>16)
#define GETRGBG(clr) uchar((clr)>>8)
#define GETRGBB(clr) uchar(clr)
#define COLOR2RGB(clr) (0xFF000000|(uchar(clr)<<16)|(uchar((clr)>>8)<<8)|uchar((clr)>>16))
#define RGB2COLOR(rgb) ((uchar(rgb)<<16)|(uchar((rgb)>>8)<<8)|uchar((rgb)>>16))
//+------------------------------------------------------------------+
//| Line end style (round, butt, square) |
//+------------------------------------------------------------------+
enum ENUM_LINE_END
{
LINE_END_ROUND,
LINE_END_BUTT,
LINE_END_SQUARE,
};
//+------------------------------------------------------------------+
//| Class CCanvas |
//| Usage: class for working with a dynamic resource |
//+------------------------------------------------------------------+
class CCanvas
{
private:
uint m_style; // line style template
uint m_style_idx; // variable - current index of bit in line style template
static uint m_default_colors[9]; // default colors
protected:
long m_chart_id; // chart ID
string m_objname; // object name
ENUM_OBJECT m_objtype; // object type
string m_rcname; // resource name
int m_width; // canvas width
int m_height; // canvas height
ENUM_COLOR_FORMAT m_format; // method of color processing
//--- for text
string m_fontname; // font name
int m_fontsize; // font size
uint m_fontflags; // font flags
uint m_fontangle; // angle of text tilt to the X axis in 0.1 degrees
//--- data
uint m_pixels[]; // array of pixels
public:
CCanvas(void);
~CCanvas(void);
//--- create/attach/destroy
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
bool CreateBitmap(const string name,const datetime time,const double price,
const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
bool CreateBitmap(const long chart_id,const int subwin,const string name,
const datetime time,const double price,const int width,const int height,
ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
bool CreateBitmapLabel(const string name,const int x,const int y,
const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
bool CreateBitmapLabel(const long chart_id,const int subwin,const string name,
const int x,const int y,const int width,const int height,
ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
virtual bool Attach(const long chart_id,const string objname,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
virtual bool Attach(const long chart_id,const string objname,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
virtual void Destroy(void);
//--- properties
string ChartObjectName(void) const { return(m_objname); }
string ResourceName(void) const { return(m_rcname); }
int Width(void) const { return(m_width); }
int Height(void) const { return(m_height); }
//--- update object on screen
void Update(const bool redraw=true);
bool Resize(const int width,const int height);
//--- clear/fill color
void Erase(const uint clr=0);
//--- data access
uint PixelGet(const int x,const int y) const;
void PixelSet(const int x,const int y,const uint clr);
//--- draw primitives
void LineVertical(int x,int y1,int y2,const uint clr);
void LineHorizontal(int x1,int x2,int y,const uint clr);
void Line(int x1,int y1,int x2,int y2,const uint clr);
void Polyline(int &x[],int &y[],const uint clr);
void Polygon(int &x[],int &y[],const uint clr);
void Rectangle(int x1,int y1,int x2,int y2,const uint clr);
void Triangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr);
void Circle(int x,int y,int r,const uint clr);
void Ellipse(int x1,int y1,int x2,int y2,const uint clr);
void Arc(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,const uint clr);
void Arc(int x,int y,int rx,int ry,double fi3,double fi4,const uint clr);
void Arc(int x,int y,int rx,int ry,double fi3,double fi4,int &x3,int &y3,int &x4,int &y4,const uint clr);
void Pie(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,const uint clr,const uint fill_clr);
void Pie(int x,int y,int rx,int ry,double fi3,double fi4,const uint clr,const uint fill_clr);
//--- draw filled primitives
void FillRectangle(int x1,int y1,int x2,int y2,const uint clr);
void FillTriangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr);
void FillPolygon(int &x[],int &y[],const uint clr);
void FillCircle(int x,int y,int r,const uint clr);
void FillEllipse(int x1,int y1,int x2,int y2,const uint clr);
void Fill(int x,int y,const uint clr);
void Fill(int x,int y,const uint clr,const uint threshould);
//--- draw primitives with antialiasing
void PixelSetAA(const double x,const double y,const uint clr);
void LineAA(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style=UINT_MAX);
void PolylineAA(int &x[],int &y[],const uint clr,const uint style=UINT_MAX);
void PolygonAA(int &x[],int &y[],const uint clr,const uint style=UINT_MAX);
void TriangleAA(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3,
const uint clr,const uint style=UINT_MAX);
void CircleAA(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX);
void EllipseAA(const double x1,const double y1,const double x2,const double y2,const uint clr,const uint style=UINT_MAX);
//--- draw primitives with antialiasing by Wu's algorithm
void LineWu(int x1,int y1,int x2,int y2,const uint clr,const uint style=UINT_MAX);
void PolylineWu(const int &x[],const int &y[],const uint clr,const uint style=UINT_MAX);
void PolygonWu(const int &x[],const int &y[],const uint clr,const uint style=UINT_MAX);
void TriangleWu(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3,const uint clr,const uint style=UINT_MAX);
void CircleWu(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX);
void EllipseWu(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style=UINT_MAX);
//--- draw primitives with prefiltered antialiasing
void LineThickVertical(const int x,const int y1,const int y2,const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
void LineThickHorizontal(const int x1,const int x2,const int y,const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
void LineThick(const int x1,const int y1,const int x2,const int y2,const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
void PolylineThick(const int &x[],const int &y[],const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
void PolygonThick(const int &x[],const int &y[],const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
//--- draw primitives smoothing polyline and polygon
void PolylineSmooth(const int &x[],const int &y[],const uint clr,const int size,
ENUM_LINE_STYLE style=STYLE_SOLID,ENUM_LINE_END end_style=LINE_END_ROUND,
double tension=0.5,double step=10);
void PolygonSmooth(int &x[],int &y[],const uint clr,const int size,
ENUM_LINE_STYLE style=STYLE_SOLID,ENUM_LINE_END end_style=LINE_END_ROUND,
double tension=0.5,double step=10);
//--- for text
bool FontSet(const string name,const int size,const uint flags=0,const uint angle=0);
bool FontNameSet(string name);
bool FontSizeSet(int size);
bool FontFlagsSet(uint flags);
bool FontAngleSet(uint angle);
void FontGet(string &name,int &size,uint &flags,uint &angle);
string FontNameGet(void) const { return(m_fontname); }
int FontSizeGet(void) const { return(m_fontsize); }
uint FontFlagsGet(void) const { return(m_fontflags); }
uint FontAngleGet(void) const { return(m_fontangle); }
void TextOut(int x,int y,string text,const uint clr,uint alignment=0);
int TextWidth(const string text);
int TextHeight(const string text);
void TextSize(const string text,int &width,int &height);
//--- services
static uint GetDefaultColor(const int i);
void TransparentLevelSet(const uchar value);
//--- load bitmap from file
bool LoadFromFile(const string filename);
//--- line style property
uint LineStyleGet(void) const;
void LineStyleSet(const uint style);
//--- load bitmap from file to buffer
static bool LoadBitmap(const string filename,uint &data[],int &width,int &height);
private:
bool FontSet(void);
void TextOutFast(int x,int y,string text,const uint clr,uint alignment=0);
bool PixelsSimilar(const uint clr0,const uint clr1,const uint threshould);
//--- for Wu's algorithm
void PixelTransform(const int x,const int y,const uint clr,const double alpha);
//--- for circle and ellipse
void PixelTransform4(const int x,const int y,const int dx,const int dy,const uint clr,const double alpha);
void PixelSet4AA(const double x,const double y,const double dx,const double dy,const uint clr);
//--- for thick line
void SegmentVertical(const int x,const int y1,const int y2,const int ysign,const double r,const uint clr,ENUM_LINE_END end_style);
void SegmentHorizontal(const int x1,const int x2,const int y,const int xsign,const double r,const uint clr,ENUM_LINE_END end_style);
void Segment(const int x1,const int y1,const int x2,const int y2,const double kp0,const double kp1,const int xsign,const int ysign,
const double rcos_k,const double rsin_k,const double r,const uint clr,ENUM_LINE_END end_style);
double DistancePointSegment(const double px,const double py,const double x1,const double y1,const double x2,const double y2);
//--- for pie
double AngleCalc(int x1,int y1,int x2,int y2);
//--- for polygon
int PointClassify(const CPoint &p0,const CPoint &p1,const CPoint &p2);
int PolygonClassify(const CPoint &p[]);
bool IsPolygonConvex(CPoint &p[]);
void PolygonNormalize(CPoint &p[]);
void PolygonIntersect(CPoint &p[],CPoint &add[]);
void PolygonFill(CPoint &p[],const uint clr);
//--- for smoothing polyline and polygon
void CalcCurveBezierEndp(const double xend,const double yend,const double xadj,const double yadj,const double tension,double &x,double &y);
void CalcCurveBezier(const int &x[],const int &y[],const int i,const double tension,double &x1,double &y1,double &x2,double &y2);
double CalcBezierX(const double t,const double x0,const double x1,const double x2,const double x3);
double CalcBezierY(const double t,const double y0,const double y1,const double y2,const double y3);
protected:
//--- method for prefiltered antialiasing
virtual double FilterFunction(const double x);
};
//+------------------------------------------------------------------+
//| Initialize static array |
//+------------------------------------------------------------------+
uint CCanvas::m_default_colors[9]=
{
XRGB(0,0,255), // blue
XRGB(255,0,0), // red
XRGB(0,128,0), // green
XRGB(255,242,0), // yellow
XRGB(255,0,128), // pink
XRGB(0,255,0), // lime
XRGB(185,0,61), // crimson
XRGB(0,183,239), // sky blue
XRGB(255,128,0) // orange
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CCanvas::CCanvas(void) : m_chart_id(0),
m_objname(NULL),
m_objtype(WRONG_VALUE),
m_rcname(NULL),
m_width(0),
m_height(0),
m_format(COLOR_FORMAT_XRGB_NOALPHA),
m_fontname("arial"),
m_fontsize(-120),
m_fontflags(0),
m_fontangle(0),
m_style(UINT_MAX),
m_style_idx(0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CCanvas::~CCanvas(void)
{
}
//+------------------------------------------------------------------+
//| Create dynamic resource |
//+------------------------------------------------------------------+
bool CCanvas::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
{
Destroy();
//--- prepare data array
if(width>0 && height>0 && ArrayResize(m_pixels,width*height)>0)
{
//--- generate resource name
m_rcname="::"+name+(string)ChartID()+(string)(GetTickCount()+MathRand());
//--- initialize data with zeros
ArrayInitialize(m_pixels,0);
//--- create dynamic resource
if(ResourceCreate(m_rcname,m_pixels,width,height,0,0,0,clrfmt))
{
//--- successfully created
//--- complete initialization
m_width =width;
m_height=height;
m_format=clrfmt;
//--- succeed
return(true);
}
}
//--- error - destroy object
Destroy();
return(false);
}
//+------------------------------------------------------------------+
//| Create object on chart with attached dynamic resource |
//+------------------------------------------------------------------+
bool CCanvas::CreateBitmap(const string name,const datetime time,const double price,
const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
{
return(CreateBitmap(0,0,name,time,price,width,height,clrfmt));
}
//+------------------------------------------------------------------+
//| Create object on chart with attached dynamic resource |
//+------------------------------------------------------------------+
bool CCanvas::CreateBitmap(const long chart_id,const int subwin,const string name,
const datetime time,const double price,const int width,const int height,
ENUM_COLOR_FORMAT clrfmt)
{
//--- create canvas
if(Create(name,width,height,clrfmt))
{
//--- create attached object
if(ObjectCreate(chart_id,name,OBJ_BITMAP,subwin,time,price))
{
//--- bind object with resource
if(ObjectSetString(chart_id,name,OBJPROP_BMPFILE,m_rcname))
{
//--- successfully created
//--- complete initialization
m_chart_id=chart_id;
m_objname =name;
m_objtype =OBJ_BITMAP;
//--- succeed
return(true);
}
}
}
//--- error
return(false);
}
//+------------------------------------------------------------------+
//| Create object on chart with attached dynamic resource |
//+------------------------------------------------------------------+
bool CCanvas::CreateBitmapLabel(const string name,const int x,const int y,
const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
{
return(CreateBitmapLabel(0,0,name,x,y,width,height,clrfmt));
}
//+------------------------------------------------------------------+
//| Create object on chart with attached dynamic resource |
//+------------------------------------------------------------------+
bool CCanvas::CreateBitmapLabel(const long chart_id,const int subwin,const string name,
const int x,const int y,const int width,const int height,
ENUM_COLOR_FORMAT clrfmt)
{
//--- create canvas
if(Create(name,width,height,clrfmt))
{
//--- create attached object
if(ObjectCreate(chart_id,name,OBJ_BITMAP_LABEL,subwin,0,0))
{
//--- set x,y and bind object with resource
if(ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x) &&
ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y) &&
ObjectSetString(chart_id,name,OBJPROP_BMPFILE,m_rcname))
{
//--- successfully created
//--- complete initialization
m_chart_id=chart_id;
m_objname =name;
m_objtype =OBJ_BITMAP_LABEL;
//--- succeed
return(true);
}
}
}
//--- error
return(false);
}
//+------------------------------------------------------------------+
//| Attach new object with bitmap resource |
//+------------------------------------------------------------------+
bool CCanvas::Attach(const long chart_id,const string objname,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA)
{
if(OBJ_BITMAP_LABEL==ObjectGetInteger(chart_id,objname,OBJPROP_TYPE))
{
string rcname=ObjectGetString(chart_id,objname,OBJPROP_BMPFILE);
rcname=StringSubstr(rcname,StringFind(rcname,"::"));
if(ResourceReadImage(rcname,m_pixels,m_width,m_height))
{
m_chart_id=chart_id;
m_objname=objname;
m_rcname=rcname;
m_format=clrfmt;
m_objtype=OBJ_BITMAP_LABEL;
//--- success
return(true);
}
}
//--- failed
return(false);
}
//+------------------------------------------------------------------+
//| Attach new object without bitmap resource |
//+------------------------------------------------------------------+
bool CCanvas::Attach(const long chart_id,const string objname,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA)
{
if(OBJ_BITMAP_LABEL==ObjectGetInteger(chart_id,objname,OBJPROP_TYPE))
{
string rcname=ObjectGetString(chart_id,objname,OBJPROP_BMPFILE);
if(StringLen(rcname)==0 && width>0 && height>0 && ArrayResize(m_pixels,width*height)>0)
{
ZeroMemory(m_pixels);
if(ResourceCreate("::"+objname,m_pixels,width,height,0,0,0,clrfmt) &&
ObjectSetString(chart_id,objname,OBJPROP_BMPFILE,"::"+objname))
{
m_chart_id=chart_id;
m_width=width;
m_height=height;
m_objname=objname;
m_rcname="::"+objname;
m_format=clrfmt;
m_objtype=OBJ_BITMAP_LABEL;
//--- success
return(true);
}
}
}
//--- failed
return(false);
}
//+------------------------------------------------------------------+
//| Remove object from chart and deallocate data array |
//+------------------------------------------------------------------+
void CCanvas::Destroy(void)
{
//--- delete object
if(m_objname!=NULL)
{
ObjectDelete(m_chart_id,m_objname);
m_chart_id=0;
m_objname =NULL;
m_objtype =WRONG_VALUE;
}
//--- deallocate array
ArrayFree(m_pixels);
//--- free resource
if(m_rcname!=NULL)
{
ResourceFree(m_rcname);
m_rcname=NULL;
}
//--- zeroize data
m_width =0;
m_height=0;
}
//+------------------------------------------------------------------+
//| Update object on screen (redraw) |
//+------------------------------------------------------------------+
void CCanvas::Update(const bool redraw)
{
//--- check
if(m_rcname==NULL)
return;
//--- update resource and redraw
if(ResourceCreate(m_rcname,m_pixels,m_width,m_height,0,0,0,m_format) && redraw)
ChartRedraw(this.m_chart_id);
}
//+------------------------------------------------------------------+
//| Resize |
//+------------------------------------------------------------------+
bool CCanvas::Resize(const int width,const int height)
{
//--- check
if(m_rcname!=NULL && width>0 && height>0)
if(ArrayResize(m_pixels,width*height)>0)
{
m_width =width;
m_height=height;
//--- initialize data with zeros
ArrayInitialize(m_pixels,0);
//--- create dynamic resource
if(ResourceCreate(m_rcname,m_pixels,m_width,m_height,0,0,0,m_format))
{
//--- bind object with resource
if(m_objname!=NULL && ObjectSetString(m_chart_id,m_objname,OBJPROP_BMPFILE,m_rcname))
return(true);
}
}
//--- error
return(false);
}
//+------------------------------------------------------------------+
//| Clear/Fill color |
//+------------------------------------------------------------------+
void CCanvas::Erase(const uint clr)
{
ArrayInitialize(m_pixels,clr);
}
//+------------------------------------------------------------------+
//| Get pixel color |
//+------------------------------------------------------------------+
uint CCanvas::PixelGet(const int x,const int y) const
{
//--- check coordinates
if(x>=0 && x<m_width && y>=0 && y<m_height)
return(m_pixels[y*m_width+x]);
//--- error
return(0);
}
//+------------------------------------------------------------------+
//| Set pixel |
//+------------------------------------------------------------------+
void CCanvas::PixelSet(const int x,const int y,const uint clr)
{
//--- check coordinates
if(x>=0 && x<m_width && y>=0 && y<m_height)
m_pixels[y*m_width+x]=clr;
}
//+------------------------------------------------------------------+
//| Fill closed region with color |
//+------------------------------------------------------------------+
void CCanvas::Fill(int x,int y,const uint clr)
{
//--- check
if(x<0 || x>=m_width || y<0 || y>=m_height)
return;
//---
int index=y*m_width+x;
uint old_clr=m_pixels[index];
//--- check if replacement is necessary
if(old_clr==clr)
return;
//--- use pseudo stack to emulate deeply-nested recursive calls
int stack[];
uint count=1;
int idx;
int total=ArraySize(m_pixels);
//--- allocate memory for stack
if(ArrayResize(stack,total)==-1)
return;
stack[0]=index;
m_pixels[index]=clr;
for(uint i=0; i<count; i++)
{
index=stack[i];
x=index%m_width;
//--- left adjacent point
idx=index-1;
if(x>0 && m_pixels[idx]==old_clr)
{
m_pixels[idx]=clr;
stack[count++]=idx;
}
//--- top adjacent point
idx=index-m_width;
if(idx>=0 && m_pixels[idx]==old_clr)
{
m_pixels[idx]=clr;
stack[count++]=idx;
}
//--- right adjacent point
idx=index+1;
if(x<m_width-1 && m_pixels[idx]==old_clr)
{
m_pixels[idx]=clr;
stack[count++]=idx;
}
//--- bottom adjacent point
idx=index+m_width;
if(idx<total && m_pixels[idx]==old_clr)
{
m_pixels[idx]=clr;
stack[count++]=idx;
}
}
//--- deallocate memory
ArrayFree(stack);
}
//+------------------------------------------------------------------+
//| Fill closed region with color |
//+------------------------------------------------------------------+
void CCanvas::Fill(int x,int y,const uint clr,const uint threshould)
{
//--- check
if(threshould==0.0)
{
Fill(x,y,clr);
return;
}
if(x<0 || x>=m_width || y<0 || y>=m_height || threshould>255)
return;
//---
int index=y*m_width+x;
uint old_clr=m_pixels[index];
//--- check if replacement is necessary
if(old_clr==clr)
return;
//--- use pseudo stack to emulate deeply-nested recursive calls
int stack[];
uint count=1;
int idx;
int total=ArraySize(m_pixels);
//--- allocate memory for stack
if(ArrayResize(stack,total)==-1)
return;
stack[0]=index;
m_pixels[index]=clr;
for(uint i=0; i<count; i++)
{
index=stack[i];
x=index%m_width;
//--- left adjacent point
idx=index-1;
if(x>0 && PixelsSimilar(m_pixels[idx],old_clr,threshould) && m_pixels[idx]!=clr)
{
m_pixels[idx]=clr;
stack[count++]=idx;
}
//--- top adjacent point
idx=index-m_width;
if(idx>=0 && PixelsSimilar(m_pixels[idx],old_clr,threshould) && m_pixels[idx]!=clr)
{
m_pixels[idx]=clr;
stack[count++]=idx;
}
//--- right adjacent point
idx=index+1;
if(x<m_width-1 && PixelsSimilar(m_pixels[idx],old_clr,threshould) && m_pixels[idx]!=clr)
{
m_pixels[idx]=clr;
stack[count++]=idx;
}
//--- bottom adjacent point
idx=index+m_width;
if(idx<total && PixelsSimilar(m_pixels[idx],old_clr,threshould) && m_pixels[idx]!=clr)
{
m_pixels[idx]=clr;
stack[count++]=idx;
}
}
//--- deallocate memory
ArrayFree(stack);
}
//+------------------------------------------------------------------+
//| Draw vertical line |
//+------------------------------------------------------------------+
void CCanvas::LineVertical(int x,int y1,int y2,const uint clr)
{
int tmp;
//--- sort by Y
if(y1>y2)
{
tmp=y1;
y1 =y2;
y2 =tmp;
}
//--- line is out of image boundaries
if(y2<0 || y1>=m_height || x<0 || x>=m_width)
return;
//--- stay withing image boundaries
if(y1<0)
y1=0;
if(y2>=m_height)
y2=m_height-1;
//--- draw line
int index=y1*m_width+x;
for(int i=y1; i<=y2; i++,index+=m_width)
m_pixels[index]=clr;
}
//+------------------------------------------------------------------+
//| Draw horizontal line |
//+------------------------------------------------------------------+
void CCanvas::LineHorizontal(int x1,int x2,int y,const uint clr)
{
int tmp;
//--- sort by X
if(x1>x2)
{
tmp=x1;
x1 =x2;
x2 =tmp;
}
//--- line is out of image boundaries
if(x2<0 || x1>=m_width || y<0 || y>=m_height)
return;
//--- stay withing image boundaries
if(x1<0)
x1=0;
if(x2>=m_width)
x2=m_width-1;
//--- draw line
ArrayFill(m_pixels,y*m_width+x1,(x2-x1)+1,clr);
}
//+------------------------------------------------------------------+
//| Draw line according to Bresenham's algorithm |
//+------------------------------------------------------------------+
void CCanvas::Line(int x1,int y1,int x2,int y2,const uint clr)
{
//--- line is out of image boundaries
if((x1<0 && x2<0) || (y1<0 && y2<0))
return;
if(x1>=m_width && x2>=m_width)
return;
if(y1>=m_height && y2>=m_height)
return;
//--- get length by X and Y
int dx=(x2>x1)? x2-x1 : x1-x2;
int dy=(y2>y1)? y2-y1 : y1-y2;
if(dx==0)
{
//--- vertical line
LineVertical(x1,y1,y2,clr);
return;
}
if(dy==0)
{
//--- horizontal line
LineHorizontal(x1,x2,y1,clr);
return;
}
//--- get direction by X and Y
int sx=(x1<x2)? 1 : -1;
int sy=(y1<y2)? 1 : -1;
int er=dx-dy;
bool draw=false;
//--- continue to draw line
while(x1!=x2 || y1!=y2)
{
if(x1<0 || x1>=m_width ||
y1<0 || y1>=m_height)
{
if(draw)
return;
}
else
{
//--- draw pixel
m_pixels[y1*m_width+x1]=clr;
draw=true;
}
//--- get coordinates of next pixel
int er2=er<<1;
if(er2>-dy)
{
er-=dy;
x1+=sx;
}
if(er2<dx)
{
er+=dx;
y1+=sy;
}
}
//--- set pixel at the end
PixelSet(x2,y2,clr);
}
//+------------------------------------------------------------------+
//| Draw polyline |
//+------------------------------------------------------------------+
void CCanvas::Polyline(int &x[],int &y[],const uint clr)
{
int total=ArraySize(x);
if(total>ArraySize(y))
total=ArraySize(y);
//--- check
if(total<2)
return;
total--;
//--- draw
for(int i=0; i<total; i++)
Line(x[i],y[i],x[i+1],y[i+1],clr);
}
//+------------------------------------------------------------------+
//| Draw polygon |
//+------------------------------------------------------------------+
void CCanvas::Polygon(int &x[],int &y[],const uint clr)
{
//--- check arrays
int total=ArraySize(x);
if(total>ArraySize(y))
total=ArraySize(y);
//--- check
if(total<2)
return;
total--;
//--- draw
for(int i=0; i<total; i++)
Line(x[i],y[i],x[i+1],y[i+1],clr);
//--- close the outline
Line(x[total],y[total],x[0],y[0],clr);
}
//+------------------------------------------------------------------+
//| Draw rectangle |
//+------------------------------------------------------------------+
void CCanvas::Rectangle(int x1,int y1,int x2,int y2,const uint clr)
{
LineHorizontal(x1,x2,y1,clr);
LineVertical(x2,y1,y2,clr);
LineHorizontal(x2,x1,y2,clr);
LineVertical(x1,y2,y1,clr);
}
//+------------------------------------------------------------------+
//| Draw triangle |
//+------------------------------------------------------------------+
void CCanvas::Triangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr)
{
Line(x1,y1,x2,y2,clr);
Line(x2,y2,x3,y3,clr);
Line(x3,y3,x1,y1,clr);
}
//+------------------------------------------------------------------+
//| Draw circle according to Bresenham's algorithm |
//+------------------------------------------------------------------+
void CCanvas::Circle(int x,int y,int r,const uint clr)
{
int f =1-r;
int dd_x=1;
int dd_y=-2*r;
int dx =0;
int dy =r;
int xx,yy;
//--- draw
while(dy>=dx)
{
xx=x+dx;
if(xx>=0 && xx<m_width)
{
yy=y+dy;
if(yy>=0 && yy<m_height)
m_pixels[yy*m_width+xx]=clr;
yy=y-dy;
if(yy>=0 && yy<m_height)
m_pixels[yy*m_width+xx]=clr;
}
xx=x-dx;
if(xx>=0 && xx<m_width)
{
yy=y+dy;
if(yy>=0 && yy<m_height)
m_pixels[yy*m_width+xx]=clr;
yy=y-dy;
if(yy>=0 && yy<m_height)
m_pixels[yy*m_width+xx]=clr;
}
xx=x+dy;
if(xx>=0 && xx<m_width)
{
yy=y+dx;
if(yy>=0 && yy<m_height)
m_pixels[yy*m_width+xx]=clr;
yy=y-dx;
if(yy>=0 && yy<m_height)
m_pixels[yy*m_width+xx]=clr;
}
xx=x-dy;
if(xx>=0 && xx<m_width)
{
yy=y+dx;
if(yy>=0 && yy<m_height)
m_pixels[yy*m_width+xx]=clr;
yy=y-dx;
if(yy>=0 && yy<m_height)
m_pixels[yy*m_width+xx]=clr;
}
//---
if(f>=0)
{
dy--;
dd_y+=2;
f+=dd_y;
}
dx++;
dd_x+=2;
f+=dd_x;
}
}
//+------------------------------------------------------------------+
//| Draw ellipse according to Bresenham's algorithm |
//+------------------------------------------------------------------+
void CCanvas::Ellipse(int x1,int y1,int x2,int y2,const uint clr)
{
int x,y;
int rx,ry;
int dx,dy;
int xx,yy;
int rx_sq,ry_sq;
int f;
int tmp;
//--- handle extreme conditions
if(x1==x2)
{
if(y1==y2)
PixelSet(x1,y1,clr);
else
LineVertical(x1,y1,y2,clr);
return;
}
if(y1==y2)
{
LineHorizontal(x1,x2,y1,clr);
return;
}
//--- sort by X
if(x1>x2)
{
tmp=x1;
x1 =x2;
x2 =tmp;
}
//--- sort by Y
if(y1>y2)
{
tmp=y1;
y1 =y2;
y2 =tmp;
}
x =(x2+x1)>>1;
y =(y2+y1)>>1;
rx=(x2-x1)>>1;
ry=(y2-y1)>>1;
dx=0;
dy=ry;
rx_sq=rx*rx;
ry_sq=ry*ry;
f=(rx_sq<<1)*((dy-1)*dy)+rx_sq+(ry_sq<<1)*(1-rx_sq);
while(rx_sq*dy>ry_sq*dx)
{
yy=y+dy;
if(yy>=0 && yy<m_height)
{
yy*=m_width;
xx=x+dx;
if(xx>=0 && xx<m_width)
m_pixels[yy+xx]=clr;
xx=x-dx;
if(xx>=0 && xx<m_width)
m_pixels[yy+xx]=clr;
}
yy=y-dy;
if(yy>=0 && yy<m_height)
{
yy*=m_width;
xx=x+dx;
if(xx>=0 && xx<m_width)
m_pixels[yy+xx]=clr;
xx=x-dx;
if(xx>=0 && xx<m_width)
m_pixels[yy+xx]=clr;
}
if(f>=0)
{
dy--;
f-=(rx_sq<<2)*dy;
}
f+=(ry_sq<<1)*(3+(dx<<1));
dx++;
}
f=(ry_sq<<1)*(dx+1)*dx+(rx_sq<<1)*(dy*(dy-2)+1)+(1-(rx_sq<<1))*ry_sq;
while(dy>=0)
{
yy=y+dy;
if(yy>=0 && yy<m_height)
{
yy*=m_width;
xx=x+dx;
if(xx>=0 && xx<m_width)
m_pixels[yy+xx]=clr;
xx=x-dx;
if(xx>=0 && xx<m_width)
m_pixels[yy+xx]=clr;
}
yy=y-dy;
if(yy>=0 && yy<m_height)
{
yy*=m_width;
xx=x+dx;
if(xx>=0 && xx<m_width)
m_pixels[yy+xx]=clr;
xx=x-dx;
if(xx>=0 && xx<m_width)
m_pixels[yy+xx]=clr;
}
if(f<=0)
{
dx++;
f+=(ry_sq<<2)*dx;
}
dy--;
f+=(rx_sq<<1)*(3-(dy<<1));
}
}
//+------------------------------------------------------------------+
//| Draws ellipse arc |
//+------------------------------------------------------------------+
void CCanvas::Arc(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,const uint clr)
{
int tmp;
int x,y;
double fi3;
double fi4;
//--- check
if(x1==x2 || y1==y2)
return;
//--- sort by X
if(x1>x2)
{
tmp=x1;
x1 =x2;
x2 =tmp;
}
//--- sort by Y
if(y1>y2)
{
tmp=y1;
y1 =y2;
y2 =tmp;
}
x =(x2+x1)>>1;
y =(y2+y1)>>1;
//--- check rays
if(x3==x && y3==y)
return;
if(x4==x && y4==y)
return;
//--- calculate parameters of ray x3,y3
fi3=AngleCalc(x,y,x3,y3);
//--- calculate parameters of ray x4,y4
fi4=AngleCalc(x,y,x4,y4);
//--- draw arc
Arc(x,y,x2-x,y2-y,fi3,fi4,clr);
}
//+------------------------------------------------------------------+
//| Draws ellipse arc |
//+------------------------------------------------------------------+
void CCanvas::Arc(int x,int y,int rx,int ry,double fi3,double fi4,const uint clr)
{
int x3,y3,x4,y4;
//--- check
if(rx<10 || ry<10)
return;
if(rx<0)
rx=-rx;
if(ry<0)
ry=-ry;
//--- check rays
if(fi3==fi4)
return;
//--- adjustment for passing through 0
if(fi4<fi3)
fi4+=2*M_PI;
//--- draw arc
Arc(x,y,rx,ry,fi3,fi4,x3,y3,x4,y4,clr);
}
//+------------------------------------------------------------------+
//| Calculates angle between ray (x1,y1),(x1+1,y1) and |
//| ray (x1,y1),(x2,y2) |
//| Note that y coordinates are inversed |
//+------------------------------------------------------------------+
double CCanvas::AngleCalc(int x1,int y1,int x2,int y2)
{
double fi;
//--- check
if(x1==x2)
{
if(y1==y2)
return(EMPTY_VALUE);
fi=(y2<y1) ? M_PI_2 : 3*M_PI_2;
}
else
{
//--- calc
fi=atan((double)(y1-y2)/(x2-x1));
//--- adjust to the 0-2Pi range
if(x2<x1)
fi+=M_PI;
else
{
if(fi<0)
fi+=2*M_PI;
}
}
//--- result
return(fi);
}
//+------------------------------------------------------------------+
//| Draws ellipse arc and finds points of intersection with rays |
//+------------------------------------------------------------------+
void CCanvas::Arc(int x,int y,int rx,int ry,double fi3,double fi4,int &x3,int &y3,int &x4,int &y4,const uint clr)
{
//--- check
if(rx<10 || ry<10)
return;
//--- variables
int dx,dy;
int xx,yy;
int rx_sq,ry_sq;
int f;
double fi;
//--- to find intersections
bool ray3=false;
bool ray4=false;
bool ckw=false;
int xx_c=0,yy_c=0;
double fi_c=0.0;
bool ackw=false;
int xx_a=0,yy_a=0;
double fi_a=0.0;
//---
rx_sq=rx*rx;
ry_sq=ry*ry;
//--- cannot avoid check if each intersection point is between rays
//--- this will significantly decrease drawing speed, but there is no other way
//--- split ellipse into four arcs
//---
//--- 1 top
//---
//--- if arc is obviously not within the rays range, don't draw
fi=MathMod(fi4,2*M_PI);
if((fi3<M_PI && fi3>0) || // ray 3 is in the 1st or 2nd quadrant
(fi<M_PI && fi>0) || // ray 4 is in the 1st or 2nd quadrant
(fi4-fi3>=M_PI)) // arc will pass through the top of the ellipse
{
dx=0;
dy=ry;
f=(rx_sq<<1)*((dy-1)*dy)+rx_sq+(ry_sq<<1)*(1-rx_sq);
while(rx_sq*dy>=ry_sq*dx)
{
yy=y-dy;
if(dx==0)
{
//--- central point
fi=AngleCalc(0,0,0,-dy);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(x,yy,clr);
ckw=ackw=true;
}
else
ckw=ackw=false;
xx_c=x;
yy_c=yy;
fi_c=fi;
xx_a=x;
yy_a=yy;
fi_a=fi;
}
else
{
//--- iterate clockwise
xx=x+dx;
fi=AngleCalc(0,0,dx,-dy);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(xx,yy,clr);
//--- if arc haven't been drawn before and intersection point of ray 4 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 4
if(!ckw)
{
ckw=true;
if(!ray4)
{
if(MathAbs(fi_c-MathMod(fi4,2*M_PI))<MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=xx_c,y4=yy_c,clr);
else
{
x4=xx;
y4=yy;
}
ray4=true;
}
}
}
else
{
//--- if arc has been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 3
if(ckw && !ray3)
{
if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3))
PixelSet(x3=xx,y3=yy,clr);
else
{
x3=xx_c;
y3=yy_c;
}
ray3=true;
}
ckw=false;
}
//--- save parameters of the last iteration
xx_c=xx;
yy_c=yy;
fi_c=fi;
//--- iterate counterclockwise
xx=x-dx;
fi=AngleCalc(0,0,-dx,-dy);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(xx,yy,clr);
//--- if arc haven't been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 3
if(!ackw)
{
ackw=true;
if(!ray3)
{
if(MathAbs(fi_a-fi3)<MathAbs(fi-fi3))
PixelSet(x3=xx_a,y3=yy_a,clr);
else
{
x3=xx;
y3=yy;
}
ray3=true;
}
}
}
else
{
//--- if arc has been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 4
if(ackw && !ray4)
{
if(MathAbs(fi_a-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=xx,y4=yy,clr);
else
{
x4=xx_a;
y4=yy_a;
}
ray4=true;
}
ackw=false;
}
//--- save parameters of the last iteration
xx_a=xx;
yy_a=yy;
fi_a=fi;
}
//--- calculate coordinates of the next point
if(f>=0)
{
dy--;
f-=(rx_sq<<2)*dy;
}
f+=(ry_sq<<1)*(3+(dx<<1));
dx++;
}
//--- if arc has been drawn clockwise "to the end" and ray 3 had not been found
if(ckw && !ray3)
{
fi=AngleCalc(0,0,dx,-dy);
if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3))
PixelSet(x3=x+dx,y3=y-dy,clr);
else
{
x3=xx_c;
y3=yy_c;
}
}
//--- if arc has been drawn counterclockwise "to the end" and ray 4 had not been found
if(ackw && !ray4)
{
fi=AngleCalc(0,0,-dx,-dy);
if(MathAbs(fi_a-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=x-dx,y4=y-dy,clr);
else
{
x4=xx_a;
y4=yy_a;
}
}
}
//--- 2 left
//---
//--- if arc is obviously not within the rays range, don't draw
fi=MathMod(fi4,2*M_PI);
if((fi3>M_PI_2 && fi3<3*M_PI_2) || // ray 3 is in the 2nd or 3rd quadrant
(fi>M_PI_2 && fi<3*M_PI_2) || // ray 4 is in the 2nd or 3rd quadrant
(fi4-fi3>=M_PI)) // arc will pass through the left part of the ellipse
{
dx=rx;
dy=0;
f=(ry_sq<<1)*((dx-1)*dx)+ry_sq+(rx_sq<<1)*(1-ry_sq);
while(ry_sq*dx>=rx_sq*dy)
{
xx=x-dx;
if(dy==0)
{
//--- central point
fi=AngleCalc(0,0,-dx,0);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(xx,y,clr);
ckw=ackw=true;
}
else
ckw=ackw=false;
xx_c=xx;
yy_c=y;
fi_c=fi;
xx_a=xx;
yy_a=y;
fi_a=fi;
}
else
{
//--- iterate clockwise
yy=y-dy;
fi=AngleCalc(0,0,-dx,-dy);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(xx,yy,clr);
//--- if arc haven't been drawn before and intersection point of ray 4 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 4
if(!ckw)
{
ckw=true;
if(!ray4)
{
if(MathAbs(fi_c-MathMod(fi4,2*M_PI))<MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=xx_c,y4=yy_c,clr);
else
{
x4=xx;
y4=yy;
}
ray4=true;
}
}
}
else
{
//--- if arc has been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 3
if(ckw && !ray3)
{
if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3))
PixelSet(x3=xx,y3=yy,clr);
else
{
x3=xx_c;
y3=yy_c;
}
ray3=true;
}
ckw=false;
}
//--- save parameters of the last iteration
xx_c=xx;
yy_c=yy;
fi_c=fi;
//--- iterate counterclockwise
yy=y+dy;
fi=AngleCalc(0,0,-dx,dy);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(xx,yy,clr);
//--- if arc haven't been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 3
if(!ackw)
{
ackw=true;
if(!ray3)
{
if(MathAbs(fi_a-fi3)<MathAbs(fi-fi3))
PixelSet(x3=xx_a,y3=yy_a,clr);
else
{
x3=xx;
y3=yy;
}
ray3=true;
}
}
}
else
{
//--- if arc has been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 4
if(ackw && !ray4)
{
if(MathAbs(fi_a-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=xx,y4=yy,clr);
else
{
x4=xx_a;
y4=yy_a;
}
ray4=true;
}
ackw=false;
}
//--- save parameters of the last iteration
xx_a=xx;
yy_a=yy;
fi_a=fi;
}
//--- calculate coordinates of the next point
if(f>=0)
{
dx--;
f-=(ry_sq<<2)*dx;
}
f+=(rx_sq<<1)*(3+(dy<<1));
dy++;
}
//--- if arc has been drawn clockwise "to the end" and ray 3 had not been found
if(ckw && !ray3)
{
fi=AngleCalc(0,0,-dx,-dy);
if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3))
PixelSet(x3=x-dx,y3=y-dy,clr);
else
{
x3=xx_c;
y3=yy_c;
}
}
//--- if arc has been drawn counterclockwise "to the end" and ray 4 had not been found
if(ackw && !ray4)
{
fi=AngleCalc(0,0,-dx,dy);
if(MathAbs(fi_a-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=x-dx,y4=y+dy,clr);
else
{
x4=xx_a;
y4=yy_a;
}
}
}
//--- 3 bottom
//---
//--- if arc is obviously not within the rays range, don't draw
fi=MathMod(fi4,2*M_PI);
if((fi3>M_PI && fi3<2*M_PI) || // ray 3 is in the 3rd or 4th quadrant
(fi>M_PI && fi<2*M_PI) || // ray 4 is in the 3rd or 4th quadrant
(fi4-fi3>=M_PI)) // arc will pass through the bottom of the ellipse
{
dx=0;
dy=ry;
f=(rx_sq<<1)*((dy-1)*dy)+rx_sq+(ry_sq<<1)*(1-rx_sq);
while(rx_sq*dy>=ry_sq*dx)
{
yy=y+dy;
if(dx==0)
{
//--- central point
fi=AngleCalc(0,0,0,dy);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(x,yy,clr);
ckw=ackw=true;
}
else
ckw=ackw=false;
xx_c=x;
yy_c=yy;
fi_c=fi;
xx_a=x;
yy_a=yy;
fi_a=fi;
}
else
{
//--- iterate clockwise
xx=x-dx;
fi=AngleCalc(0,0,-dx,dy);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(xx,yy,clr);
//--- if arc haven't been drawn before and intersection point of ray 4 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 4
if(!ckw)
{
ckw=true;
if(!ray4)
{
if(MathAbs(fi_c-MathMod(fi4,2*M_PI))<MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=xx_c,y4=yy_c,clr);
else
{
x4=xx;
y4=yy;
}
ray4=true;
}
}
}
else
{
//--- if arc has been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 3
if(ckw && !ray3)
{
if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3))
PixelSet(x3=xx,y3=yy,clr);
else
{
x3=xx_c;
y3=yy_c;
}
ray3=true;
}
ckw=false;
}
//--- save parameters of the last iteration
xx_c=xx;
yy_c=yy;
fi_c=fi;
//--- iterate counterclockwise
xx=x+dx;
fi=AngleCalc(0,0,dx,dy);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(xx,yy,clr);
//--- if arc haven't been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 3
if(!ackw)
{
ackw=true;
if(!ray3)
{
if(MathAbs(fi_a-fi3)<MathAbs(fi-fi3))
PixelSet(x3=xx_a,y3=yy_a,clr);
else
{
x3=xx;
y3=yy;
}
ray3=true;
}
}
}
else
{
//--- if arc has been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 4
if(ackw && !ray4)
{
if(MathAbs(fi_a-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=xx,y4=yy,clr);
else
{
x4=xx_a;
y4=yy_a;
}
ray4=true;
}
ackw=false;
}
//--- save parameters of the last iteration
xx_a=xx;
yy_a=yy;
fi_a=fi;
}
//--- calculate coordinates of the next point
if(f>=0)
{
dy--;
f-=(rx_sq<<2)*dy;
}
f+=(ry_sq<<1)*(3+(dx<<1));
dx++;
}
//--- if arc has been drawn clockwise "to the end" and ray 3 had not been found
if(ckw && !ray3)
{
fi=AngleCalc(0,0,-dx,dy);
if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3))
PixelSet(x3=x-dx,y3=y+dy,clr);
else
{
x3=xx_c;
y3=yy_c;
}
}
//--- if arc has been drawn counterclockwise "to the end" and ray 4 had not been found
if(ackw && !ray4)
{
fi=AngleCalc(0,0,dx,dy);
if(MathAbs(fi_a-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=x+dx,y4=y+dy,clr);
else
{
x4=xx_a;
y4=yy_a;
}
}
}
//--- 4 right
//---
//--- if arc is obviously not within the rays range, don't draw
fi=MathMod(fi4,2*M_PI);
if((fi3<M_PI_2 || fi3>3*M_PI_2) || // ray 3 is 1 or 4 quadrant
(fi<M_PI_2 || fi>3*M_PI_2) || // ray 4 is 1 or 4 quadrant
(fi4-fi3>=M_PI)) // arc will pass through the right side of the ellipse
{
dx=rx;
dy=0;
f=(ry_sq<<1)*((dx-1)*dx)+ry_sq+(rx_sq<<1)*(1-ry_sq);
while(ry_sq*dx>=rx_sq*dy)
{
xx=x+dx;
if(dy==0)
{
//--- central point
fi=AngleCalc(0,0,dx,0);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(xx,y,clr);
ckw=ackw=true;
}
else
ckw=ackw=false;
xx_c=xx;
yy_c=y;
fi_c=fi;
xx_a=xx;
yy_a=y;
fi_a=fi;
}
else
{
//--- iterate clockwise
yy=y+dy;
fi=AngleCalc(0,0,dx,dy);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(xx,yy,clr);
//--- if arc haven't been drawn before and intersection point of ray 4 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 4
if(!ckw)
{
ckw=true;
if(!ray4)
{
if(MathAbs(fi_c-MathMod(fi4,2*M_PI))<MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=xx_c,y4=yy_c,clr);
else
{
x4=xx;
y4=yy;
}
ray4=true;
}
}
}
else
{
//--- if arc has been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 3
if(ckw && !ray3)
{
if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3))
PixelSet(x3=xx,y3=yy,clr);
else
{
x3=xx_c;
y3=yy_c;
}
ray3=true;
}
ckw=false;
}
//--- save parameters of the last iteration
xx_c=xx;
yy_c=yy;
fi_c=fi;
//--- iterate counterclockwise
yy=y-dy;
fi=AngleCalc(0,0,dx,-dy);
if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI))
{
PixelSet(xx,yy,clr);
//--- if arc haven't been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 3
if(!ackw)
{
ackw=true;
if(!ray3)
{
if(MathAbs(MathMod(fi_a,2*M_PI)-fi3)<MathAbs(fi-fi3))
PixelSet(x3=xx_a,y3=yy_a,clr);
else
{
x3=xx;
y3=yy;
}
ray3=true;
}
}
}
else
{
//--- if arc has been drawn before and intersection point of ray 3 and arc is not defined
//--- this means that we (while iterating over points of the ellipse) had just crossed ray 4
if(ackw && !ray4)
{
if(MathAbs(MathMod(fi_a,2*M_PI)-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=xx,y4=yy,clr);
else
{
x4=xx_a;
y4=yy_a;
}
ray4=true;
}
ackw=false;
}
//--- save parameters of the last iteration
xx_a=xx;
yy_a=yy;
fi_a=fi;
}
//--- calculate coordinates of the next point
if(f>=0)
{
dx--;
f-=(ry_sq<<2)*dx;
}
f+=(rx_sq<<1)*(3+(dy<<1));
dy++;
}
//--- if arc has been drawn clockwise "to the end" and ray 3 had not been found
if(ckw && !ray3)
{
fi=AngleCalc(0,0,dx,dy);
if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3))
PixelSet(x3=x+dx,y3=y+dy,clr);
else
{
x3=xx_c;
y3=yy_c;
}
}
//--- if arc has been drawn counterclockwise "to the end" and ray 4 had not been found
if(ackw && !ray4)
{
fi=AngleCalc(0,0,dx,-dy);
if(MathAbs(MathMod(fi_a,2*M_PI)-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI)))
PixelSet(x4=x+dx,y4=y-dy,clr);
else
{
x4=xx_a;
y4=yy_a;
}
}
}
}
//+------------------------------------------------------------------+
//| Draws ellipse pie |
//+------------------------------------------------------------------+
void CCanvas::Pie(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,const uint clr,const uint fill_clr)
{
int tmp;
int x,y;
//---
double fi3;
double fi4;
//--- check
if(x1==x2 || y1==y2)
return;
//--- sort by X
if(x1>x2)
{
tmp=x1;
x1 =x2;
x2 =tmp;
}
//--- sort by Y
if(y1>y2)
{
tmp=y1;
y1 =y2;
y2 =tmp;
}
x =(x2+x1)>>1;
y =(y2+y1)>>1;
//--- check rays
if(x3==x && y3==y)
return;
if(x4==x && y4==y)
return;
//--- calculate parameters of ray x3,y3
fi3=AngleCalc(x,y,x3,y3);
//--- calculate parameters of ray x4,y4
fi4=AngleCalc(x,y,x4,y4);
//--- draw pie
Pie(x,y,x2-x,y2-y,fi3,fi4,clr,fill_clr);
}
//+------------------------------------------------------------------+
//| Draws ellipse pie |
//+------------------------------------------------------------------+
void CCanvas::Pie(int x,int y,int rx,int ry,double fi3,double fi4,const uint clr,const uint fill_clr)
{
int x3=x;
int y3=y;
int x4=x;
int y4=y;
//--- check
if(rx==0 || ry==0)
return;
if(rx<0)
rx=-rx;
if(ry<0)
ry=-ry;
//--- check rays
if(fi3==fi4)
return;
//--- adjustment for passing through 0
if(fi4<fi3)
fi4+=2*M_PI;
//--- draw arc and radii
Arc(x,y,rx,ry,fi3,fi4,x3,y3,x4,y4,clr);
if((x==x3 && y==y3) || (x==x4 && y==y4))
return;
Line(x,y,x3,y3,clr);
Line(x,y,x4,y4,clr);
//--- fill
if(rx>ry)
rx=ry;
double fi=(fi3+fi4)/2;
int xf=x+(int)(0.9*rx*cos(fi));
int yf=y-(int)(0.9*rx*sin(fi));
Fill(xf,yf,fill_clr);
}
//+------------------------------------------------------------------+
//| Draw filled circle |
//+------------------------------------------------------------------+
void CCanvas::FillCircle(int x,int y,int r,const uint clr)
{
int f =1-r;
int dd_x=1;
int dd_y=-2*r;
int dx =0;
int dy =r;
//--- draw
while(dy>=dx)
{
LineHorizontal(x-dy,x+dy,y-dx,clr);
LineHorizontal(x-dy,x+dy,y+dx,clr);
//---
if(f>=0)
{
LineHorizontal(x-dx,x+dx,y-dy,clr);
LineHorizontal(x-dx,x+dx,y+dy,clr);
dy--;
dd_y+=2;
f+=dd_y;
}
dx++;
dd_x+=2;
f+=dd_x;
}
}
//+------------------------------------------------------------------+
//| Draw filled ellipse |
//+------------------------------------------------------------------+
void CCanvas::FillEllipse(int x1,int y1,int x2,int y2,const uint clr)
{
int x,y;
int rx,ry;
int dx,dy;
int rx_sq,ry_sq;
int f;
int tmp;
//--- handle extreme conditions
if(x1==x2)
{
if(y1==y2)
PixelSet(x1,y1,clr);
else
LineVertical(x1,y1,y2,clr);
return;
}
if(y1==y2)
{
LineHorizontal(x1,x2,y1,clr);
return;
}
//--- sort by X
if(x1>x2)
{
tmp=x1;
x1 =x2;
x2 =tmp;
}
//--- sort by Y
if(y1>y2)
{
tmp=y1;
y1 =y2;
y2 =tmp;
}
x =(x2+x1)>>1;
y =(y2+y1)>>1;
rx=(x2-x1)>>1;
ry=(y2-y1)>>1;
dx=0;
dy=ry;
rx_sq=rx*rx;
ry_sq=ry*ry;
f=(rx_sq<<1)*((dy-1)*dy)+rx_sq+(ry_sq<<1)*(1-rx_sq);
while(rx_sq*dy>ry_sq*(dx))
{
LineHorizontal(x-dx,x+dx,y+dy,clr);
LineHorizontal(x-dx,x+dx,y-dy,clr);
if(f>=0)
{
dy--;
f-=(rx_sq<<2)*dy;
}
f+=(ry_sq<<1)*(3+(dx<<1));
dx++;
}
f=(ry_sq<<1)*(dx+1)*dx+(rx_sq<<1)*(dy*(dy-2)+1)+(1-(rx_sq<<1))*ry_sq;
while(dy>=0)
{
LineHorizontal(x-dx,x+dx,y+dy,clr);
LineHorizontal(x-dx,x+dx,y-dy,clr);
if(f<=0)
{
dx++;
f+=(ry_sq<<2)*dx;
}
dy--;
f+=(rx_sq<<1)*(3-(dy<<1));
}
}
//+------------------------------------------------------------------+
//| Draw filled rectangle |
//+------------------------------------------------------------------+
void CCanvas::FillRectangle(int x1,int y1,int x2,int y2,const uint clr)
{
int tmp;
//--- sort vertexes
if(x2<x1)
{
tmp=x1;
x1 =x2;
x2 =tmp;
}
if(y2<y1)
{
tmp=y1;
y1 =y2;
y2 =tmp;
}
//--- out of screen boundaries
if(x2<0 || y2<0 || x1>=m_width || y1>=m_height)
return;
//--- stay withing screen boundaries
if(x1<0)
x1=0;
if(y1<0)
y1=0;
if(x2>=m_width)
x2=m_width -1;
if(y2>=m_height)
y2=m_height-1;
int len=(x2-x1)+1;
//--- set pixels
for(; y1<=y2; y1++)
ArrayFill(m_pixels,y1*m_width+x1,len,clr);
}
//+------------------------------------------------------------------+
//| Draw filled triangle |
//+------------------------------------------------------------------+
void CCanvas::FillTriangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr)
{
int xx1,xx2,tmp;
double k1=0,k2=0,xd1,xd2;
//--- sort vertexes from lesser to greater
if(y1>y2)
{
tmp=y2;
y2 =y1;
y1 =tmp;
tmp=x2;
x2 =x1;
x1=tmp;
}
if(y1>y3)
{
tmp=y1;
y1 =y3;
y3 =tmp;
tmp=x1;
x1 =x3;
x3 =tmp;
}
if(y2>y3)
{
tmp=y2;
y2 =y3;
y3 =tmp;
tmp=x2;
x2 =x3;
x3 =tmp;
}
//--- all vertexes are out of image boundaries
if(y3<0 || y1>m_height)
return;
if(x1<0 && x2<0 && x3<0)
return;
if(x1>m_width && x2>m_width && x3>m_width)
return;
//--- find coefficients of lines
if((tmp=y1-y2)!=0)
k1=(x1-x2)/(double)tmp;
if((tmp=y1-y3)!=0)
k2=(x1-x3)/(double)tmp;
//---
xd1=x1;
xd2=x1;
//---
for(int i=y1; i<=y3; i++)
{
if(i==y2)
{
if((tmp=y2-y3)!=0)
k1=(x2-x3)/(double)tmp;
xd1=x2;
}
//--- calculate new boundaries of triangle line
xx1 =(int)xd1;
xd1+=k1;
xx2 =(int)xd2;
xd2+=k2;
//--- triangle line is out of screen boundaries
if(i<0 || i>=m_height)
continue;
//--- sort
if(xx1>xx2)
{
tmp=xx1;
xx1=xx2;
xx2=tmp;
}
//--- line is out of screen boundaries
if(xx2<0 || xx1>=m_width)
continue;
//--- draw only what is within screen boundaries
if(xx1<0)
xx1=0;
if(xx2>=m_width)
xx2=m_width-1;
//--- draw horizontal line of triangle
ArrayFill(m_pixels,i*m_width+xx1,xx2-xx1,clr);
}
}
//+------------------------------------------------------------------+
//| Draw filled poligon |
//+------------------------------------------------------------------+
void CCanvas::FillPolygon(int &x[],int &y[],const uint clr)
{
static CPoint p[];
int total=ArraySize(x);
if(total>ArraySize(y))
total=ArraySize(y);
//--- check
if(total<3)
return;
//--- resize array of points
ArrayResize(p,total);
//--- find top-left point
int imin=0;
int xmin=x[0];
int ymin=y[0];
for(int i=1; i<total; i++)
{
if(y[i]>ymin)
continue;
if(y[i]==ymin)
{
if(x[i]<xmin)
{
xmin=x[i];
imin=i;
}
continue;
}
xmin=x[i];
ymin=y[i];
imin=i;
}
//--- copy coordinates arrays to array of pixels (starting from top-left)
for(int i=0; i<total; i++,imin++)
{
p[i].x=x[imin%total];
p[i].y=y[imin%total];
}
PolygonFill(p,clr);
ArrayFree(p);
}
//+------------------------------------------------------------------+
//| Draw pixel with antialiasing |
//+------------------------------------------------------------------+
void CCanvas::PixelSetAA(const double x,const double y,const uint clr)
{
static double rr[4];
static int xx[4];
static int yy[4];
//--- preliminary calculations
int ix=(int)MathRound(x);
int iy=(int)MathRound(y);
double rrr=0;
double k;
double dx=x-ix;
double dy=y-iy;
uchar a,r,g,b;
uint c;
//--- no need for anti-aliasing
if(dx==0.0 && dy==0.0)
{
PixelSet(ix,iy,clr);
return;
}
//--- prepare array of pixels
xx[0]=xx[2]=ix;
yy[0]=yy[1]=iy;
if(dx<0.0)
xx[1]=xx[3]=ix-1;
if(dx==0.0)
xx[1]=xx[3]=ix;
if(dx>0.0)
xx[1]=xx[3]=ix+1;
if(dy<0.0)
yy[2]=yy[2]=iy-1;
if(dy==0.0)
yy[2]=yy[2]=iy;
if(dy>0.0)
yy[2]=yy[2]=iy+1;
//--- calculate radii and sum of their squares
for(int i=0; i<4; i++)
{
dx=xx[i]-x;
dy=yy[i]-y;
rr[i]=1/(dx*dx+dy*dy);
rrr+=rr[i];
}
//--- draw pixels
for(int i=0; i<4; i++)
{
k=rr[i]/rrr;
c=PixelGet(xx[i],yy[i]);
a=(uchar)(k*GETRGBA(clr)+(1-k)*GETRGBA(c));
r=(uchar)(k*GETRGBR(clr)+(1-k)*GETRGBR(c));
g=(uchar)(k*GETRGBG(clr)+(1-k)*GETRGBG(c));
b=(uchar)(k*GETRGBB(clr)+(1-k)*GETRGBB(c));
PixelSet(xx[i],yy[i],ARGB(a,r,g,b));
}
}
//+------------------------------------------------------------------+
//| Get line style |
//+------------------------------------------------------------------+
uint CCanvas::LineStyleGet(void) const
{
switch(m_style)
{
case 0xFFFFFF:
return(STYLE_SOLID);
break;
case 0x3FFFF:
return(STYLE_DASH);
break;
case 0x1C71C7:
return(STYLE_DOT);
break;
case 0x381FF:
return(STYLE_DASHDOT);
break;
case 0x1C71FF:
return(STYLE_DASHDOTDOT);
break;
default:
return (m_style);
break;
}
}
//+------------------------------------------------------------------+
//| Set line style |
//+------------------------------------------------------------------+
void CCanvas::LineStyleSet(const uint style)
{
switch(style)
{
case STYLE_SOLID:
m_style=0xFFFFFF;
break;
case STYLE_DASH:
m_style=0x3FFFF;
break;
case STYLE_DOT:
m_style=0x1C71C7;
break;
case STYLE_DASHDOT:
m_style=0x381FF;
break;
case STYLE_DASHDOTDOT:
m_style=0x1C71FF;
break;
default:
//--- high-order bit must be set then custom style
if((style&0x80000000)!=0)
{
m_style=style;
}
break;
}
m_style_idx=0;
}
//+------------------------------------------------------------------+
//| Draw line with antialiasing (with style) |
//+------------------------------------------------------------------+
void CCanvas::LineAA(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style)
{
//--- line is out of image boundaries
if((x1<0 && x2<0) || (y1<0 && y2<0))
return;
if(x1>=m_width && x2>=m_width)
return;
if(y1>=m_height && y2>=m_height)
return;
//--- check
if(x1==x2 && y1==y2)
{
PixelSet(x1,y1,clr);
return;
}
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
//--- preliminary calculations
double dx=x2-x1;
double dy=y2-y1;
double xy=sqrt(dx*dx+dy*dy);
double xx=x1;
double yy=y1;
uint mask=1<<m_style_idx;
//--- set pixels
dx/=xy;
dy/=xy;
do
{
if((m_style&mask)==mask)
{
PixelSetAA(xx,yy,clr);
}
xx+=dx;
yy+=dy;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
while(fabs(x2-xx)>=fabs(dx) && fabs(y2-yy)>=fabs(dy));
//--- set last pixel
if((m_style&mask)==mask)
{
PixelSetAA(x2,y2,clr);
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw polyline with antialiasing (with style) |
//+------------------------------------------------------------------+
void CCanvas::PolylineAA(int &x[],int &y[],const uint clr,const uint style)
{
//--- check arrays
int total=ArraySize(x);
if(total>ArraySize(y))
total=ArraySize(y);
//--- check
if(total<2)
return;
total--;
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw
for(int i=0; i<total; i++)
{
int x1=x[i];
int y1=y[i];
int x2=x[i+1];
int y2=y[i+1];
//--- line is out of image boundaries
if((x1<0 && x2<0) || (y1<0 && y2<0))
{
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
return;
}
if(x1>=m_width && x2>=m_width)
{
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
return;
}
if(y1>=m_height && y2>=m_height)
{
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
return;
}
//--- check
if(x1==x2 && y1==y2)
{
PixelSet(x1,y1,clr);
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
return;
}
//--- preliminary calculations
double dx=x2-x1;
double dy=y2-y1;
double xy=sqrt(dx*dx+dy*dy);
double xx=x1;
double yy=y1;
//--- set pixels
dx/=xy;
dy/=xy;
do
{
if((m_style&mask)==mask)
{
PixelSetAA(xx,yy,clr);
}
xx+=dx;
yy+=dy;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
while(fabs(x2-xx)>=fabs(dx) && fabs(y2-yy)>=fabs(dy));
//--- set last pixel
if((m_style&mask)==mask)
{
PixelSetAA(x2,y2,clr);
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw polygon with antialiasing (with style) |
//+------------------------------------------------------------------+
void CCanvas::PolygonAA(int &x[],int &y[],const uint clr,const uint style)
{
//--- check arrays
int total=ArraySize(x);
if(total>ArraySize(y))
total=ArraySize(y);
//--- check
if(total<2)
return;
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw
for(int i=0; i<total; i++)
{
int x1=x[i];
int y1=y[i];
int x2=(i+1!=total) ? x[i+1] : x[0];
int y2=(i+1!=total) ? y[i+1] : y[0];
//--- line is out of image boundaries
if((x1<0 && x2<0) || (y1<0 && y2<0))
{
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
return;
}
if(x1>=m_width && x2>=m_width)
{
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
return;
}
if(y1>=m_height && y2>=m_height)
{
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
return;
}
//--- check
if(x1==x2 && y1==y2)
{
PixelSet(x1,y1,clr);
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
return;
}
//--- preliminary calculations
double dx=x2-x1;
double dy=y2-y1;
double xy=sqrt(dx*dx+dy*dy);
double xx=x1;
double yy=y1;
//--- set pixels
dx/=xy;
dy/=xy;
do
{
if((m_style&mask)==mask)
{
PixelSetAA(xx,yy,clr);
}
xx+=dx;
yy+=dy;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
while(fabs(x2-xx)>=fabs(dx) && fabs(y2-yy)>=fabs(dy));
//--- set last pixel
if((m_style&mask)==mask)
{
PixelSetAA(x2,y2,clr);
}
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw triangle with antialiasing |
//+------------------------------------------------------------------+
void CCanvas::TriangleAA(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3,const uint clr,const uint style)
{
//--- draw
int x[3];
int y[3];
x[0] = x1;
x[1] = x2;
x[2] = x3;
y[0] = y1;
y[1] = y2;
y[2] = y3;
PolygonAA(x,y,clr,style);
}
//+------------------------------------------------------------------+
//| Draw circle with antialiasing |
//+------------------------------------------------------------------+
void CCanvas::CircleAA(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX)
{
if(r<=0)
return;
//--- preliminary calculations
double xx=x+r;
double yy=y;
double fi=0;
double df=M_PI_2/MathCeil(r);
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw
if(r>M_PI)
df/=2;
do
{
xx=x+r*cos(fi);
yy=y-r*sin(fi);
if((m_style&mask)==mask)
PixelSetAA(xx,yy,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
fi+=df;
}
while(fabs(2*M_PI-fi)>=df/2);
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw ellipse with antialiasing |
//+------------------------------------------------------------------+
void CCanvas::EllipseAA(const double x1,const double y1,const double x2,const double y2,const uint clr,const uint style=UINT_MAX)
{
double rx = (x2-x1)/2;
double ry = (y2-y1)/2;
//--- preliminary calculations
double x=(x2>x1) ? x1+rx : x2+rx;
double y=(y2>y1) ? y1+ry : y2+ry;
double rx2=rx*rx;
double ry2=ry*ry;
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw
double quarter=round(rx2/sqrt(rx2+ry2));
for(double dx=0; dx<=quarter; dx++)
{
double dy=ry*sqrt(1-dx*dx/rx2);
if((m_style&mask)==mask)
PixelSet4AA(x,y,dx,dy,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
}
quarter=round(ry2/sqrt(rx2+ry2));
for(double dy=0; dy<=quarter; dy++)
{
double dx=rx*sqrt(1-dy*dy/ry2);
if((m_style&mask)==mask)
PixelSet4AA(x,y,dx,dy,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Gets default color |
//+------------------------------------------------------------------+
static uint CCanvas::GetDefaultColor(const int i)
{
if(i<0)
return(0);
if(i<ArraySize(m_default_colors))
return(m_default_colors[i]);
//---
return(XRGB((i%3)*60+i*50,((i+1)%3)*60+i*60,((i+2)%3)*60+i*50));
}
//+------------------------------------------------------------------+
//| Set level of transparency |
//+------------------------------------------------------------------+
void CCanvas::TransparentLevelSet(const uchar value)
{
int total=ArraySize(m_pixels);
uint value24=(uint)value<<24;
for(int i=0; i<total; i++)
m_pixels[i]=value24|(m_pixels[i]&0xFFFFFF);
}
//+------------------------------------------------------------------+
//| Set font |
//+------------------------------------------------------------------+
bool CCanvas::FontSet(const string name,const int size,const uint flags,const uint angle)
{
if(!TextSetFont(name,size,flags,angle))
return(false);
//--- save parameters of generated font
m_fontname =name;
m_fontsize =size;
m_fontflags=flags;
m_fontangle=angle;
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set fontname |
//+------------------------------------------------------------------+
bool CCanvas::FontNameSet(string name)
{
if(!TextSetFont(name,m_fontsize,m_fontflags,m_fontangle))
return(false);
//--- save parameter of generated font
m_fontname=name;
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set fontsize |
//+------------------------------------------------------------------+
bool CCanvas::FontSizeSet(int size)
{
if(!TextSetFont(m_fontname,size,m_fontflags,m_fontangle))
return(false);
//--- save parameter of generated font
m_fontsize=size;
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set fontflags |
//+------------------------------------------------------------------+
bool CCanvas::FontFlagsSet(uint flags)
{
if(!TextSetFont(m_fontname,m_fontsize,flags,m_fontangle))
return(false);
//--- save parameter of generated font
m_fontflags=flags;
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set fontangle |
//+------------------------------------------------------------------+
bool CCanvas::FontAngleSet(uint angle)
{
if(!TextSetFont(m_fontname,m_fontsize,m_fontflags,angle))
return(false);
//--- save parameter of generated font
m_fontangle=angle;
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Set font |
//+------------------------------------------------------------------+
bool CCanvas::FontSet(void)
{
return(TextSetFont(m_fontname,m_fontsize,m_fontflags,m_fontangle));
}
//+------------------------------------------------------------------+
//| Get font params |
//+------------------------------------------------------------------+
void CCanvas::FontGet(string &name,int &size,uint &flags,uint &angle)
{
name =m_fontname;
size =m_fontsize;
flags=m_fontflags;
angle=m_fontangle;
}
//+------------------------------------------------------------------+
//| Out text |
//+------------------------------------------------------------------+
void CCanvas::TextOut(int x,int y,string text,const uint clr,uint alignment)
{
if(FontSet())
TextOut(text,x,y,alignment,m_pixels,m_width,m_height,clr,m_format);
}
//+------------------------------------------------------------------+
//| Out text |
//+------------------------------------------------------------------+
void CCanvas::TextOutFast(int x,int y,string text,const uint clr,uint alignment)
{
TextOut(text,x,y,alignment,m_pixels,m_width,m_height,clr,m_format);
}
//+------------------------------------------------------------------+
//| Text width |
//+------------------------------------------------------------------+
int CCanvas::TextWidth(const string text)
{
if(!FontSet())
return(0);
//---
int w,h;
TextGetSize(text,w,h);
//--- result
return(w);
}
//+------------------------------------------------------------------+
//| Text height |
//+------------------------------------------------------------------+
int CCanvas::TextHeight(const string text)
{
if(!FontSet())
return(0);
//---
int w,h;
TextGetSize(text,w,h);
//--- result
return(h);
}
//+------------------------------------------------------------------+
//| Text rectangle |
//+------------------------------------------------------------------+
void CCanvas::TextSize(const string text,int &width,int &height)
{
if(FontSet())
TextGetSize(text,width,height);
}
//+------------------------------------------------------------------+
//| Load data from file |
//+------------------------------------------------------------------+
bool CCanvas::LoadFromFile(const string filename)
{
//--- load image
if(!CCanvas::LoadBitmap(filename,m_pixels,m_width,m_height))
return(false);
//--- color components are not processed by terminal (they should be correctly specified by user)
if(m_format==COLOR_FORMAT_ARGB_RAW)
{
uchar a,r,g,b;
int img_size=m_width*m_height;
//--- convert image to premultiplied ARGB
for(int i=0; i<img_size; i++)
{
switch(a=GETRGBA(m_pixels[i]))
{
case 0xFF:
break;
case 0x00:
m_pixels[i]=0;
break;
default:
r=GETRGBR(m_pixels[i])*a/255;
g=GETRGBG(m_pixels[i])*a/255;
b=GETRGBB(m_pixels[i])*a/255;
m_pixels[i]=ARGB(a,r,g,b);
break;
}
}
}
//--- success
return(true);
}
//+------------------------------------------------------------------+
//| Load data from file |
//+------------------------------------------------------------------+
bool CCanvas::LoadBitmap(const string filename,uint &data[],int &width,int &height)
{
struct BitmapHeader
{
ushort type;
uint size;
uint reserv;
uint offbits;
uint imgSSize;
uint imgWidth;
uint imgHeight;
ushort imgPlanes;
ushort imgBitCount;
uint imgCompression;
uint imgSizeImage;
uint imgXPelsPerMeter;
uint imgYPelsPerMeter;
uint imgClrUsed;
uint imgClrImportant;
};
BitmapHeader header;
bool result=true;
CFileBin file;
uint img_size;
bool no_alpha,no_flip=false;
uchar r,g,b;
//--- open file
if(file.Open(filename,FILE_READ)==INVALID_HANDLE)
{
Print("File not found");
return(false);
}
//--- read header
if(file.ReadStruct(header)!=sizeof(header))
{
Print("Failed to read file header");
file.Close();
return(false);
}
width =(int)header.imgWidth;
height=(int)header.imgHeight;
if(height<0)
{
height=-height;
no_flip=true;
}
//--- process depending on color depth
if(header.imgBitCount==32)
{
no_alpha=true;
img_size=file.ReadArray(data);
//--- flip image
if(!no_flip)
for(int i=0; i<height/2; i++)
{
uint tmp[];
ArrayCopy(tmp,data,0,width*i,width);
ArrayCopy(data,data,width*i,width*(height-i-1),width);
ArrayCopy(data,tmp,width*(height-i-1),0,width);
}
//--- check if at least one pixel has alpha channel
//--- then leave image as is (consider it as premultiplied ARGB)
for(uint i=0; i<img_size; i++)
{
//--- there is alpha channel
if(GETRGBA(data[i])!=0)
{
no_alpha=false;
break;
}
}
//--- no alpha channel
if(no_alpha)
{
//--- consider image as nontransparent, add alpha channel as 0xFF
for(uint i=0; i<img_size; i++)
data[i]|=0xFF000000;
}
}
else
{
//--- 24 bits - change image color depth to 32 bits
int byte_width;
//--- allocate memory for pixels
if(ArrayResize(data,width*height)!=-1)
{
//--- the number of bytes that define a line of pixels must be multiple of 4
byte_width=width*3; // number of bytes in line of pixels
byte_width=(byte_width+3)&~3; // align line to the 4 byte boundary
uchar tmp[];
for(int i=0; i<height; i++)
{
if(file.ReadArray(tmp,0,byte_width)!=byte_width)
{
result=false;
break;
}
for(int j=0,k=0,p=width*(height-i-1); j<width; j++,p++,k+=3)
{
r=tmp[k+2];
g=tmp[k+1];
b=tmp[k];
data[p]=XRGB(r,g,b);
}
}
}
else
result=false;
}
//--- succeed
file.Close();
return(result);
}
//+------------------------------------------------------------------+
//| Determines direction of points iteration (<0 - clockwise) |
//+------------------------------------------------------------------+
int CCanvas::PointClassify(const CPoint &p0,const CPoint &p1,const CPoint &p2)
{
return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));
}
//+------------------------------------------------------------------+
//| Determines direction of polygon iteration |
//+------------------------------------------------------------------+
int CCanvas::PolygonClassify(const CPoint &p[])
{
int total=ArraySize(p);
int im= 0;
int xm=p[0].x;
int ym=p[0].y;
//--- find the most top-left vertex
for(int i=1; i<total; i++)
{
if(p[i].y>ym)
continue;
if((p[i].y==ym) && (p[i].x>xm))
continue;
im=i;
xm=p[i].x;
ym=p[i].y;
}
//--- check the orientation of triangle
return PointClassify(p[(im-1+total)%total],p[im],p[(im+1)%total]);
}
//+------------------------------------------------------------------+
//| Checks convexity of polygon |
//+------------------------------------------------------------------+
bool CCanvas::IsPolygonConvex(CPoint &p[])
{
int total=ArraySize(p);
//--- triangle - always convex
if(total==3)
return(true);
int res=SIGN(PointClassify(p[0],p[1],p[2]));
for(int i=1; i<total; i++)
{
int res1=SIGN(PointClassify(p[i],p[(i+1)%total],p[(i+2)%total]));
if(res!=res1)
return(false);
}
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Normalizes polygon for drawing |
//+------------------------------------------------------------------+
void CCanvas::PolygonNormalize(CPoint &p[])
{
int total=ArraySize(p);
//--- find top-left point
int imin=0;
int xmin=p[0].x;
int ymin=p[0].y;
for(int i=1; i<total; i++)
{
if(p[i].y>ymin)
continue;
if(p[i].y==ymin)
{
if(p[i].x<xmin)
{
xmin=p[i].x;
imin=i;
}
continue;
}
xmin=p[i].x;
ymin=p[i].y;
imin=i;
}
if(imin==0)
return;
for(int i=0; i<imin; i++)
{
CPoint tmp=p[0];
ArrayCopy(p,p,0,1);
p[total-1]=tmp;
}
}
//+------------------------------------------------------------------+
//| Dissects non-convex polygon into two |
//+------------------------------------------------------------------+
void CCanvas::PolygonIntersect(CPoint &p[],CPoint &add[])
{
int total=ArraySize(p);
int res=SIGN(PolygonClassify(p));
//--- scan vertices clockwise and counterclockwise to find a non-convex one
for(int i=0; i<total; i++)
{
int rr=SIGN(PointClassify(p[i],p[(i+1)%total],p[(i+2)%total]));
int rl=SIGN(PointClassify(p[(total-i-2)%total],p[(total-i-1)%total],p[(total-i)%total]));
if(rl!=res || rr!=res)
{
//--- find non-convex vertex, dissect
res=(total-i-1)-(i+1);
if(res<0)
return;
if(res<2)
{
ArrayResize(add,total-i);
add[0]=p[0];
ArrayCopy(add,p,1,i+1,total-i-1);
ArrayResize(p,i+2);
}
else
{
ArrayResize(add,res+1);
ArrayCopy(add,p,0,i+1,res+1);
ArrayCopy(p,p,i+2,i+res+1,total-res-i-1);
ArrayResize(p,total-res+1);
}
break;
}
}
}
//+------------------------------------------------------------------+
//| Draws filled convex polygon (point 0 is top-left) |
//+------------------------------------------------------------------+
void CCanvas::PolygonFill(CPoint &p[],const uint clr)
{
int il,ir;
double xl,xr;
int yy;
double dl=0.0,dr=0.0;
int total=ArraySize(p);
//--- check
if(total<3)
return;
//--- check polygon for convexity
while(!IsPolygonConvex(p))
{
CPoint add[];
PolygonIntersect(p,add);
PolygonNormalize(add);
PolygonFill(add,clr);
ArrayFree(add);
}
total=ArraySize(p);
//--- initial settings
il=ir=0;
xl=xr=p[0].x;
yy=p[0].y;
//--- in case of top horizontal line
if(yy==p[1].y)
xr=p[ir=1].x;
//--- draw the top
LineHorizontal((int)MathCeil(xl),(int)MathFloor(xr),yy,clr);
//--- loop by Y
do
{
while(yy==p[il].y)
{
il=(il-1+total)%total;
if(yy>p[il].y)
return;
if(yy!=p[il].y)
{
dl=(p[il].x-xl)/(p[il].y-yy);
//--- make adjustment for half of left increment dl/2
LineHorizontal((int)MathCeil(xl+dl/2),(int)MathFloor(xl),yy,clr);
xl+=dl/2;
}
else
LineHorizontal((int)MathCeil(xl),(int)MathFloor(p[il].x),yy,clr);
}
while(yy==p[ir].y)
{
ir=(ir+1)%total;
if(yy>p[ir].y)
return;
if(yy!=p[ir].y)
{
dr=(p[ir].x-xr)/(p[ir].y-yy);
//--- make adjustment for half of right increment dr/2
LineHorizontal((int)MathCeil(xr),(int)MathFloor(xr+dr/2),yy,clr);
xr+=dr/2;
}
else
LineHorizontal((int)MathCeil(p[ir].x),(int)MathFloor(xr),yy,clr);
}
yy++;
if(yy==p[il].y)
xl=p[il].x;
else
xl+=dl;
if(yy==p[ir].y)
xr=p[ir].x;
else
xr+=dr;
LineHorizontal((int)MathCeil(xl),(int)MathFloor(xr),yy,clr);
}
while(il>=ir && ir!=0);
}
//+------------------------------------------------------------------+
//| Draw line according to Wu's algorithm |
//+------------------------------------------------------------------+
void CCanvas::LineWu(int x1,int y1,int x2,int y2,const uint clr,const uint style=UINT_MAX)
{
//--- calculating the variation of the coordinates
int dx = (x2 > x1) ? (x2 - x1) : (x1 - x2);
int dy = (y2 > y1) ? (y2 - y1) : (y1 - y2);
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
int tmp;
//--- check if dx==0 then draw vertical line
if(dx==0)
{
//--- sort by Y
if(y1>y2)
{
tmp=y1;
y1 =y2;
y2 =tmp;
}
//--- line is out of image boundaries
if(y2<0 || y1>=m_height || x1<0 || x1>=m_width)
{
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
return;
}
//--- stay withing image boundaries
if(y1<0)
y1=0;
if(y2>=m_height-1)
y2=m_height-1;
//--- draw line
int index=y1*m_width+x1;
for(int i=y1; i<=y2; i++,index+=m_width)
{
if((m_style&mask)==mask)
m_pixels[index]=clr;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
//--- success
return;
}
//--- check if dy==0 then draw horizontal line
if(dy==0)
{
//--- sort by X
if(x1>x2)
{
tmp=x1;
x1 =x2;
x2 =tmp;
}
//--- line is out of image boundaries
if(x2<0 || x1>=m_width || y1<0 || y1>=m_height)
{
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
return;
}
//--- stay withing image boundaries
if(x1<0)
x1=0;
if(x2>=m_width)
x2=m_width-1;
//--- draw line
for(int i=0,index=y1*m_width+x1; i<x2-x1; i++,index++)
{
if((m_style&mask)==mask)
m_pixels[index]=clr;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
//--- success
return;
}
//--- check if dx==0 and dy==0 then draw point
if(dx==0 && dy==0)
{
PixelSet(x1,y1,clr);
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
//--- success
return;
}
//--- for the X-line (slope < 1)
if(dy<dx)
{
//--- first point has to have a smaller X coordinate
if(x2<x1)
{
x2 += x1;
x1 = x2 - x1;
x2 -= x1;
y2 += y1;
y1 = y2 - y1;
y2 -= y1;
}
if(y2<y1)
{
dy*=-1;
}
//--- relative change of the Y
float grad=(float)dy/dx;
//--- intermediate variable for Y
float intery=y1+grad;
//--- first point
if((m_style&mask)==mask)
PixelSet(x1,y1,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
for(int x=x1+1; x<x2; x++)
{
double alpha1=1-(intery-(int)intery);
double alpha2=(intery-(int)intery);
if((m_style&mask)==mask)
{
//--- high point
PixelTransform(x,(int)(intery),clr,alpha1);
//--- low point
PixelTransform(x,(int)(intery)+1,clr,alpha2);
}
//--- change the Y coordinate
intery+=grad;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last point
if((m_style&mask)==mask)
PixelSet(x2,y2,clr);
}
//--- for the Y-line (slope > 1)
else
{
//--- first point has to have a smaller Y coordinate
if(y2<y1)
{
x2 += x1;
x1 = x2 - x1;
x2 -= x1;
y2 += y1;
y1 = y2 - y1;
y2 -= y1;
}
if(x2<x1)
{
dx*=-1;
}
//--- relative change of the X
float grad=(float)dx/dy;
//--- intermediate variable for X
float interx=x1+grad;
//--- first point
if((m_style&mask)==mask)
PixelSet(x1,y1,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
for(int y=y1+1; y<y2; y++)
{
double alpha1=1-(interx-(int)interx);
double alpha2=(interx-(int)interx);
if((m_style&mask)==mask)
{
//--- high point
PixelTransform((int)(interx),y,clr,alpha1);
//--- low point
PixelTransform((int)(interx)+1,y,clr,alpha2);
}
//--- change the X coordinate
interx+=grad;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last point
if((m_style&mask)==mask)
PixelSet(x2,y2,clr);
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw Wu's polyline |
//+------------------------------------------------------------------+
void CCanvas::PolylineWu(const int &x[],const int &y[],const uint clr,const uint style=UINT_MAX)
{
//--- check arrays
int total=ArraySize(x);
if(total>ArraySize(y))
total=ArraySize(y);
//--- check
if(total<2)
return;
total--;
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw
for(int i=0; i<total; i++)
{
int x1=x[i];
int x2=x[i+1];
int y1=y[i];
int y2=y[i+1];
//--- calculating the variation of the coordinates
int dx = (x2 > x1) ? (x2 - x1) : (x1 - x2);
int dy = (y2 > y1) ? (y2 - y1) : (y1 - y2);
int tmp;
//--- check if dx==0 then draw vertical line
if(dx==0)
{
//--- sort by Y
if(y1>y2)
{
tmp=y1;
y1 =y2;
y2 =tmp;
}
//--- line is out of image boundaries
if(y2<0 || y1>=m_height || x1<0 || x1>=m_width)
continue;
//--- stay withing image boundaries
if(y1<0)
y1=0;
if(y2>=m_height-1)
y2=m_height-1;
//--- draw line
int index=y1*m_width+x1;
for(int j=y1; j<=y2; j++,index+=m_width)
{
if((m_style&mask)==mask)
m_pixels[index]=clr;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
continue;
}
//--- check if dy==0 then draw horizontal line
if(dy==0)
{
//--- sort by X
if(x1>x2)
{
tmp=x1;
x1 =x2;
x2 =tmp;
}
//--- line is out of image boundaries
if(x2<0 || x1>=m_width || y1<0 || y1>=m_height)
continue;
//--- stay withing image boundaries
if(x1<0)
x1=0;
if(x2>=m_width)
x2=m_width-1;
//--- draw line
for(int j=0,index=y1*m_width+x1; j<x2-x1; j++,index++)
{
if((m_style&mask)==mask)
m_pixels[index]=clr;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
continue;
}
//--- check if dx==0 and dy==0 then draw point
if(dx==0 && dy==0)
{
PixelSet(x1,y1,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
continue;
}
//--- for the X-line (slope < 1)
if(dy<dx)
{
//--- first point has to have a smaller X coordinate
if(x2<x1)
{
x2 += x1;
x1 = x2 - x1;
x2 -= x1;
y2 += y1;
y1 = y2 - y1;
y2 -= y1;
}
if(y2<y1)
{
dy*=-1;
}
//--- relative change of the Y
float grad=(float)dy/dx;
//--- intermediate variable for Y
float intery=y1+grad;
//--- first point
if((m_style&mask)==mask)
PixelSet(x1,y1,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
for(int xc=x1+1; xc<x2; xc++)
{
double alpha1=1-(intery-(int)intery);
double alpha2=(intery-(int)intery);
if((m_style&mask)==mask)
{
//--- high point
PixelTransform(xc,(int)(intery),clr,alpha1);
//--- low point
PixelTransform(xc,(int)(intery)+1,clr,alpha2);
}
//--- change the Y coordinate
intery+=grad;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last point
if((m_style&mask)==mask)
PixelSet(x2,y2,clr);
}
//--- for the Y-line (slope > 1)
else
{
//--- first point has to have a smaller Y coordinate
if(y2<y1)
{
x2 += x1;
x1 = x2 - x1;
x2 -= x1;
y2 += y1;
y1 = y2 - y1;
y2 -= y1;
}
if(x2<x1)
{
dx*=-1;
}
//--- relative change of the X
float grad=(float)dx/dy;
//--- intermediate variable for X
float interx=x1+grad;
//--- first point
if((m_style&mask)==mask)
PixelSet(x1,y1,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
for(int yc=y1+1; yc<y2; yc++)
{
double alpha1=1-(interx-(int)interx);
double alpha2=(interx-(int)interx);
if((m_style&mask)==mask)
{
//--- high point
PixelTransform((int)(interx),yc,clr,alpha1);
//--- low point
PixelTransform((int)(interx)+1,yc,clr,alpha2);
}
//--- change the X coordinate
interx+=grad;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last point
if((m_style&mask)==mask)
PixelSet(x2,y2,clr);
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw Wu's polygon |
//+------------------------------------------------------------------+
void CCanvas::PolygonWu(const int &x[],const int &y[],const uint clr,const uint style=UINT_MAX)
{
//--- check arrays
int total=ArraySize(x);
if(total>ArraySize(y))
total=ArraySize(y);
//--- check
if(total<2)
return;
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw
for(int i=0; i<total; i++)
{
int x1=x[i];
int y1=y[i];
int x2=(i+1!=total) ? x[i+1] : x[0];
int y2=(i+1!=total) ? y[i+1] : y[0];
//--- calculating the variation of the coordinates
int dx = (x2 > x1) ? (x2 - x1) : (x1 - x2);
int dy = (y2 > y1) ? (y2 - y1) : (y1 - y2);
int tmp;
//--- check if dx==0 then draw vertical line
if(dx==0)
{
//--- sort by Y
if(y1>y2)
{
tmp=y1;
y1 =y2;
y2 =tmp;
}
//--- line is out of image boundaries
if(y2<0 || y1>=m_height || x1<0 || x1>=m_width)
continue;
//--- stay withing image boundaries
if(y1<0)
y1=0;
if(y2>=m_height-1)
y2=m_height-1;
//--- draw line
int index=y1*m_width+x1;
for(int j=y1; j<=y2; j++,index+=m_width)
{
if((m_style&mask)==mask)
m_pixels[index]=clr;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
continue;
}
//--- check if dy==0 then draw horizontal line
if(dy==0)
{
//--- sort by X
if(x1>x2)
{
tmp=x1;
x1 =x2;
x2 =tmp;
}
//--- line is out of image boundaries
if(x2<0 || x1>=m_width || y1<0 || y1>=m_height)
continue;
//--- stay withing image boundaries
if(x1<0)
x1=0;
if(x2>=m_width)
x2=m_width-1;
//--- draw line
for(int j=0,index=y1*m_width+x1; j<x2-x1; j++,index++)
{
if((m_style&mask)==mask)
m_pixels[index]=clr;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
continue;
}
//--- check if dx==0 and dy==0 then draw point
if(dx==0 && dy==0)
{
PixelSet(x1,y1,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
continue;
}
//--- for the X-line (slope < 1)
if(dy<dx)
{
//--- first point has to have a smaller X coordinate
if(x2<x1)
{
x2 += x1;
x1 = x2 - x1;
x2 -= x1;
y2 += y1;
y1 = y2 - y1;
y2 -= y1;
}
if(y2<y1)
{
dy*=-1;
}
//--- relative change of the Y
float grad=(float)dy/dx;
//--- intermediate variable for Y
float intery=y1+grad;
//--- first point
if((m_style&mask)==mask)
PixelSet(x1,y1,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
for(int xc=x1+1; xc<x2; xc++)
{
double alpha1=1-(intery-(int)intery);
double alpha2=(intery-(int)intery);
if((m_style&mask)==mask)
{
//--- high point
PixelTransform(xc,(int)(intery),clr,alpha1);
//--- low point
PixelTransform(xc,(int)(intery)+1,clr,alpha2);
}
//--- change the Y coordinate
intery+=grad;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last point
if((m_style&mask)==mask)
PixelSet(x2,y2,clr);
}
//--- for the Y-line (slope > 1)
else
{
//--- first point has to have a smaller Y coordinate
if(y2<y1)
{
x2 += x1;
x1 = x2 - x1;
x2 -= x1;
y2 += y1;
y1 = y2 - y1;
y2 -= y1;
}
if(x2<x1)
{
dx*=-1;
}
//--- relative change of the X
float grad=(float)dx/dy;
//--- intermediate variable for X
float interx=x1+grad;
//--- first point
if((m_style&mask)==mask)
PixelSet(x1,y1,clr);
mask<<=1;
if(mask==0x1000000)
mask=1;
for(int yc=y1+1; yc<y2; yc++)
{
double alpha1=1-(interx-(int)interx);
double alpha2=(interx-(int)interx);
if((m_style&mask)==mask)
{
//--- high point
PixelTransform((int)(interx),yc,clr,alpha1);
//--- low point
PixelTransform((int)(interx)+1,yc,clr,alpha2);
}
//--- change the X coordinate
interx+=grad;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last point
if((m_style&mask)==mask)
PixelSet(x2,y2,clr);
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw triangle with Wu's lines |
//+------------------------------------------------------------------+
void CCanvas::TriangleWu(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3,const uint clr,const uint style=UINT_MAX)
{
//--- draw
int x[3];
int y[3];
x[0] = x1;
x[1] = x2;
x[2] = x3;
y[0] = y1;
y[1] = y2;
y[2] = y3;
PolygonWu(x,y,clr,style);
}
//+------------------------------------------------------------------+
//| Draw circle according to Wu's algorithm |
//+------------------------------------------------------------------+
void CCanvas::CircleWu(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX)
{
if(r<=0)
return;
//--- preliminary calculations
double r2=r*r;
double quarter=round(r/sqrt(2.0));
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw
for(int d1=0; d1<=quarter; d1++)
{
double d2=sqrt(r2-d1*d1);
double alpha1=d2-floor(d2);
double alpha2=1-alpha1;
if((m_style&mask)==mask)
{
PixelTransform4(x,y,(int)d2+1,d1,clr,alpha1);
PixelTransform4(x,y,d1,(int)(d2)+1,clr,alpha1);
}
mask<<=1;
if(mask==0x1000000)
mask=1;
if((m_style&mask)==mask)
{
PixelTransform4(x,y,d1,(int)(d2),clr,alpha2);
PixelTransform4(x,y,(int)d2,d1,clr,alpha2);
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw ellipse according to Wu's algorithm |
//+------------------------------------------------------------------+
void CCanvas::EllipseWu(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style=UINT_MAX)
{
int rx=(int)(x2-x1)/2;
int ry=(int)(y2-y1)/2;
int x=(x2>x1) ? x1+rx : x2+rx;
int y=(y2>y1) ? y1+ry : y2+ry;
if(rx<=0 || ry<=0)
return;
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- preliminary calculations
double rx2=rx*rx;
double ry2=ry*ry;
double quarter=round(rx2/sqrt(rx2+ry2));
//--- draw
for(int dx=0; dx<=quarter; dx++)
{
double dy=ry*sqrt(1-dx*dx/rx2);
double alpha1=dy-floor(dy);
double alpha2=1-alpha1;
if((m_style&mask)==mask)
{
PixelTransform4(x,y,dx,(int)(dy)+1,clr,alpha1);
PixelTransform4(x,y,dx,(int)(dy),clr,alpha2);
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
quarter=round(ry2/sqrt(rx2+ry2));
for(int dy=0; dy<=quarter; dy++)
{
double dx=rx*sqrt(1-dy*dy/ry2);
double alpha1=dx-floor(dx);
double alpha2=1-alpha1;
if((m_style&mask)==mask)
{
PixelTransform4(x,y,(int)(dx)+1,dy,clr,alpha1);
PixelTransform4(x,y,(int)(dx),dy,clr,alpha2);
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw vertical thick line with prefiltered antialiasing |
//+------------------------------------------------------------------+
void CCanvas::LineThickVertical(const int x,const int y1,const int y2,const uint clr,const int size,const uint style,ENUM_LINE_END end_style)
{
if(size<=2)
{
if(size>0)
LineWu(x,y1,x,y2,clr,style);
return;
}
//--- r be the filter radius (and also the half-width of the wide line)
double r=(size/2.0);
//--- primary calculate
int dy=MathAbs(y2-y1);
int sign=(y1<y2) ? 1 : -1;
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw vertical thick line by segment
if(style==STYLE_SOLID)
{
SegmentVertical(x,y1,y2,sign,r,clr,end_style);
}
else
{
int ys=0;
int ye=0;
int steps=(int)MathRound(dy/r);
bool segment=false;
for(int i=0; i<=steps; i++)
{
if((m_style&mask)==mask && !segment)
{
ys=y1+(sign)*(int)(i*r);
segment=true;
}
else
if((m_style&mask)!=mask && segment)
{
ye=y1+(sign)*(int)(i*r);
SegmentVertical(x,ys,ye,sign,r,clr,end_style);
segment=false;
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last segment
if(segment)
SegmentVertical(x,ys,y2,sign,r,clr,end_style);
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw horizontal thick line with prefiltered antialiasing |
//+------------------------------------------------------------------+
void CCanvas::LineThickHorizontal(const int x1,const int x2,const int y,const uint clr,const int size,const uint style,ENUM_LINE_END end_style)
{
if(size<=2)
{
if(size>0)
LineWu(x1,y,x2,y,clr,style);
return;
}
//--- r be the filter radius (and also the half-width of the wide line)
double r=(size/2.0);
//--- primary calculate
int dx=MathAbs(x2-x1);
int sign=(x1<x2) ? 1 : -1;
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw horizontal thick line by segment
if(style==STYLE_SOLID)
{
SegmentHorizontal(x1,x2,y,sign,r,clr,end_style);
}
else
{
int xs=0;
int xe=0;
int steps=(int)MathRound(dx/r);
bool segment=false;
for(int i=0; i<=steps; i++)
{
if((m_style&mask)==mask && !segment)
{
xs=x1+(sign)*(int)(i*r);
segment=true;
}
else
if((m_style&mask)!=mask && segment)
{
xe=x1+(sign)*(int)(i*r);
SegmentHorizontal(xs,xe,y,sign,r,clr,end_style);
segment=false;
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last segment
if(segment)
SegmentHorizontal(xs,x2,y,sign,r,clr,end_style);
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw thick line with prefiltered antialiasing |
//+------------------------------------------------------------------+
void CCanvas::LineThick(const int x1,const int y1,const int x2,const int y2,const uint clr,const int size,const uint style,ENUM_LINE_END end_style)
{
if(size<=2)
{
if(size>0)
LineWu(x1,y1,x2,y2,clr,style);
return;
}
//--- r be the filter radius (and also the half-width of the wide line)
double r=(size/2.0);
//--- compute x and y deltas
double dx=MathAbs(x2-x1);
double dy=MathAbs(y2-y1);
if(dx==0)
{
LineThickVertical(x1,y1,y2,size,clr,style,end_style);
return;
}
if(dy==0)
{
LineThickHorizontal(x1,x2,y1,size,clr,style,end_style);
return;
}
//--- compute the linear coefficients of the two (scaled) edge functions
double k=MathArctan(dx/dy);
double rcos_k=r*cos(k);
double rsin_k=r*sin(k);
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- primary calculate
int xsign = (x1<x2) ? 1 : -1;
int ysign = (y1<y2) ? 1 : -1;
double kp0=(-xsign*ysign)*(dx/dy);
double kp1=-1/kp0;
//--- draw thick line by segment
if(style==STYLE_SOLID)
{
Segment(x1,y1,x2,y2,kp0,kp1,xsign,ysign,rcos_k,rsin_k,r,clr,end_style);
}
else
{
int xs=0;
int ys=0;
int xe=0;
int ye=0;
double length=MathSqrt(dx*dx+dy*dy);
int steps=(int)MathRound(length/r);
bool segment=false;
for(int i=0; i<=steps; i++)
{
if((m_style&mask)==mask && !segment)
{
xs=x1+(xsign)*(int)(i*rsin_k);
ys=y1+(ysign)*(int)(i*rcos_k);
segment=true;
}
else
if((m_style&mask)!=mask && segment)
{
xe=x1+(xsign)*(int)(i*rsin_k);
ye=y1+(ysign)*(int)(i*rcos_k);
Segment(xs,ys,xe,ye,kp0,kp1,xsign,ysign,rcos_k,rsin_k,r,clr,end_style);
segment=false;
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last segment
if(segment)
Segment(xs,ys,x2,y2,kp0,kp1,xsign,ysign,rcos_k,rsin_k,r,clr,end_style);
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw thick polyline |
//+------------------------------------------------------------------+
void CCanvas::PolylineThick(const int &x[],const int &y[],const uint clr,const int size,const uint style,ENUM_LINE_END end_style)
{
if(size<=2)
{
if(size>0)
PolylineWu(x,y,clr,style);
return;
}
//--- check arrays
int total=ArraySize(x);
if(total>ArraySize(y))
total=ArraySize(y);
//--- check
if(total<2)
return;
total--;
//--- r be the filter radius (and also the half-width of the wide line)
double r=(size/2.0);
//---
double gap=1.0;
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw
for(int index=0; index<total; index++)
{
int x1=x[index];
int y1=y[index];
int x2=x[index+1];
int y2=y[index+1];
//--- compute x and y deltas
double dx=MathAbs(x2-x1);
double dy=MathAbs(y2-y1);
if(dx==0)
{
int sign=(y1<y2) ? 1 : -1;
//--- draw vertical thick line by segment
if(style==STYLE_SOLID)
{
SegmentVertical(x1,y1,y2,sign,r,clr,end_style);
}
else
{
int ys=y1;
int ye=0;
double steps=dy/r;
int isteps=(int)steps;
bool segment=false;
for(int i=0; i<isteps; i++)
{
if((m_style&mask)==mask && !segment)
{
ys=y1+(sign)*(int)(i*r);
segment=true;
}
else
if((m_style&mask)!=mask && segment)
{
ye=y1+(sign)*(int)(i*r);
SegmentVertical(x1,ys,ye,sign,r,clr,end_style);
segment=false;
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last segment
if(segment || (steps<1 && (m_style&mask)==mask))
SegmentVertical(x1,ys,y2,sign,r,clr,end_style);
gap-=steps-isteps;
if(gap<0)
{
gap++;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
}
continue;
}
if(dy==0)
{
int sign=(x1<x2) ? 1 : -1;
//--- draw horizontal thick line by segment
if(style==STYLE_SOLID)
{
SegmentHorizontal(x1,x2,y1,sign,r,clr,end_style);
}
else
{
int xs=x1;
int xe=0;
double steps=dx/r;
int isteps=(int)steps;
bool segment=false;
for(int i=0; i<isteps; i++)
{
if((m_style&mask)==mask && !segment)
{
xs=x1+(sign)*(int)(i*r);
segment=true;
}
else
if((m_style&mask)!=mask && segment)
{
xe=x1+(sign)*(int)(i*r);
SegmentHorizontal(xs,xe,y1,sign,r,clr,end_style);
segment=false;
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last segment
if(segment || (steps<1 && (m_style&mask)==mask))
SegmentHorizontal(xs,x2,y1,sign,r,clr,end_style);
gap-=steps-isteps;
if(gap<0)
{
gap++;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
}
continue;
}
//--- compute the linear coefficients of the two (scaled) edge functions
double k=MathArctan(dx/dy);
double rcos_k=r*cos(k);
double rsin_k=r*sin(k);
//--- primary calculate
int xsign=(x1<x2) ? 1 : -1;
int ysign=(y1<y2) ? 1 : -1;
double kp0=(-xsign*ysign)*(dx/dy);
double kp1=-1/kp0;
//--- draw thick line by segment
if(style==STYLE_SOLID)
{
Segment(x1,y1,x2,y2,kp0,kp1,xsign,ysign,rcos_k,rsin_k,r,clr,end_style);
}
else
{
int xs=x1;
int ys=y1;
int xe=0;
int ye=0;
double length=MathSqrt(dx*dx+dy*dy);
double steps=length/r;
int isteps=(int)steps;
bool segment=false;
for(int i=0; i<isteps; i++)
{
if((m_style&mask)==mask && !segment)
{
xs=x1+(xsign)*(int)(i*rsin_k);
ys=y1+(ysign)*(int)(i*rcos_k);
segment=true;
}
else
if((m_style&mask)!=mask && segment)
{
xe=x1+(xsign)*(int)(i*rsin_k);
ye=y1+(ysign)*(int)(i*rcos_k);
Segment(xs,ys,xe,ye,kp0,kp1,xsign,ysign,rcos_k,rsin_k,r,clr,end_style);
segment=false;
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last segment
if(segment || (steps<1 && (m_style&mask)==mask))
Segment(xs,ys,x2,y2,kp0,kp1,xsign,ysign,rcos_k,rsin_k,r,clr,end_style);
gap-=steps-isteps;
if(gap<0)
{
gap++;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
}
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Draw thick polygon |
//+------------------------------------------------------------------+
void CCanvas::PolygonThick(const int &x[],const int &y[],const uint clr,const int size,const uint style,ENUM_LINE_END end_style)
{
if(size<=2)
{
if(size>0)
PolylineWu(x,y,clr,style);
return;
}
//--- check arrays
int total=ArraySize(x);
if(total>ArraySize(y))
total=ArraySize(y);
//--- check
if(total<2)
return;
//--- r be the filter radius (and also the half-width of the wide line)
double r=(size/2.0);
//---
double gap=1.0;
//--- set the line style
uint prev_style=m_style;
if(style!=UINT_MAX)
LineStyleSet(style);
uint mask=1<<m_style_idx;
//--- draw
for(int index=0; index<total; index++)
{
int x1=x[index];
int y1=y[index];
int x2=(index!=total-1) ? x[index+1] : x[0];
int y2=(index!=total-1) ? y[index+1] : y[0];
//--- compute x and y deltas
double dx=MathAbs(x2-x1);
double dy=MathAbs(y2-y1);
if(dx==0)
{
int sign=(y1<y2) ? 1 : -1;
//--- draw vertical thick line by segment
if(style==STYLE_SOLID)
{
SegmentVertical(x1,y1,y2,sign,r,clr,end_style);
}
else
{
int ys=y1;
int ye=0;
double steps=dy/r;
int isteps=(int)steps;
bool segment=false;
for(int i=0; i<isteps; i++)
{
if((m_style&mask)==mask && !segment)
{
ys=y1+(sign)*(int)(i*r);
segment=true;
}
else
if((m_style&mask)!=mask && segment)
{
ye=y1+(sign)*(int)(i*r);
SegmentVertical(x1,ys,ye,sign,r,clr,end_style);
segment=false;
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last segment
if(segment || (steps<1 && (m_style&mask)==mask))
SegmentVertical(x1,ys,y2,sign,r,clr,end_style);
gap-=steps-isteps;
if(gap<0)
{
gap++;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
}
continue;
}
if(dy==0)
{
int sign=(x1<x2) ? 1 : -1;
//--- draw horizontal thick line by segment
if(style==STYLE_SOLID)
{
SegmentHorizontal(x1,x2,y1,sign,r,clr,end_style);
}
else
{
int xs=x1;
int xe=0;
double steps=dx/r;
int isteps=(int)steps;
bool segment=false;
for(int i=0; i<isteps; i++)
{
if((m_style&mask)==mask && !segment)
{
xs=x1+(sign)*(int)(i*r);
segment=true;
}
else
if((m_style&mask)!=mask && segment)
{
xe=x1+(sign)*(int)(i*r);
SegmentHorizontal(xs,xe,y1,sign,r,clr,end_style);
segment=false;
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last segment
if(segment || (steps<1 && (m_style&mask)==mask))
SegmentHorizontal(xs,x2,y1,sign,r,clr,end_style);
gap-=steps-isteps;
if(gap<0)
{
gap++;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
}
continue;
}
//--- compute the linear coefficients of the two (scaled) edge functions
double k=MathArctan(dx/dy);
double rcos_k=r*cos(k);
double rsin_k=r*sin(k);
//--- primary calculate
int xsign=(x1<x2) ? 1 : -1;
int ysign=(y1<y2) ? 1 : -1;
double kp0=(-xsign*ysign)*(dx/dy);
double kp1=-1/kp0;
//--- draw thick line by segment
if(style==STYLE_SOLID)
{
Segment(x1,y1,x2,y2,kp0,kp1,xsign,ysign,rcos_k,rsin_k,r,clr,end_style);
}
else
{
int xs=x1;
int ys=y1;
int xe=0;
int ye=0;
double length=MathSqrt(dx*dx+dy*dy);
double steps=length/r;
int isteps=(int)steps;
bool segment=false;
for(int i=0; i<isteps; i++)
{
if((m_style&mask)==mask && !segment)
{
xs=x1+(xsign)*(int)(i*rsin_k);
ys=y1+(ysign)*(int)(i*rcos_k);
segment=true;
}
else
if((m_style&mask)!=mask && segment)
{
xe=x1+(xsign)*(int)(i*rsin_k);
ye=y1+(ysign)*(int)(i*rcos_k);
Segment(xs,ys,xe,ye,kp0,kp1,xsign,ysign,rcos_k,rsin_k,r,clr,end_style);
segment=false;
}
mask<<=1;
if(mask==0x1000000)
mask=1;
}
//--- last segment
if(segment || (steps<1 && (m_style&mask)==mask))
Segment(xs,ys,x2,y2,kp0,kp1,xsign,ysign,rcos_k,rsin_k,r,clr,end_style);
gap-=steps-isteps;
if(gap<0)
{
gap++;
mask<<=1;
if(mask==0x1000000)
mask=1;
}
}
}
//--- set the previous line style
if(style!=UINT_MAX)
m_style=prev_style;
}
//+------------------------------------------------------------------+
//| Parametric method of color comparison |
//+------------------------------------------------------------------+
bool CCanvas::PixelsSimilar(const uint clr0,const uint clr1,const uint threshould)
{
uint dr=MathAbs(uint((clr0>>16) &0xff) -
uint((clr1>>16) &0xff));
uint dg=MathAbs(uint((clr0>>8) &0xff) -
uint((clr1>>8) &0xff));
uint db=MathAbs(uint((clr0>>0) &0xff) -
uint((clr1>>0) &0xff));
//--- return
return (dr<=threshould || dg<=threshould || db<=threshould);
}
//+------------------------------------------------------------------+
//| Calculate and set new color |
//+------------------------------------------------------------------+
void CCanvas::PixelTransform(const int x,const int y,const uint clr,const double alpha)
{
int index=y*m_width+x;
//--- check
if(x<0 || y<0 || x>m_width || y>m_height || index>=ArraySize(m_pixels))
return;
//--- check alpha
if(alpha==1)
{
m_pixels[index]=clr;
return;
}
//--- get pixel color
uint clr0=m_pixels[index];
//--- transform of color component for the background
double r0 = ((clr0>>16) & 0xFF) * (1.0-alpha);
double g0 = ((clr0>>8) & 0xFF) * (1.0-alpha);
double b0 = ((clr0>>0) & 0xFF) * (1.0-alpha);
//--- transform of color component
double r1 = ((clr>>16) & 0xFF) * (alpha);
double g1 = ((clr>>8) & 0xFF) * (alpha);
double b1 = ((clr>>0) & 0xFF) * (alpha);
//--- components of the new color
int r = (int)(r0+r1);
int g = (int)(g0+g1);
int b = (int)(b0+b1);
//--- set new color
m_pixels[y*m_width+x]=((r<<16)|(g<<8)|(b<<0)|(255<<24));
}
//+------------------------------------------------------------------+
//| Draw 4 pixel with PixelTransform method |
//+------------------------------------------------------------------+
void CCanvas::PixelTransform4(const int x,const int y,const int dx,const int dy,const uint clr,const double alpha)
{
PixelTransform(x+dx,y+dy,clr,alpha);
PixelTransform(x-dx,y+dy,clr,alpha);
PixelTransform(x+dx,y-dy,clr,alpha);
PixelTransform(x-dx,y-dy,clr,alpha);
}
//+------------------------------------------------------------------+
//| Draw 4 pixel with antialiasing |
//+------------------------------------------------------------------+
void CCanvas::PixelSet4AA(const double x,const double y,const double dx,const double dy,const uint clr)
{
PixelSetAA(x+dx,y+dy,clr);
PixelSetAA(x-dx,y+dy,clr);
PixelSetAA(x+dx,y-dy,clr);
PixelSetAA(x-dx,y-dy,clr);
}
//+------------------------------------------------------------------+
//| Draw solid segment for vertical thick line |
//+------------------------------------------------------------------+
void CCanvas::SegmentVertical(const int x,const int y1,const int y2,const int ysign,const double r,const uint clr,ENUM_LINE_END end_style)
{
//--- compute the constol points of the solid segment
int ye1,ye2;
int ys1,ys2;
switch(end_style)
{
case LINE_END_ROUND:
{
ye1=y1;
ye2=y2;
ys1=y1-(int)(ysign*r);
ys2=y2+(int)(ysign*r);
break;
}
case LINE_END_BUTT:
{
ye1=y1;
ye2=y2;
ys1=y1;
ys2=y2;
break;
}
case LINE_END_SQUARE:
{
ye1=y1-(int)(ysign*r);
ye2=y2+(int)(ysign*r);
ys1=ye1;
ys2=ye2;
break;
}
default:
return;
};
//--- darw solid segment
for(int i=0; i<=MathAbs(ys2-ys1); i++)
{
double yi=ys1+(ysign*i);
for(int j=0; j<2*r; j++)
{
double xi=x-r+j;
double dist=DistancePointSegment(xi,yi,x,ye1,x,ye2);
double val=MathAbs(dist/r);
PixelTransform((int)xi,(int)yi,clr,FilterFunction(val));
}
}
}
//+------------------------------------------------------------------+
//| Draw solid segment for horizontal thick line |
//+------------------------------------------------------------------+
void CCanvas::SegmentHorizontal(const int x1,const int x2,const int y,const int xsign,const double r,const uint clr,ENUM_LINE_END end_style)
{
//--- compute the constol points of the solid segment
int xe1,xe2;
int xs1,xs2;
switch(end_style)
{
case LINE_END_ROUND:
{
xe1=x1;
xe2=x2;
xs1=x1-(int)(xsign*r);
xs2=x2+(int)(xsign*r);
break;
}
case LINE_END_BUTT:
{
xe1=x1;
xe2=x2;
xs1=x1;
xs2=x2;
break;
}
case LINE_END_SQUARE:
{
xe1=x1-(int)(xsign*r);
xe2=x2+(int)(xsign*r);
xs1=xe1;
xs2=xe2;
break;
}
default:
return;
};
//--- draw solid segment
for(int i=0; i<=MathAbs(xs2-xs1); i++)
{
double xi=xs1+(xsign*i);
for(int j=0; j<2*r; j++)
{
double yi=y-r+j;
double dist=DistancePointSegment(xi,yi,xe1,y,xe2,y);
double val=MathAbs(dist/r);
PixelTransform((int)xi,(int)yi,clr,FilterFunction(val));
}
}
}
//+------------------------------------------------------------------+
//| Draw solid segment for thick line |
//+------------------------------------------------------------------+
void CCanvas::Segment(const int x1,const int y1,const int x2,const int y2,const double kp0,const double kp1,const int xsign,const int ysign,
const double rcos_k,const double rsin_k,const double r,const uint clr,ENUM_LINE_END end_style)
{
if(x1==x2 && y1==y2)
return;
if(x1==x2)
{
SegmentVertical(x1,y1,y2,ysign,r,clr,end_style);
return;
}
if(y1==y2)
{
SegmentHorizontal(x1,x2,y1,xsign,r,clr,end_style);
return;
}
//--- compute the constol points of the solid segment
int xe1,ye1,xe2,ye2;
int xs1,ys1,xs2,ys2;
switch(end_style)
{
case LINE_END_ROUND:
{
xe1=x1;
ye1=y1;
xe2=x2;
ye2=y2;
xs1=x1-(xsign)*(int)(rsin_k);
ys1=y1-(ysign)*(int)(rcos_k);
xs2=x2+(xsign)*(int)(rsin_k);
ys2=y2+(ysign)*(int)(rcos_k);
break;
}
case LINE_END_BUTT:
{
xe1=x1;
ye1=y1;
xe2=x2;
ye2=y2;
xs1=x1;
ys1=y1;
xs2=x2;
ys2=y2;
break;
}
case LINE_END_SQUARE:
{
xe1=x1-(xsign)*(int)(rsin_k);
ye1=y1-(ysign)*(int)(rcos_k);
xe2=x2+(xsign)*(int)(rsin_k);
ye2=y2+(ysign)*(int)(rcos_k);
xs1=xe1;
ys1=ye1;
xs2=xe2;
ys2=ye2;
break;
}
default:
return;
};
//--- compute the four corners of the wide line
double p0x=xs1+(xsign)*(rcos_k);
double p0y=ys1-(ysign)*(rsin_k);
double p1x=xs1-(xsign)*(rcos_k);
double p1y=ys1+(ysign)*(rsin_k);
double p2x=xs2+(xsign)*(rcos_k);
double p2y=ys2-(ysign)*(rsin_k);
double p3x=xs2-(xsign)*(rcos_k);
double p3y=ys2+(ysign)*(rsin_k);
//--- draw solid segment
if(MathAbs(kp0)>=1)
{
double xi0,xi1;
double height=MathAbs(p3y-p0y);
for(int i=0; i<=height; i++)
{
double y=p0y+(ysign*i);
double xi00 = MathRound(p0x + (y-p0y)/kp0);
double xi01 = MathRound(p1x + (y-p1y)/kp1);
double xi02 = MathRound(p2x + (y-p2y)/kp1);
double xi03 = MathRound(p3x + (y-p3y)/kp0);
if(xsign==1)
{
xi0 = MathMax(xi00,xi01);
xi1 = MathMin(xi02,xi03);
}
else
{
xi0 = MathMin(xi00,xi01);
xi1 = MathMax(xi02,xi03);
}
double width=MathAbs(MathRound(xi1-xi0));
for(int j=0; j<=width; j++)
{
double xi=xi0+(xsign*j);
double dist=DistancePointSegment(xi,y,xe1,ye1,xe2,ye2);
double val = MathAbs(dist/r);
PixelTransform((int)xi,(int)y,clr,FilterFunction(val));
}
}
}
else
{
double yi0,yi1;
double width=MathAbs(p2x-p1x);
for(int i=0; i<=width; i++)
{
double x=p1x+(xsign*i);
double yi00 = MathRound(p0y + (x-p0x)*kp0);
double yi01 = MathRound(p1y + (x-p1x)*kp1);
double yi02 = MathRound(p2y + (x-p2x)*kp1);
double yi03 = MathRound(p3y + (x-p3x)*kp0);
if(ysign==1)
{
yi0 = MathMax(yi00,yi02);
yi1 = MathMin(yi01,yi03);
}
else
{
yi0 = MathMin(yi00,yi02);
yi1 = MathMax(yi01,yi03);
}
double height=MathAbs(yi1-yi0);
for(int j=0; j<=height; j++)
{
double yi=yi0+(ysign*j);
double dist=DistancePointSegment(x,yi,xe1,ye1,xe2,ye2);
double val=MathAbs(dist/r);
PixelTransform((int)x,(int)yi,clr,FilterFunction(val));
}
}
}
}
//+------------------------------------------------------------------+
//| Filter function for calculating alpha channel |
//+------------------------------------------------------------------+
double CCanvas::FilterFunction(const double x)
{
if(x<=0.8)
return(1.0);
else
return MathExp(-(x-0.8)*(x-0.8)*50);
}
//+------------------------------------------------------------------+
//| Calculate distance between point and segment |
//+------------------------------------------------------------------+
double CCanvas::DistancePointSegment(const double px,const double py,const double x1,const double y1,const double x2,const double y2)
{
//--- primary calculate
double a=(px-x1)*(px-x1)+(py-y1)*(py-y1);
double b=(px-x2)*(px-x2)+(py-y2)*(py-y2);
double c=(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
//--- check
if(a>=b+c)
return (MathSqrt(b));
if(b>=a+c)
return (MathSqrt(a));
//--- calculate distance
a=MathSqrt(a);
b=MathSqrt(b);
c=MathSqrt(c);
double p=(a+b+c)/2;
double s=MathSqrt((p-a)*(p-b)*(p-c)*p);
//--- check distance
if(MathIsValidNumber(s))
return(s*2.0/c);
else
return(0);
}
//+------------------------------------------------------------------+
//| Draw smothing polyline |
//+------------------------------------------------------------------+
void CCanvas::PolylineSmooth(const int &x[],const int &y[],const uint clr,const int size,ENUM_LINE_STYLE style=STYLE_SOLID,
ENUM_LINE_END end_style=LINE_END_ROUND,double tension=0.5,double step=10)
{
//---
int arr_size= ArraySize(x);
if(arr_size!=ArraySize(y))
return;
//---
double x1,x2,y1,y2;
tension*=0.3;
//--- coordinates of Bezier curve
int xc[];
int yc[];
//--- initialize control points
double ptX[];
double ptY[];
int size_pt=arr_size*3-2;
ArrayResize(ptX,size_pt);
ArrayResize(ptY,size_pt);
//--- calculation of control points
CalcCurveBezierEndp(x[0],y[0],x[1],y[1],tension,x1,y1);
ptX[0] = x[0];
ptY[0] = y[0];
ptX[1] = x1;
ptY[1] = y1;
for(int i=0; i<arr_size-2; i++)
{
CalcCurveBezier(x,y,i,tension,x1,y1,x2,y2);
ptX[3*i+2] = x1;
ptY[3*i+2] = y1;
ptX[3*i+3] = x[i+1];
ptY[3*i+3] = y[i+1];
ptX[3*i+4] = x2;
ptY[3*i+4] = y2;
}
CalcCurveBezierEndp(x[arr_size-1],y[arr_size-1],x[arr_size-2],y[arr_size-2],tension,x1,y1);
ptX[size_pt-2] = x1;
ptY[size_pt-2] = y1;
ptX[size_pt-1] = x[arr_size-1];
ptY[size_pt-1] = y[arr_size-1];
//--- calculation of the coordinates of Bezier curves
int index=0;
for(int i=0; i<arr_size-1; i++)
{
//--- Euclidean distance between two neighboring points
double distance=MathSqrt((x[i+1]-x[i])*(x[i+1]-x[i])+(y[i+1]-y[i])*(y[i+1]-y[i]));
int size_i=(step>0.0) ?(int)(distance/step) : 1;
if(size_i<1)
size_i=2;
ArrayResize(xc,ArraySize(xc)+size_i,1024);
ArrayResize(yc,ArraySize(yc)+size_i,1024);
for(int t=0; t<size_i; t++,index++)
{
xc[index]=(int)MathRound(CalcBezierX((double)t/size_i,ptX[3*i],ptX[3*i+1],ptX[3*i+2],ptX[3*i+3]));
yc[index]=(int)MathRound(CalcBezierY((double)t/size_i,ptY[3*i],ptY[3*i+1],ptY[3*i+2],ptY[3*i+3]));
}
}
PolylineThick(xc,yc,clr,size,style,LINE_END_ROUND);
}
//+------------------------------------------------------------------+
//| Draw smothing polygone |
//+------------------------------------------------------------------+
void CCanvas::PolygonSmooth(int &x[],int &y[],const uint clr,const int size,ENUM_LINE_STYLE style=STYLE_SOLID,
ENUM_LINE_END end_style=LINE_END_ROUND,double tension=0.5,double step=10)
{
//---
int size_arr= ArraySize(x);
if(size_arr!=ArraySize(y))
return;
//---
double x1,x2,y1,y2;
tension*=0.3;
//--- coordinates of Bezier curve
int xc[];
int yc[];
//--- initialize control points
double ptX[];
double ptY[];
int size_pt=(size_arr+1)*3-3;
ArrayResize(ptX,size_pt);
ArrayResize(ptY,size_pt);
//--- calculation of control points
int xe[];
int ye[];
ArrayResize(xe,size_arr+2);
ArrayResize(ye,size_arr+2);
xe[0]=x[size_arr-1];
ye[0]=y[size_arr-1];
xe[size_arr+1] = x[0];
ye[size_arr+1] = y[0];
ArrayCopy(xe,x,1,0,size_arr);
ArrayCopy(ye,y,1,0,size_arr);
//---
for(int i=0; i<size_arr; i++)
{
CalcCurveBezier(xe,ye,i,tension,x1,y1,x2,y2);
ptX[3*i+0] = x1;
ptY[3*i+0] = y1;
ptX[3*i+1] = xe[i+1];
ptY[3*i+1] = ye[i+1];
ptX[3*i+2] = x2;
ptY[3*i+2] = y2;
}
//--- Euclidean distance between two neighboring points
int index=0;
for(int i=0; i<size_arr-1; i++)
{
double distance=MathSqrt((x[i]-x[i+1])*(x[i]-x[i+1])+(y[i]-y[i+1])*(y[i]-y[i+1]));
int size_i=(step>0.0) ?(int)(distance/step) : 1;
if(size_i<1)
size_i=2;
ArrayResize(xc,ArraySize(xc)+size_i,1024);
ArrayResize(yc,ArraySize(yc)+size_i,1024);
for(int t=0; t<size_i; t++,index++)
{
xc[index]=(int)MathRound(CalcBezierX((double)t/size_i,ptX[1+i*3],ptX[2+i*3],ptX[3+i*3],ptX[4+i*3]));
yc[index]=(int)MathRound(CalcBezierY((double)t/size_i,ptY[1+i*3],ptY[2+i*3],ptY[3+i*3],ptY[4+i*3]));
}
}
//---
double distance=MathSqrt((x[size_arr-1]-x[0])*(x[size_arr-1]-x[0])+(y[size_arr-1]-y[0])*(y[size_arr-1]-y[0]));
int size_i=(step>0.0) ?(int)(distance/step) : 1;
if(size_i<1)
size_i=2;
ArrayResize(xc,ArraySize(xc)+size_i,1024);
ArrayResize(yc,ArraySize(yc)+size_i,1024);
for(int t=0; t<size_i; t++,index++)
{
xc[index]=(int)MathRound(CalcBezierX((double)t/size_i,ptX[size_pt-2],ptX[size_pt-1],ptX[0],ptX[1]));
yc[index]=(int)MathRound(CalcBezierY((double)t/size_i,ptY[size_pt-2],ptY[size_pt-1],ptY[0],ptY[1]));
}
PolygonThick(xc,yc,clr,size,style,LINE_END_ROUND);
}
//+------------------------------------------------------------------+
//| Calculates Bezier points from cardinal spline endpoints. |
//+------------------------------------------------------------------+
void CCanvas::CalcCurveBezierEndp(const double xend,const double yend,const double xadj,const double yadj,const double tension,double &x,double &y)
{
x = (tension * (xadj - xend) + xend);
y = (tension * (yadj - yend) + yend);
}
//+------------------------------------------------------------------+
//| Calculates Bezier points from cardinal spline points |
//+------------------------------------------------------------------+
void CCanvas::CalcCurveBezier(const int &x[],const int &y[],const int i,const double tension,double &x1,double &y1,double &x2,double &y2)
{
double xdiff,ydiff;
//--- calculate tangent
xdiff = x[i+2] - x[i];
ydiff = y[i+2] - y[i];
//--- apply tangent to get control points
x1 = x[i+1] - tension * xdiff;
y1 = y[i+1] - tension * ydiff;
x2 = x[i+1] + tension * xdiff;
y2 = y[i+1] + tension * ydiff;
//---
}
//+------------------------------------------------------------------+
//| Calculate x coordinate of Bezier curve |
//+------------------------------------------------------------------+
double CCanvas::CalcBezierX(const double t,const double x0,const double x1,const double x2,const double x3)
{
return(x0*((1-t)*(1-t)*(1-t))+
x1*3*t*((1-t)*(1-t))+
x2*3*(t*t)*(1-t)+
x3*(t*t*t));
}
//+------------------------------------------------------------------+
//| Calculate y coordinate of Bezier curve |
//+------------------------------------------------------------------+
double CCanvas::CalcBezierY(const double t,const double y0,const double y1,const double y2,const double y3)
{
return(y0*((1-t)*(1-t)*(1-t))+
y1*3*t*((1-t)*(1-t))+
y2*3*(t*t)*(1-t)+
y3*(t*t*t));
}
//+------------------------------------------------------------------+
//#include <Tools\DateTime.mqh>
//+------------------------------------------------------------------+
//| DateTime.mqh |
//| Copyright 2009-2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Structure CDateTime. |
//| Purpose: Working with dates and time. |
//| Extends the MqlDateTime structure. |
//+------------------------------------------------------------------+
struct CDateTime : public MqlDateTime
{
//--- additional information
string MonthName(const int num) const;
string ShortMonthName(const int num) const;
string DayName(const int num) const;
string ShortDayName(const int num) const;
string MonthName(void) const { return(MonthName(mon)); }
string ShortMonthName(void) const { return(ShortMonthName(mon)); }
string DayName(void) const { return(DayName(day_of_week)); }
string ShortDayName(void) const { return(ShortDayName(day_of_week)); }
int DaysInMonth(void) const;
//--- data access
datetime DateTime(void) { return(StructToTime(this)); }
void DateTime(const datetime value) { TimeToStruct(value,this); }
void DateTime(const MqlDateTime& value) { this=value; }
void Date(const datetime value);
void Date(const MqlDateTime &value);
void Time(const datetime value);
void Time(const MqlDateTime &value);
//--- settings
void Sec(const int value);
void Min(const int value);
void Hour(const int value);
void Day(const int value);
void Mon(const int value);
void Year(const int value);
//--- increments
void SecDec(int delta=1);
void SecInc(int delta=1);
void MinDec(int delta=1);
void MinInc(int delta=1);
void HourDec(int delta=1);
void HourInc(int delta=1);
void DayDec(int delta=1);
void DayInc(int delta=1);
void MonDec(int delta=1);
void MonInc(int delta=1);
void YearDec(int delta=1);
void YearInc(int delta=1);
//--- check
void DayCheck(void);
};
//+------------------------------------------------------------------+
//| Gets month name |
//+------------------------------------------------------------------+
string CDateTime::MonthName(const int num) const
{
switch(num)
{
case 1: return("January");
case 2: return("February");
case 3: return("March");
case 4: return("April");
case 5: return("May");
case 6: return("June");
case 7: return("July");
case 8: return("August");
case 9: return("September");
case 10: return("October");
case 11: return("November");
case 12: return("December");
}
//---
return("Bad month");
}
//+------------------------------------------------------------------+
//| Gets short name of month |
//+------------------------------------------------------------------+
string CDateTime::ShortMonthName(const int num) const
{
switch(num)
{
case 1: return("jan");
case 2: return("feb");
case 3: return("mar");
case 4: return("apr");
case 5: return("may");
case 6: return("jun");
case 7: return("jul");
case 8: return("aug");
case 9: return("sep");
case 10: return("oct");
case 11: return("nov");
case 12: return("dec");
}
//---
return("Bad month");
}
//+------------------------------------------------------------------+
//| Gets name of week day |
//+------------------------------------------------------------------+
string CDateTime::DayName(const int num) const
{
switch(num)
{
case 0: return("Sunday");
case 1: return("Monday");
case 2: return("Tuesday");
case 3: return("Wednesday");
case 4: return("Thursday");
case 5: return("Friday");
case 6: return("Saturday");
}
//---
return("Bad day of week");
}
//+------------------------------------------------------------------+
//| Gets short name of week day |
//+------------------------------------------------------------------+
string CDateTime::ShortDayName(const int num) const
{
switch(num)
{
case 0: return("Su");
case 1: return("Mo");
case 2: return("Tu");
case 3: return("We");
case 4: return("Th");
case 5: return("Fr");
case 6: return("Sa");
}
//---
return("Bad day of week");
}
//+------------------------------------------------------------------+
//| Gets number of days in month |
//+------------------------------------------------------------------+
int CDateTime::DaysInMonth(void) const
{
int leap_year;
//---
switch(mon)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return(31);
case 2:
leap_year=year;
if(year%100==0)
leap_year/=100;
return((leap_year%4==0)? 29 : 28);
case 4:
case 6:
case 9:
case 11:
return(30);
}
//---
return(0);
}
//+------------------------------------------------------------------+
//| Sets date |
//+------------------------------------------------------------------+
void CDateTime::Date(const datetime value)
{
MqlDateTime dt;
//--- convert to structure
TimeToStruct(value,dt);
//--- set
Date(dt);
}
//+------------------------------------------------------------------+
//| Sets date |
//+------------------------------------------------------------------+
void CDateTime::Date(const MqlDateTime &value)
{
day =value.day;
mon =value.mon;
year=value.year;
//--- check if day is correct
DayCheck();
}
//+------------------------------------------------------------------+
//| Sets time |
//+------------------------------------------------------------------+
void CDateTime::Time(const datetime value)
{
MqlDateTime dt;
//--- convert to structure
TimeToStruct(value,dt);
//--- set
Time(dt);
}
//+------------------------------------------------------------------+
//| Sets time |
//+------------------------------------------------------------------+
void CDateTime::Time(const MqlDateTime &value)
{
hour=value.hour;
min =value.min;
sec =value.sec;
}
//+------------------------------------------------------------------+
//| Sets seconds |
//+------------------------------------------------------------------+
void CDateTime::Sec(const int value)
{
//--- check and set
if(value>=0 && value<60)
sec=value;
}
//+------------------------------------------------------------------+
//| Sets minutes |
//+------------------------------------------------------------------+
void CDateTime::Min(const int value)
{
//--- check and set
if(value>=0 && value<60)
min=value;
}
//+------------------------------------------------------------------+
//| Sets hours |
//+------------------------------------------------------------------+
void CDateTime::Hour(const int value)
{
//--- check and set
if(value>=0 && value<24)
hour=value;
}
//+------------------------------------------------------------------+
//| Sets day of month |
//+------------------------------------------------------------------+
void CDateTime::Day(const int value)
{
//--- check and set
if(value>0 && value<=DaysInMonth())
{
day=value;
//--- check if day is correct
DayCheck();
}
}
//+------------------------------------------------------------------+
//| Sets month |
//+------------------------------------------------------------------+
void CDateTime::Mon(const int value)
{
//--- check and set
if(value>0 && value<=12)
{
mon=value;
//--- check if day is correct
DayCheck();
}
}
//+------------------------------------------------------------------+
//| Sets year |
//+------------------------------------------------------------------+
void CDateTime::Year(const int value)
{
//--- check and set
if(value>=1970)
{
year=value;
//--- check if day is correct
DayCheck();
}
}
//+------------------------------------------------------------------+
//| Subtracts specified number of seconds |
//+------------------------------------------------------------------+
void CDateTime::SecDec(int delta)
{
//--- if increment is 0 - exit
if(delta==0)
return;
//--- if increment is negative - inverse the operation
if(delta<0)
{
SecInc(-delta);
return;
}
//--- check if subtract from upper number positions
if(delta>60)
{
MinDec(delta/60);
delta%=60;
}
sec-=delta;
if(sec<0)
{
sec+=60;
MinDec();
}
}
//+------------------------------------------------------------------+
//| Adds specified number of seconds |
//+------------------------------------------------------------------+
void CDateTime::SecInc(int delta)
{
//--- if increment is 0 - exit
if(delta==0)
return;
//--- if increment is negative - inverse the operation
if(delta<0)
{
SecDec(-delta);
return;
}
//--- check if add to upper number positions
if(delta>60)
{
MinInc(delta/60);
delta%=60;
}
sec+=delta;
if(sec>=60)
{
sec-=60;
MinInc();
}
}
//+------------------------------------------------------------------+
//| Subtracts specified number of minutes |
//+------------------------------------------------------------------+
void CDateTime::MinDec(int delta)
{
//--- if increment is 0 - exit
if(delta==0)
return;
//--- if increment is negative - inverse the operation
if(delta<0)
{
MinInc(-delta);
return;
}
//--- check if subtract from upper number positions
if(delta>60)
{
HourDec(delta/60);
delta%=60;
}
min-=delta;
if(min<0)
{
min+=60;
HourDec();
}
}
//+------------------------------------------------------------------+
//| Adds specified number of minutes |
//+------------------------------------------------------------------+
void CDateTime::MinInc(int delta)
{
//--- if increment is 0 - exit
if(delta==0)
return;
//--- if increment is negative - inverse the operation
if(delta<0)
{
MinDec(-delta);
return;
}
//--- check if add to upper number positions
if(delta>60)
{
HourInc(delta/60);
delta%=60;
}
min+=delta;
if(min>=60)
{
min-=60;
HourInc();
}
}
//+------------------------------------------------------------------+
//| Subtracts specified number of hours |
//+------------------------------------------------------------------+
void CDateTime::HourDec(int delta)
{
//--- if increment is 0 - exit
if(delta==0)
return;
//--- if increment is negative - inverse the operation
if(delta<0)
{
HourInc(-delta);
return;
}
//--- check if subtract from upper number positions
if(delta>24)
{
DayDec(delta/24);
delta%=24;
}
hour-=delta;
if(hour<0)
{
hour+=24;
DayDec();
}
}
//+------------------------------------------------------------------+
//| Adds specified number of hours |
//+------------------------------------------------------------------+
void CDateTime::HourInc(int delta)
{
//--- if increment is 0 - exit
if(delta==0)
return;
//--- if increment is negative - inverse the operation
if(delta<0)
{
HourDec(-delta);
return;
}
//--- check if add to upper number positions
if(delta>24)
{
DayInc(delta/24);
delta%=24;
}
hour+=delta;
if(hour>=24)
{
hour-=24;
DayInc();
}
}
//+------------------------------------------------------------------+
//| Subtracts specified number of days |
//+------------------------------------------------------------------+
void CDateTime::DayDec(int delta)
{
//--- if increment is 0 - exit
if(delta==0)
return;
//--- if increment is negative - inverse the operation
if(delta<0)
{
DayInc(-delta);
return;
}
//--- uncertain condition, as the number of days in month can differ
while(day<=delta)
{
delta-=day;
MonDec();
day=DaysInMonth();
}
day-=delta;
//--- check if day is correct
DayCheck();
}
//+------------------------------------------------------------------+
//| Adds specified number of days |
//+------------------------------------------------------------------+
void CDateTime::DayInc(int delta)
{
//--- if increment is 0 - exit
if(delta==0)
return;
//--- if increment is negative - inverse the operation
if(delta<0)
{
DayDec(-delta);
return;
}
//--- uncertain condition, as the number of days in month can differ
while(DaysInMonth()-day<delta)
{
delta-=DaysInMonth()-day+1;
MonInc();
day=1;
}
day+=delta;
//--- check if day is correct
DayCheck();
}
//+------------------------------------------------------------------+
//| Subtracts specified number of months |
//+------------------------------------------------------------------+
void CDateTime::MonDec(int delta)
{
//--- if increment is 0 - exit
if(delta==0)
return;
//--- if increment is negative - inverse the operation
if(delta<0)
{
MonInc(-delta);
return;
}
//--- check if subtract from upper number positions
if(delta>12)
{
YearDec(delta/12);
delta%=12;
}
mon-=delta;
if(mon<=0)
{
mon+=12;
YearDec();
}
//--- check if day is correct
DayCheck();
}
//+------------------------------------------------------------------+
//| Adds specified number of months |
//+------------------------------------------------------------------+
void CDateTime::MonInc(int delta)
{
//--- if increment is 0 - exit
if(delta==0)
return;
//--- if increment is negative - inverse the operation
if(delta<0)
{
MonDec(-delta);
return;
}
//--- check if add to upper number positions
if(delta>12)
{
YearInc(delta/12);
delta%=12;
}
mon+=delta;
if(mon>12)
{
mon-=12;
YearInc();
}
//--- check if day is correct
DayCheck();
}
//+------------------------------------------------------------------+
//| Subtracts specified number of years |
//+------------------------------------------------------------------+
void CDateTime::YearDec(int delta)
{
//--- if increment is 0 - exit
if(delta!=0)
{
year-=delta;
//--- check if day is correct
DayCheck();
}
}
//+------------------------------------------------------------------+
//| Adds specified number of years |
//+------------------------------------------------------------------+
void CDateTime::YearInc(int delta)
{
//--- if increment is 0 - exit
if(delta!=0)
{
year+=delta;
//--- check if day is correct
DayCheck();
}
}
//+------------------------------------------------------------------+
//| Checks if day number is correct |
//+------------------------------------------------------------------+
void CDateTime::DayCheck(void)
{
if(day>DaysInMonth())
day=DaysInMonth();
//--- this is required to get day of week and day of year
TimeToStruct(StructToTime(this),this);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Enumerations |
//+------------------------------------------------------------------+
//--- date modes
enum ENUM_DATE_MODES
{
DATE_MODE_MON, // month mode
DATE_MODE_YEAR // year mode
};
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
//--- Can not place the same file into resource twice
#resource "\\Include\\Controls\\res\\LeftTransp.bmp"
#resource "\\Include\\Controls\\res\\RightTransp.bmp"
//+------------------------------------------------------------------+
//| Class CDateDropList |
//| Usage: drop-down list |
//+------------------------------------------------------------------+
class CDateDropList : public CWndContainer
{
private:
//--- dependent controls
CBmpButton m_dec; // the button object
CBmpButton m_inc; // the button object
CPicture m_list; // the drop-down list object
CCanvas m_canvas; // and its canvas
//--- data
CDateTime m_value; // current value
//--- variable
ENUM_DATE_MODES m_mode; // operation mode
CRect m_click_rect[32]; // array of click sensibility areas on canvas
public:
CDateDropList(void);
~CDateDropList(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- data
datetime Value(void) { return(StructToTime(m_value)); }
void Value(datetime value) { m_value.Date(value); }
void Value(MqlDateTime& value) { m_value=value; }
//--- state
virtual bool Show(void);
protected:
//--- internal event handlers
virtual bool OnClick(void);
//--- create dependent controls
virtual bool CreateButtons(void);
virtual bool CreateList(void);
//--- draw
void DrawCanvas(void);
void DrawClickRect(const int idx,int x,int y,string text,const uint clr,uint alignment=0);
//--- handlers of the dependent controls events
virtual bool OnClickDec(void);
virtual bool OnClickInc(void);
virtual bool OnClickList(void);
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CDateDropList)
ON_EVENT(ON_CLICK,m_dec,OnClickDec)
ON_EVENT(ON_CLICK,m_inc,OnClickInc)
ON_EVENT(ON_CLICK,m_list,OnClickList)
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CDateDropList::CDateDropList(void) : m_mode(DATE_MODE_MON)
{
ZeroMemory(m_value);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CDateDropList::~CDateDropList(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CDateDropList::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- need to find dimensions depending on font size
//--- width 7 columns + 2 offsets
int w=7*(2*CONTROLS_FONT_SIZE)+2*CONTROLS_FONT_SIZE;
//--- header height + 7 rows
int h=(CONTROLS_BUTTON_SIZE+4*CONTROLS_BORDER_WIDTH)+7*(2*CONTROLS_FONT_SIZE);
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x1+w,y1+h))
return(false);
//--- create dependent controls
if(!CreateList())
return(false);
if(!CreateButtons())
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create drop-down list |
//+------------------------------------------------------------------+
bool CDateDropList::CreateList(void)
{
//--- create object
if(!m_list.Create(m_chart_id,m_name+"List",m_subwin,0,0,Width(),Height()))
return(false);
if(!Add(m_list))
return(false);
//--- create canvas
if(!m_canvas.Create(m_name,Width(),Height()))
return(false);
m_canvas.FontSet(CONTROLS_FONT_NAME,CONTROLS_FONT_SIZE*(-10));
m_list.BmpName(m_canvas.ResourceName());
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create buttons |
//+------------------------------------------------------------------+
bool CDateDropList::CreateButtons(void)
{
//--- right align button (try to make equal offsets from top and bottom)
int x1=2*CONTROLS_BORDER_WIDTH;
int y1=2*CONTROLS_BORDER_WIDTH;
int x2=x1+CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create "Dec" button
if(!m_dec.Create(m_chart_id,m_name+"Dec",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_dec.BmpNames("::Include\\Controls\\res\\LeftTransp.bmp"))
return(false);
if(!Add(m_dec))
return(false);
//---
x2=Width()-2*CONTROLS_BORDER_WIDTH;
x1=x2-CONTROLS_BUTTON_SIZE;
//--- create "Inc" button
if(!m_inc.Create(m_chart_id,m_name+"Inc",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_inc.BmpNames("::Include\\Controls\\res\\RightTransp.bmp"))
return(false);
if(!Add(m_inc))
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CDateDropList::Show(void)
{
//--- draw canvas
DrawCanvas();
//--- call method of the parent class
return(CWndContainer::Show());
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CDateDropList::OnClickDec(void)
{
switch(m_mode)
{
//--- within the month
case DATE_MODE_MON:
m_value.MonDec();
break;
//--- within the year
case DATE_MODE_YEAR:
m_value.YearDec();
break;
}
DrawCanvas();
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CDateDropList::OnClickInc(void)
{
switch(m_mode)
{
//--- within the month
case DATE_MODE_MON:
m_value.MonInc();
break;
//--- within the year
case DATE_MODE_YEAR:
m_value.YearInc();
break;
}
DrawCanvas();
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on picture |
//+------------------------------------------------------------------+
bool CDateDropList::OnClickList(void)
{
m_mouse_x=m_list.MouseX();
m_mouse_y=m_list.MouseY();
//---
OnClick();
//---
m_mouse_x=0;
m_mouse_y=0;
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Handler of the "click" event |
//+------------------------------------------------------------------+
bool CDateDropList::OnClick(void)
{
for(int i=0;i<32;i++)
{
if(m_click_rect[i].Contains(m_mouse_x,m_mouse_y))
{
if(i==0)
{
//--- clicked on the header
switch(m_mode)
{
//--- within the month
case DATE_MODE_MON:
//--- switch to the "within the year" mode
m_mode=DATE_MODE_YEAR;
DrawCanvas();
break;
//--- within the year
case DATE_MODE_YEAR:
//--- do nothing for now
break;
}
}
else
{
//--- selected
switch(m_mode)
{
//--- within the month
case DATE_MODE_MON:
m_value.Day(i);
Hide();
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
break;
//--- within the year
case DATE_MODE_YEAR:
m_value.Mon(i);
m_mode=DATE_MODE_MON;
DrawCanvas();
break;
default:
break;
}
}
break;
}
}
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Draw canvas |
//+------------------------------------------------------------------+
void CDateDropList::DrawCanvas(void)
{
int x,y;
int dx,dy;
string text;
uint text_al=TA_CENTER|TA_VCENTER;
CDateTime tmp_date;
int rows,cols;
int idx;
//--- zero out array of areas
for(int i=0;i<32;i++)
ZeroMemory(m_click_rect[i]);
//---
m_canvas.Erase(COLOR2RGB(CONTROLS_EDIT_COLOR_BG));
m_canvas.Rectangle(0,0,Width()-1,Height()-1,COLOR2RGB(CONTROLS_EDIT_COLOR_BORDER));
x=Width()/2;
y=CONTROLS_BUTTON_SIZE/2+2*CONTROLS_BORDER_WIDTH;
switch(m_mode)
{
//--- within the month
case DATE_MODE_MON:
text=m_value.MonthName()+" "+IntegerToString(m_value.year);
DrawClickRect(0,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
rows=6;
cols=7;
x=dx=Width()/(cols+1);
y+=y;
dy=(Height()-y-2*CONTROLS_BORDER_WIDTH)/(rows+1);
y+=dy/2;
for(int i=0;i<cols;i++,x+=dx)
m_canvas.TextOut(x,y,m_value.ShortDayName(i),COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
//--- backup data
tmp_date=m_value;
//--- find the beginning of the first displayed week
tmp_date.DayDec(tmp_date.day_of_week);
while(tmp_date.mon==m_value.mon && tmp_date.day!=1)
tmp_date.DayDec(cols);
//--- draw
idx=1;
y+=dy;
for(int i=0;i<rows;i++,y+=dy)
{
x=dx;
for(int j=0;j<cols;j++,x+=dx)
{
text=IntegerToString(tmp_date.day);
if(tmp_date.mon==m_value.mon)
{
if(tmp_date.day==m_value.day)
m_canvas.FillRectangle(x-dx/2,y-dy/2,x+dx/2,y+dy/2,COLOR2RGB(CONTROLS_COLOR_BG_SEL));
DrawClickRect(idx++,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
}
else
m_canvas.TextOut(x,y,text,COLOR2RGB(CONTROLS_BUTTON_COLOR_BORDER),text_al);
tmp_date.DayInc();
}
}
break;
//--- within the year
case DATE_MODE_YEAR:
text=IntegerToString(m_value.year);
DrawClickRect(0,x,y,text,COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
rows=3;
cols=4;
x=dx=Width()/(cols+1);
y+=y;
dy=(Height()-y)/rows;
y+=dy/2;
for(int i=0;i<rows*cols;i++)
{
if(i+1==m_value.mon)
m_canvas.FillRectangle(x-dx/2,y-dy/4,x+dx/2,y+dy/4,COLOR2RGB(CONTROLS_COLOR_BG_SEL));
DrawClickRect(i+1,x,y,m_value.ShortMonthName(i+1),COLOR2RGB(CONTROLS_EDIT_COLOR),text_al);
if(i%cols==cols-1)
{
x=dx;
y+=dy;
}
else
x+=dx;
}
break;
default:
break;
}
m_canvas.Update();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CDateDropList::DrawClickRect(const int idx,int x,int y,string text,const uint clr,uint alignment)
{
int text_w,text_h;
//--- display the text
m_canvas.TextOut(x,y,text,clr,alignment);
//--- determine area occupied by text
m_canvas.TextSize(text,text_w,text_h);
//--- convert relative coordinated to absolute ones
x+=Left();
y+=Top();
//--- check flags of horizontal alignment
switch(alignment&(TA_LEFT|TA_CENTER|TA_RIGHT))
{
case TA_LEFT:
m_click_rect[idx].left=x;
break;
case TA_CENTER:
m_click_rect[idx].left=x-text_w/2;
break;
case TA_RIGHT:
m_click_rect[idx].left=x-text_w;
break;
}
m_click_rect[idx].Width(text_w);
//--- check flags of vertical alignment
switch(alignment&(TA_TOP|TA_VCENTER|TA_BOTTOM))
{
case TA_TOP:
m_click_rect[idx].top=y;
break;
case TA_VCENTER:
m_click_rect[idx].top=y-text_h/2;
break;
case TA_BOTTOM:
m_click_rect[idx].top=y-text_h;
break;
}
m_click_rect[idx].Height(text_h);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
//--- Can not place the same file into resource twice
#resource "\\Include\\Controls\\res\\DateDropOn.bmp" // image file
#resource "\\Include\\Controls\\res\\DateDropOff.bmp" // image file
//+------------------------------------------------------------------+
//| Class CDatePicker |
//| Usage: date picker |
//+------------------------------------------------------------------+
class CDatePicker : public CWndContainer
{
protected:
//--- dependent controls
CEdit m_edit; // the entry field object
CBmpButton m_drop; // the button object
CDateDropList m_list; // the drop-down list object
//--- data
datetime m_value; // current value
public:
CDatePicker(void);
~CDatePicker(void);
//--- create
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- chart event handler
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- data
datetime Value(void) const { return(m_value); }
void Value(datetime value) { m_edit.Text(TimeToString(m_value=value,TIME_DATE)); }
//--- state
virtual bool Show(void);
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
protected:
//--- create dependent controls
virtual bool CreateEdit(void);
virtual bool CreateButton(void);
virtual bool CreateList(void);
//--- handlers of the dependent controls events
virtual bool OnClickEdit(void);
virtual bool OnClickButton(void);
virtual bool OnChangeList(void);
//--- show drop-down list
bool ListShow(void);
bool ListHide(void);
void CheckListHide(const int id,int x,int y);
virtual bool OnResize(void) override;
};
//+------------------------------------------------------------------+
//| Common handler of chart events |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CDatePicker)
ON_EVENT(ON_CLICK,m_edit,OnClickEdit)
ON_EVENT(ON_CLICK,m_drop,OnClickButton)
ON_EVENT(ON_CHANGE,m_list,OnChangeList)
CheckListHide(id,(int)lparam,(int)dparam);
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
EVENT_MAP_END(CWndContainer)
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CDatePicker::CDatePicker(void) : m_value(0)
{
RTTI;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CDatePicker::~CDatePicker(void)
{
}
//+------------------------------------------------------------------+
//| Create a control |
//+------------------------------------------------------------------+
bool CDatePicker::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
//--- call method of the parent class
if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- create dependent controls
if(!CreateEdit())
return(false);
if(!CreateButton())
return(false);
if(!CreateList())
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create main entry field |
//+------------------------------------------------------------------+
bool CDatePicker::CreateEdit(void)
{
//--- create
if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,0,0,Width(),Height()))
return(false);
if(!m_edit.Text(""))
return(false);
if(!m_edit.ReadOnly(true))
return(false);
if(!Add(m_edit))
return(false);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create button |
//+------------------------------------------------------------------+
bool CDatePicker::CreateButton(void)
{
//--- right align button (try to make equal offsets from top and bottom)
int x1=Width()-(2*CONTROLS_BUTTON_SIZE+CONTROLS_COMBO_BUTTON_X_OFF);
int y1=(Height()-CONTROLS_BUTTON_SIZE)/2;
int x2=x1+2*CONTROLS_BUTTON_SIZE;
int y2=y1+CONTROLS_BUTTON_SIZE;
//--- create
if(!m_drop.Create(m_chart_id,m_name+"Drop",m_subwin,x1,y1,x2,y2))
return(false);
if(!m_drop.BmpNames("::Include\\Controls\\res\\DateDropOff.bmp","::Include\\Controls\\res\\DateDropOn.bmp"))
return(false);
if(!Add(m_drop))
return(false);
m_drop.Locking(true);
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Create drop-down list |
//+------------------------------------------------------------------+
bool CDatePicker::CreateList(void)
{
//--- create
if(!m_list.Create(m_chart_id,m_name+"List",m_subwin,0,Height()-1,Width(),0))
return(false);
if(!Add(m_list))
return(false);
m_list.Hide();
//--- succeeded
return(true);
}
//+------------------------------------------------------------------+
//| Makes the control visible |
//+------------------------------------------------------------------+
bool CDatePicker::Show(void)
{
m_edit.Show();
m_drop.Show();
m_list.Hide();
//--- call method of the parent class
return(CWnd::Show());
}
//+------------------------------------------------------------------+
//| save |
//+------------------------------------------------------------------+
bool CDatePicker::Save(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//--- write
FileWriteLong(file_handle,Value());
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| load |
//+------------------------------------------------------------------+
bool CDatePicker::Load(const int file_handle)
{
//--- check
if(file_handle==INVALID_HANDLE)
return(false);
//--- load
if(!FileIsEnding(file_handle))
Value(FileReadLong(file_handle));
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Handler of click on main entry field |
//+------------------------------------------------------------------+
bool CDatePicker::OnClickEdit(void)
{
//--- change button state
if(!m_drop.Pressed(!m_drop.Pressed()))
return(false);
//--- call the click on button handler
return(OnClickButton());
}
//+------------------------------------------------------------------+
//| Handler of click on button |
//+------------------------------------------------------------------+
bool CDatePicker::OnClickButton(void)
{
BringToTop();
// show or hide the drop-down list depending on the button state
return((m_drop.Pressed()) ? ListShow():ListHide());
}
//+------------------------------------------------------------------+
//| Handler of change on drop-down list |
//+------------------------------------------------------------------+
bool CDatePicker::OnChangeList(void)
{
string text=TimeToString(m_value=m_list.Value(),TIME_DATE);
//--- hide the list, depress the button
ListHide();
m_drop.Pressed(false);
//--- set text in the main entry field
m_edit.Text(text);
//--- send notification
EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name);
//--- handled
return(true);
}
//+------------------------------------------------------------------+
//| Show the drop-down list |
//+------------------------------------------------------------------+
bool CDatePicker::ListShow(void)
{
//--- set value
m_list.Value(m_value);
//--- show the list
return(m_list.Show());
}
//+------------------------------------------------------------------+
//| Hide drop-down list |
//+------------------------------------------------------------------+
bool CDatePicker::ListHide(void)
{
//--- hide the list
return(m_list.Hide());
}
//+------------------------------------------------------------------+
//| Hide the drop-down element if necessary |
//+------------------------------------------------------------------+
void CDatePicker::CheckListHide(const int id,int x,int y)
{
//--- check event ID
if(id!=CHARTEVENT_CLICK)
return;
//--- check visibility of the drop-down element
if(!m_list.IsVisible())
return;
//--- check mouse cursor's position
y-=(int)ChartGetInteger(m_chart_id,CHART_WINDOW_YDISTANCE,m_subwin);
if(!m_edit.Contains(x,y) && !m_list.Contains(x,y))
{
m_drop.Pressed(false);
m_list.Hide();
}
}
//+------------------------------------------------------------------+
//| Resize internal objects |
//+------------------------------------------------------------------+
bool CDatePicker::OnResize(void) override
{
m_edit.Width(Width());
m_edit.Height(Height());
int x1 = Width() - (2 * CONTROLS_BUTTON_SIZE + CONTROLS_COMBO_BUTTON_X_OFF);
int y1 = (Height() - CONTROLS_BUTTON_SIZE) / 2;
m_drop.Move(Left() + x1, Top() + y1);
m_list.Move(Right() - m_list.Width(), Bottom());
return CWndContainer::OnResize();
}
//#include <ControlsPlus/CheckBox.mqh>
//#include <ControlsPlus/RadioButton.mqh>
//#include "Box.mqh"
//#include "Grid.mqh"
//+------------------------------------------------------------------+
//| 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()
{
RTTI;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CGrid::CGrid(int rows, int cols, int hgap = 0, int vgap = 0)
{
Init(rows, cols, hgap, vgap);
RTTI;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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);
CBox *container = dynamic_cast<CBox *>(control);
//if(control.Type() == CLASS_LAYOUT)
if(container)
{
container.Pack();
}
cnt++;
}
return (true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CGrid::CheckControlSize(CWnd *control)
{
control.Size(m_cell_size.cx, m_cell_size.cy);
}
//+------------------------------------------------------------------+
//#include "Layout.mqh"
//+------------------------------------------------------------------+
//| Layout.mqh |
//| Copyright (c) 2020, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//| GUI Layout declarative language |
//| https://www.mql5.com/ru/articles/7734/ |
//| https://www.mql5.com/ru/articles/7795/ |
//+------------------------------------------------------------------+
//#include <Marketeer/RubbArray.mqh>
//+------------------------------------------------------------------+
//| RubbArray.mqh |
//| Copyright (c) 2019, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//| https://www.mql5.com/ru/articles/5638 |
//+------------------------------------------------------------------+
template <typename T>
interface Clonable
{
T clone();
};
template <typename T>
class BaseArray
{
protected:
T data[];
public:
virtual ~BaseArray()
{
clear();
}
virtual void clear()
{
ArrayResize(data, 0);
}
T operator[](int i) const
{
return get(i);
}
T get(int i) const
{
if(i < 0 || i >= ArraySize(data))
{
Print("Array size=", ArraySize(data), ", index=", i);
return NULL;
}
return data[i];
}
T top() const
{
if(ArraySize(data) == 0)
{
Print("Array size=0");
return NULL;
}
return data[ArraySize(data) - 1];
}
T peek() const
{
return top();
}
BaseArray *add(T d)
{
int n = ArraySize(data);
ArrayResize(data, n + 1);
data[n] = d;
return &this;
}
BaseArray *operator<<(T d)
{
return add(d);
}
BaseArray *operator<<(const BaseArray<T> *x)
{
for(int i = 0; i < x.size(); i++)
{
Clonable<T> *clone = dynamic_cast<Clonable<T> *>(x[i]);
if(clone != NULL)
{
add(clone.clone());
}
else
{
add(x[i]);
}
}
return &this;
}
BaseArray *push(T d)
{
return add(d);
}
void operator=(const BaseArray &d)
{
int i, n = d.size();
ArrayResize(data, n);
for(i = 0; i < n; i++)
{
data[i] = d[i];
}
}
T operator>>(int i)
{
T d = this[i];
if(d == NULL) return NULL;
int n = ArraySize(data) - 1;
if(i < n)
{
ArrayCopy(data, data, i, i + 1);
}
ArrayResize(data, n);
return d;
}
T pop()
{
int _size = ArraySize(data) - 1;
T d = this[_size];
ArrayResize(data, _size);
return d;
}
int size() const
{
return ArraySize(data);
}
string toString() const
{
static string formats[4][2] = {{"double", "%f"}, {"long", "%i"}, {"string", "%s"}, {"int", "%i"}};
string fmt = "%x";
for(int k = 0; k < ArrayRange(formats, 0); k++)
{
if(typename(T) == formats[k][0])
{
fmt = formats[k][1];
break;
}
}
int i, n = ArraySize(data);
string s;
for(i = 0; i < n; i++)
{
s += StringFormat(fmt, data[i]) + ",";
}
return (s);
}
};
template <typename T>
class RubbArray: public BaseArray<T>
{
public:
RubbArray()
{
}
~RubbArray()
{
clear();
}
virtual void clear() override
{
int i, n = ArraySize(data);
for(i = 0; i < n; i++)
{
if(CheckPointer(data[i]) == POINTER_DYNAMIC) delete data[i];
}
ArrayResize(data, 0);
}
T replace(const int i, T v)
{
int n = ArraySize(data);
if(i < n)
{
if(CheckPointer(data[i]) == POINTER_DYNAMIC) delete data[i];
data[i] = v;
}
return v;
}
};
#define List RubbArray
#define Stack RubbArray
//#include "Generators.mqh"
template<typename T>
class Generator
{
public:
virtual T operator++() = 0;
};
template<typename T>
class ItemGenerator
{
public:
virtual bool addItemTo(T *object) = 0;
};
template<typename T>
class SequenceGenerator: public Generator<T>
{
protected:
T current;
int max;
int count;
public:
SequenceGenerator(const T start = NULL, const int _max = 0): current(start), max(_max), count(0) {}
virtual void reset(const T start, const int _max = 0)
{
current = start;
count = 0;
max = _max;
}
virtual T operator++() = 0;
};
template<typename T>
class SimpleSequenceGenerator: public SequenceGenerator<T>
{
public:
SimpleSequenceGenerator(const T start = NULL, const int _max = 0): SequenceGenerator(start, _max) {}
virtual T operator++() override
{
ulong ul = (ulong)current;
ul++;
count++;
if(count > max) return NULL;
current = (T)ul;
return current;
}
};
union PackedRect
{
const ulong compound;
const ushort parts[4];
PackedRect(const ulong value): compound(value) {}
PackedRect(const ushort left, const ushort top, const ushort right, const ushort bottom): compound(left | ((ulong)top << 16) | ((ulong)right << 32) | ((ulong)bottom << 48)) {}
PackedRect(const CRect &r): compound(r.left | ((ulong)r.top << 16) | ((ulong)r.right << 32) | ((ulong)r.bottom << 48)) {}
};
template<typename T>
class ControlProperties
{
protected:
T *object;
string context;
public:
ControlProperties(): object(NULL), context(NULL) {}
ControlProperties(T *ptr): object(ptr), context(NULL) {}
void assign(T *ptr) { object = ptr; }
T *get(void) { return object; }
virtual ControlProperties<T> *operator[](const string property) { context = property; StringToLower(context); return &this; };
virtual T *operator<=(const bool b) = 0;
virtual T *operator<=(const ENUM_ALIGN_MODE align) = 0;
virtual T *operator<=(const color c) = 0;
virtual T *operator<=(const string s) = 0;
virtual T *operator<=(const int i) = 0;
virtual T *operator<=(const long l) = 0;
virtual T *operator<=(const double d) = 0;
virtual T *operator<=(const float f) = 0;
virtual T *operator<=(const datetime d) = 0;
virtual T *operator<=(const PackedRect &r) = 0;
// TODO: ushort for margins?
};
class LayoutData
{
protected:
static RubbArray<LayoutData *> stack;
static string rootId;
int _x1, _y1, _x2, _y2;
string _id;
public:
LayoutData()
{
_x1 = _y1 = _x2 = _y2 = 0;
_id = NULL;
}
};
enum STYLER_PHASE
{
STYLE_PHASE_BEFORE_INIT,
STYLE_PHASE_AFTER_INIT
};
template<typename C>
class LayoutStyleable
{
public:
virtual void apply(C *control, const STYLER_PHASE phase) {};
};
template<typename C>
class LayoutCache
{
protected:
C *cache[]; // autocreated controls and boxes
public:
~LayoutCache()
{
for(int i = 0; i < ArraySize(cache); i++)
{
if(CheckPointer(cache[i]) == POINTER_DYNAMIC) delete cache[i];
}
}
virtual LayoutStyleable<C> *getStyler() const
{
return NULL;
}
virtual void save(C *control)
{
const int n = ArraySize(cache);
ArrayResize(cache, n + 1);
cache[n] = control;
}
virtual C *get(const string name) = 0;
virtual C *get(const long m)
{
if(m < 0 || m >= ArraySize(cache)) return NULL;
return cache[(int)m];
}
virtual bool find(C *control, const int excludeLast = 0) const
{
for(int i = 0; i < ArraySize(cache) - excludeLast; i++) // excluding just added (latest element)
{
if(cache[i] == control)
{
return true;
}
}
return false;
}
virtual int indexOf(C *control)
{
for(int i = 0; i < ArraySize(cache); i++)
{
if(cache[i] == control)
{
return i;
}
}
return -1;
}
virtual C *findParent(C *control) const = 0;
virtual bool revoke(C *control) = 0;
virtual int cacheSize()
{
return ArraySize(cache);
}
virtual bool onEvent(const int event, C *control)
{
return false;
}
};
template<typename P,typename C>
class LayoutBase: public LayoutData
{
protected:
P *container; // not null if container (can be used as flag)
C *object;
C *array[];
int shadow; // set to 1 during creation (when last cached object not yet registered)
static LayoutCache<C> *cacher;
public:
LayoutBase(): container(NULL), object(NULL), shadow(0) {}
C *get()
{
return object;
}
C *operator[](const int i = 0) const
{
if(object != NULL) return object;
if(i < 0 || i >= ArraySize(array)) return NULL;
return array[i];
}
int size() const
{
return ArraySize(array);
}
static void setCache(LayoutCache<C> *c)
{
cacher = c;
}
protected:
virtual bool setContainer(C *control) = 0;
virtual string create(C *object, const string id = NULL) = 0;
virtual void add(C *object) = 0;
virtual string getRootId(const string id) = 0;
virtual bool save(C *control)
{
if(cacher == NULL)
{
Print("Before first implicit layout object created please assign a LayoutCache storage");
return false;
}
cacher.save(control);
return true;
}
// nonbound layout, control T is implicitly stored in internal cache
template<typename T>
T *init(const string name, const int m = 1, const int x1 = 0, const int y1 = 0, const int x2 = 0, const int y2 = 0)
{
if(m > 1)
{
ArrayResize(array, m);
object = NULL;
container = NULL;
}
T *temp = NULL;
for(int i = 0; i < m; i++)
{
temp = new T();
if(save(temp))
{
if(m > 1) array[i] = temp;
shadow = 1;
init(temp, name + (m > 1 ? (string)(i + 1) : ""), x1, y1, x2, y2);
shadow = 0;
}
else return NULL;
}
return temp;
}
// bound layout, with explicit control object passed as reference/pointer
template<typename T>
void init(T *ref, const string id = NULL, const int x1 = 0, const int y1 = 0, const int x2 = 0, const int y2 = 0)
{
if(ArraySize(array) == 0)
{
setContainer(ref);
object = ref;
}
_x1 = x1;
_y1 = y1;
_x2 = x2;
_y2 = y2;
if(stack.size() > 0)
{
if(_x1 == 0 && _y1 == 0 && _x2 == 0 && _y2 == 0)
{
_x1 = stack.top()._x1;
_y1 = stack.top()._y1;
_x2 = stack.top()._x2;
_y2 = stack.top()._y2;
}
_id = rootId + (id == NULL ? typename(T) + StringFormat("%d", ref) : id);
}
else
{
_id = (id == NULL ? typename(T) + StringFormat("%d", ref) : id);
}
bool existing = false;
if(cacher != NULL && cacher.find(ref, shadow))
{
// this object exists in the cache, no need to create again
// can be a dynamic modification of the dialog
existing = true;
}
// FIXME: this is a hack because rootId behaviour is implementation specific for standard library
// this 'if' is used for the case, when a blank form was created on start
// (it's not in the cache since it's automatic (it's a rule so far)), and then
// new elements are added ad-hoc, so the form re-creation should be skipped,
// but it's needed on the stack
else if(rootId == _id) // the dialog already created
{
existing = true;
}
else // normal workflow branch
{
_id = create(ref);
}
if(stack.size() == 0)
{
rootId = getRootId(_id);
}
if(container)
{
stack << &this;
}
if(cacher != NULL && !existing)
{
LayoutStyleable<C> *styler = cacher.getStyler();
if(styler != NULL)
{
styler.apply(ref, STYLE_PHASE_BEFORE_INIT);
}
}
if(ArraySize(array) > 0)
{
LayoutBase *up = stack.size() > 0 ? stack.top() : NULL;
if(up != NULL && up.container != NULL)
{
up.add(ref);
}
}
}
// array of explicitly defined controls of type T, bound to the single layout object
// only simple controls (not containers) are allowed to init via arrays
template<typename T>
void init(T &refs[], const string id = NULL, const int x1 = 0, const int y1 = 0, const int x2 = 0, const int y2 = 0)
{
object = NULL;
container = NULL;
_x1 = x1;
_y1 = y1;
_x2 = x2;
_y2 = y2;
if(stack.size() > 0)
{
if(_x1 == 0 && _y1 == 0 && _x2 == 0 && _y2 == 0)
{
_x1 = stack.top()._x1;
_y1 = stack.top()._y1;
_x2 = stack.top()._x2;
_y2 = stack.top()._y2;
}
_id = rootId + (id == NULL ? typename(T) + StringFormat("%d", &refs[0]) : id) + "_";
}
else
{
_id = (id == NULL ? typename(T) + StringFormat("%d", &refs[0]) : id) + "_";
}
LayoutStyleable<C> *styler = cacher != NULL ? cacher.getStyler() : NULL;
int size = ArraySize(refs);
ArrayResize(array, size);
LayoutBase *up = stack.size() > 0 ? stack.top() : NULL;
for(int i = 0; i < size; i++)
{
create(&refs[i], _id + (string)(i + 1));
if(styler != NULL)
{
styler.apply(&refs[i], STYLE_PHASE_BEFORE_INIT);
}
if(up != NULL && up.container != NULL)
{
up.add(&refs[i]);
}
array[i] = &refs[i];
}
}
~LayoutBase()
{
if(container)
{
stack.pop();
}
if(object)
{
// FIXME: should not call styler for "old" objects
if(cacher != NULL)
{
LayoutStyleable<C> *styler = cacher.getStyler();
if(styler != NULL)
{
styler.apply(object, STYLE_PHASE_AFTER_INIT);
}
}
LayoutBase *up = stack.size() > 0 ? stack.top() : NULL;
if(up != NULL && up.container != NULL)
{
up.add(object);
}
}
if(ArraySize(array) > 0 && cacher != NULL)
{
LayoutStyleable<C> *styler = cacher.getStyler();
for(int i = 0; i < ArraySize(array); i++)
{
styler.apply(array[i], STYLE_PHASE_AFTER_INIT);
}
}
if(stack.size() == 0 && cacher != NULL)
{
cacher = NULL;
}
}
template<typename V>
LayoutBase<P,C> *operator<=(const V value) // template function cannot be virtual
{
Print("Please, override " , __FUNCSIG__, " in your concrete Layout class");
return &this;
}
virtual LayoutBase<P,C> *operator<=(const PackedRect &r) // optional
{
Print("Please, override " , __FUNCSIG__, " in your concrete Layout class");
return &this;
}
virtual LayoutBase<P,C> *operator[](const string prop) // optional
{
Print("Please, override " , __FUNCSIG__, " in your concrete Layout class");
return &this;
}
};
template<typename P,typename C>
static LayoutCache<C> *LayoutBase::cacher = NULL;
static RubbArray<LayoutData *> LayoutData::stack;
static string LayoutData::rootId;
template<typename T>
class StdControlProperties: public ControlProperties<T>
{
public:
StdControlProperties(): ControlProperties() {}
StdControlProperties(T *ptr): ControlProperties(ptr) {}
// we need dynamic_cast throughout below, because control classes
// in the standard library does not provide a set of common virtual methods
// to assign specific properties for all of them (for example, readonly
// is available for edit field only)
virtual T *operator<=(const bool b) override
{
if(StringFind(context, "enable") > -1)
{
if(b) object.Enable();
else object.Disable();
}
else
if(StringFind(context, "visible") > -1)
{
object.Visible(b);
}
else
{
CEdit *edit = dynamic_cast<CEdit *>(object);
if(edit != NULL) edit.ReadOnly(b);
CButton *button = dynamic_cast<CButton *>(object);
if(button != NULL) button.Locking(b);
}
return object;
}
virtual T *operator<=(const ENUM_ALIGN_MODE align) override
{
CEdit *edit = dynamic_cast<CEdit *>(object);
if(edit != NULL) edit.TextAlign(align);
return object;
}
virtual T *operator<=(const color c) override
{
CWndObj *ctrl = dynamic_cast<CWndObj *>(object);
if(ctrl != NULL)
{
if(StringFind(context, "background") > -1)
{
ctrl.ColorBackground(c);
}
else if(StringFind(context, "border") > -1)
{
ctrl.ColorBorder(c);
}
else // default
{
ctrl.Color(c);
}
}
else
{
CWndClient *client = dynamic_cast<CWndClient *>(object);
if(client != NULL)
{
if(StringFind(context, "border") > -1)
{
client.ColorBorder(c);
}
else
{
client.ColorBackground(c);
}
}
}
return object;
}
virtual T *operator<=(const string s) override
{
CWndObj *ctrl = dynamic_cast<CWndObj *>(object);
if(ctrl != NULL)
{
if(StringFind(context, "font") > -1)
{
ctrl.Font(s);
}
else // default
{
ctrl.Text(s);
}
}
else
{
CCheckBox *check = dynamic_cast<CCheckBox *>(object);
if(check != NULL) check.Text(s);
else
{
CRadioButton *radio = dynamic_cast<CRadioButton *>(object);
if(radio != NULL) radio.Text(s);
}
}
return object;
}
virtual T *operator<=(const int i) override
{
if(StringFind(context, "width") > -1)
{
object.Width(i);
}
else
if(StringFind(context, "height") > -1)
{
object.Height(i);
}
else
if(StringFind(context, "margin") > -1)
{
object.Margins(i, i, i, i);
}
else
if(StringFind(context, "left") > -1)
{
CRect r = object.Margins();
object.Margins(i, r.top, r.right, r.bottom);
}
else
if(StringFind(context, "top") > -1)
{
CRect r = object.Margins();
object.Margins(r.left, i, r.right, r.bottom);
}
else
if(StringFind(context, "right") > -1)
{
CRect r = object.Margins();
object.Margins(r.left, r.top, i, r.bottom);
}
else
if(StringFind(context, "bottom") > -1)
{
CRect r = object.Margins();
object.Margins(r.left, r.top, r.right, i);
}
else
if(StringFind(context, "align") > -1)
{
object.Alignment(i);
}
else
if(StringFind(context, "fontsize") > -1)
{
CWndObj *ctrl = dynamic_cast<CWndObj *>(object);
if(ctrl != NULL)
{
ctrl.FontSize(i);
}
}
else // default
{
CSpinEdit *spin = dynamic_cast<CSpinEdit *>(object);
if(spin != NULL)
{
if(StringFind(context, "min") > -1)
{
spin.MinValue(i);
}
else
if(StringFind(context, "max") > -1)
{
spin.MaxValue(i);
}
else
{
spin.Value(i);
}
}
else
{
CComboBox *combo = dynamic_cast<CComboBox *>(object);
if(combo != NULL)
{
combo.Select(i);
}
}
}
return object;
}
virtual T *operator<=(const datetime d) override
{
CDatePicker *date = dynamic_cast<CDatePicker *>(object);
if(date != NULL)
{
date.Value(d);
}
return object;
}
virtual T *operator<=(const long l) override
{
if(StringFind(context, "zorder") > -1)
{
CWndObj *ctrl = dynamic_cast<CWndObj *>(object);
if(ctrl != NULL)
{
ctrl.ZOrder(l);
}
}
else
{
object.Id(l);
}
return object;
}
virtual T *operator<=(const float f) override
{
const int margin = (int)f;
CGrid *grid = dynamic_cast<CGrid *>(object);
if(grid != NULL)
{
if(StringFind(context, "left") > -1
|| StringFind(context, "right") > -1)
{
grid.HGap(margin);
}
else
if(StringFind(context, "top") > -1
|| StringFind(context, "bottom") > -1)
{
grid.VGap(margin);
}
else
{
grid.HGap(margin);
grid.VGap(margin);
}
}
else
{
CBox *box = dynamic_cast<CBox *>(object);
if(box != NULL)
{
if(StringFind(context, "left") > -1)
{
box.PaddingLeft(margin);
}
else
if(StringFind(context, "top") > -1)
{
box.PaddingTop(margin);
}
else
if(StringFind(context, "right") > -1)
{
box.PaddingRight(margin);
}
else
if(StringFind(context, "bottom") > -1)
{
box.PaddingBottom(margin);
}
else
{
// wrap this container's content with padding
// (don't use it side by side with standard alignment!)
box.Padding(margin, margin, margin, margin);
}
}
}
return object;
}
virtual T *operator<=(const double d) override
{
const int margin = (int)d;
// align this control inside its container
object.Margins(margin, margin, margin, margin);
return object;
}
virtual T *operator<=(const PackedRect &r) override
{
object.Margins(r.parts[0], r.parts[1], r.parts[2], r.parts[3]);
return object;
}
virtual T *operator<=(const ENUM_WND_ALIGN_FLAGS align)
{
object.Alignment(align);
return object;
}
virtual T *operator<=(const LAYOUT_STYLE style)
{
CBox *box = dynamic_cast<CBox *>(object);
if(box != NULL)
{
box.LayoutStyle(style);
}
return object;
}
virtual T *operator<=(const VERTICAL_ALIGN v)
{
CBox *box = dynamic_cast<CBox *>(object);
if(box != NULL)
{
box.VerticalAlign(v);
}
return object;
}
virtual T *operator<=(const HORIZONTAL_ALIGN h)
{
CBox *box = dynamic_cast<CBox *>(object);
if(box != NULL)
{
box.HorizontalAlign(h);
}
return object;
}
};
class StdLayoutStyleable: public LayoutStyleable<CWnd>
{
public:
virtual void apply(CWnd *control, const STYLER_PHASE phase) = 0;
};
// CWnd implementation specific
class StdLayoutCache: public LayoutCache<CWnd>
{
protected:
public:
static bool StringEndsWith(const string text, const string suffix)
{
if(StringLen(text) == 0) return StringLen(suffix) == 0;
const int pos = StringFind(text, suffix);
return pos == 5 && pos == StringLen(text) - StringLen(suffix); // this relies on 5-digit instance id!
}
virtual CWnd *get(const string name) override
{
const int n = ArraySize(cache);
for(int i = 0; i < n; i++)
{
if(StringEndsWith(cache[i].Name(), name)) return cache[i];
}
return NULL;
}
virtual CWnd *get(const long m) override
{
if(m < 0)
{
for(int i = 0; i < ArraySize(cache); i++)
{
if(cache[i].Id() == -m) return cache[i];
CWndContainer *container = dynamic_cast<CWndContainer *>(cache[i]);
if(container != NULL)
{
for(int j = 0; j < container.ControlsTotal(); j++)
{
if(container.Control(j).Id() == -m) return container.Control(j);
}
}
}
return NULL;
}
else if(m >= ArraySize(cache)) return NULL;
return cache[(int)m];
}
virtual CWnd *findParent(CWnd *control) const override
{
for(int i = 0; i < ArraySize(cache); i++)
{
CWndContainer *container = dynamic_cast<CWndContainer *>(cache[i]);
if(container != NULL)
{
for(int j = 0; j < container.ControlsTotal(); j++)
{
if(container.Control(j) == control)
{
return container;
}
}
}
}
return NULL;
}
virtual bool revoke(CWnd *control) override
{
static CWnd dummy;
for(int i = 0; i < ArraySize(cache); i++)
{
if(cache[i] == control)
{
CWndContainer *container = dynamic_cast<CWndContainer *>(control);
if(container != NULL)
{
for(int j = 0; j < container.ControlsTotal(); j++)
{
revoke(container.Control(j));
}
}
// do not delete objects here, since they belong to their respective
// parent controls/windows and are deleted from there
// if(CheckPointer(control) == POINTER_DYNAMIC) delete control;
cache[i] = &dummy;
return true;
}
}
return false;
}
void print()
{
for(int i = 0; i < ArraySize(cache); i++)
{
CWnd *wnd = cache[i];
Print(wnd._rtti, " / ", wnd.Name(), " ", wnd.Id(), " F:", wnd.StateFlags());
}
}
};
class StdLayoutBase: public LayoutBase<CWndContainer,CWnd>
{
public:
virtual string getRootId(const string id) override
{
return StringSubstr(id, 0, 5);
}
virtual bool setContainer(CWnd *control) override
{
CDialog *dialog = dynamic_cast<CDialog *>(control);
CBox *box = dynamic_cast<CBox *>(control);
if(dialog != NULL)
{
container = dialog;
}
else if(box != NULL)
{
container = box;
}
return true;
}
virtual string create(CWnd *child, const string id = NULL) override
{
child.Create(ChartID(), id != NULL ? id : _id, 0, _x1, _y1, _x2, _y2);
if(cacher != NULL)
{
child.Id(cacher.cacheSize() - 1);
}
return child.Name();
}
virtual void add(CWnd *child) override
{
CDialog *dlg = dynamic_cast<CDialog *>(container);
if(dlg != NULL)
{
dlg.Add(child);
}
else
{
CWndContainer *ptr = dynamic_cast<CWndContainer *>(container);
if(ptr != NULL)
{
ptr.Add(child);
}
else
{
Print("Can't add ", child.Name(), " to ", container.Name());
}
}
}
~StdLayoutBase()
{
}
};
template<typename T>
class _layout: public StdLayoutBase
{
protected:
StdControlProperties<T> wrapper;
public:
_layout(const string id)
{
T *ptr = init<T>(id);
wrapper.assign(ptr);
wrapper <= id;
}
_layout(const string id, const int n)
{
T *ptr = init<T>(id, n, 0, 0, 0, 0);
}
_layout(const string id, const int dx, const int dy)
{
T *ptr = init<T>(id, 1, 0, 0, dx, dy);
wrapper.assign(ptr);
wrapper <= id;
}
_layout(const string id, const int x1, const int y1, const int x2, const int y2)
{
T *ptr = init<T>(id, 1, x1, y1, x2, y2);
wrapper.assign(ptr);
wrapper <= id;
}
template<typename V>
_layout(const string id, const int dx, const int dy, const V value)
{
T *ptr = init<T>(id, 1, 0, 0, dx, dy);
wrapper.assign(ptr);
wrapper <= value;
}
_layout(T &ref, const string id = NULL)
{
init(&ref, id, 0, 0, 0, 0);
wrapper.assign(&ref);
if(id != NULL) wrapper <= id;
}
_layout(T *ptr, const string id = NULL)
{
init(ptr, id, 0, 0, 0, 0);
wrapper.assign(ptr);
if(id != NULL) wrapper <= id;
}
template<typename V>
_layout(T &ref, const string id, const int dx, const int dy, const V value)
{
init(&ref, id, 0, 0, dx, dy);
wrapper.assign(&ref);
wrapper <= value;
}
_layout(T &ref, const string id, const int dx, const int dy)
{
init(&ref, id, 0, 0, dx, dy);
wrapper.assign(&ref);
wrapper <= id;
}
_layout(T *ptr, const string id, const int dx, const int dy)
{
init(ptr, id, 0, 0, dx, dy);
wrapper.assign(ptr);
wrapper <= id;
}
_layout(T &ref, const string id, const int x1, const int y1, const int x2, const int y2)
{
init(&ref, id, x1, y1, x2, y2);
wrapper.assign(&ref);
wrapper <= id;
}
_layout(T *ptr, const string id, const int x1, const int y1, const int x2, const int y2)
{
init(ptr, id, x1, y1, x2, y2);
wrapper.assign(ptr);
wrapper <= id;
}
_layout(T &refs[], const string id, const int x1, const int y1, const int x2, const int y2)
{
init(refs, id, x1, y1, x2, y2);
}
_layout(T &refs[], const string id = NULL)
{
init(refs, id, 0, 0, 0, 0);
}
template<typename V>
_layout<T> *operator<=(const V value) // overrides base class method
{
if(object != NULL)
{
wrapper <= value;
}
else
{
for(int i = 0; i < ArraySize(array); i++)
{
wrapper.assign(array[i]);
wrapper <= value;
}
}
return &this;
}
virtual _layout<T> *operator[](const string prop) override
{
wrapper[prop];
return &this;
}
virtual _layout<T> *operator<=(const PackedRect &r) override
{
if(object != NULL)
{
wrapper <= r;
}
else
{
for(int i = 0; i < ArraySize(array); i++)
{
wrapper.assign(array[i]);
wrapper <= r;
}
}
return &this;
}
// the following methods are specific to StdLayoutBase
template<typename V>
_layout<T> *operator<=(SequenceGenerator<V> &gen)
{
if(object == NULL)
{
for(int i = 0; i < ArraySize(array); i++)
{
wrapper.assign(array[i]);
wrapper <= ++gen;
}
}
return &this;
}
_layout<T> *operator<(ItemGenerator<T> *gen)
{
while(gen.addItemTo(object));
if(CheckPointer(gen) == POINTER_DYNAMIC) delete gen;
return &this;
}
_layout<T> *operator<=(ItemGenerator<T> &gen)
{
while(gen.addItemTo(object));
return &this;
}
template<typename V>
void attach(StdValue<V> *v)
{
((T *)object).bind(v);
}
template<typename V>
void attach(StdValue<V> &a[])
{
if(ArraySize(array) == ArraySize(a))
{
for(int i = 0; i < ArraySize(a); i++)
{
((T *)array[i]).bind(&a[i]);
}
}
else
{
Print("Can't bind arrays in ", typename(this));
}
}
};
template<typename T>
class StdItemGenerator: public ItemGenerator<T>
{
protected:
long maximum;
long index;
string prefix;
public:
StdItemGenerator(const long max, const string customText = NULL): index(0), maximum(max), prefix(customText) {}
virtual long index2value()
{
return index;
}
virtual bool addItemTo(T *object) override
{
object.AddItem((prefix != NULL ? prefix : typename(T)) + (string)index, index2value());
index++;
return index < maximum;
}
};
template<typename T>
class StdGroupItemGenerator: public StdItemGenerator<T>
{
public:
StdGroupItemGenerator(const long max, const string customText = NULL): StdItemGenerator(max, customText) {}
virtual long index2value() override
{
return 1 << index;
}
};
template<typename T>
class SymbolsItemGenerator: public ItemGenerator<T>
{
protected:
long index;
public:
SymbolsItemGenerator(): index(0) {}
virtual bool addItemTo(T *object) override
{
object.AddItem(SymbolName((int)index, true), index);
index++;
return index < SymbolsTotal(true);
}
};
template<typename T,typename V>
class ArrayItemGenerator: public ItemGenerator<T>
{
protected:
V data[];
int index;
bool bitmask;
public:
ArrayItemGenerator(const V &array[], const bool group = false): index(0), bitmask(group)
{
ArrayCopy(data, array);
}
virtual bool addItemTo(T *object)
{
if(index < ArraySize(data))
{
object.AddItem((string)data[index], (bitmask ? 1 << index : index));
index++;
return true;
}
return false;
}
};
//#include <Layouts/SpinEditResizable.mqh>
//+------------------------------------------------------------------+
//| SpinEditResizable.mqh |
//| Copyright (c) 2019, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//+------------------------------------------------------------------+
//#include <ControlsPlus/SpinEdit.mqh>
class SpinEditResizable: public CSpinEdit
{
public:
SpinEditResizable()
{
RTTI;
}
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();
}
};
//#include <Layouts/Sort.mqh>
class SORT
{
private:
template<typename T>
static void Swap(T &Array[], const int i, const int j)
{
const T Temp = Array[i];
Array[i] = Array[j];
Array[j] = Temp;
}
template<typename T1, typename T2>
static int Partition(T1 &Array[], const T2 &Compare, const int Start, const int End)
{
int Marker = Start;
for(int i = Start; i <= End; i++)
{
if(Compare.Compare(Array[i], Array[End]) <= 0)
{
Swap(Array, i, Marker);
Marker++;
}
}
return(Marker - 1);
}
template<typename T1, typename T2>
static void QuickSort(T1 &Array[], const T2 &Compare, const int Start, const int End)
{
if(Start < End)
{
const int Pivot = Partition(Array, Compare, Start, End);
QuickSort(Array, Compare, Start, Pivot - 1);
QuickSort(Array, Compare, Pivot + 1, End);
}
}
public:
/* MQL-like ArraySort:
void& array[] // array to sort
void& Compare // comparator
int count = WHOLE_ARRAY, // number of elements
int start = 0, // starting index
*/
template<typename T1, typename T2>
static void Sort(T1 &Array[], const T2 &Compare, int Count = WHOLE_ARRAY, const int Start = 0)
{
if(Count == WHOLE_ARRAY)
Count = ArraySize(Array);
QuickSort(Array, Compare, Start, Start + Count - 1);
}
};
template<typename T>
class COMPARE
{
protected:
int Direction;
public:
COMPARE(const int iMode = +1)
{
Direction = iMode;
}
virtual int Compare(const T &First, const T &Second) const
{
return 0;
}
};
template<typename T>
class DefaultCompare: public COMPARE<T>
{
public:
DefaultCompare(const int iMode = +1): COMPARE(iMode) {}
virtual int Compare(const T &First, const T &Second) const override
{
return (First > Second) ? Direction : -Direction;
}
};
#define TAB_CURRENT -1
#define TAB_CHARTS 0
#define TAB_INDICATORS 1
#define TAB_EXPERTS 2
#define TAB_SCRIPTS 3
const static string tabs[4] = {"Charts", "Indicators", "Experts", "Scripts"};
string period2string(const ENUM_TIMEFRAMES tf)
{
const static int plen = StringLen("PERIOD_");
return StringSubstr(EnumToString(tf), plen);
}
template<typename T>
int push(T &results[], const T &text)
{
const int n = ArraySize(results);
ArrayResize(results, n + 1);
results[n] = text;
return n;
}
struct Pair
{
public:
Pair() {}
Pair(const string S, const long L): s(S), id(L) {}
string s;
long id;
};
class ComparePairs : public COMPARE<Pair>
{
public:
int Compare(const Pair &First, const Pair &Second) const
{
return Second.s < First.s ? +1 : (Second.s == First.s ? 0 : -1);
}
};
int listCharts(const int type, string &results[], long &ids[])
{
const string gap = " ";
const long me = ChartID();
long id = ChartFirst();
int count = 0, used = 0, temp, experts = 0, scripts = 0, indicators = 0, subs = 0;
Pair sorter[];
while(id != -1)
{
temp = 0;
const int win = (int)ChartGetInteger(id, CHART_WINDOWS_TOTAL);
// props: symbol, period, expert, script, main window indicators, subwindow indicators
string header = StringFormat("%s %s %s %s", ChartSymbol(id), period2string(ChartPeriod(id)), (win > 1 ? (string)(win - 1) : ""), (id == me ? " *" : ""));
string expert = ChartGetString(id, CHART_EXPERT_NAME);
string script = ChartGetString(id, CHART_SCRIPT_NAME);
if(expert != NULL || script != NULL)
{
if(expert != NULL)
{
experts++;
if(type == 0) header += "\n" + gap + "[E] " + expert;
else if(type == 2)
{
expert += "\n" + gap + header;
push(sorter, Pair(expert, id));
}
}
if(script != NULL)
{
scripts++;
if(type == 0) header += "\n" + gap + "[S] " + script;
else if(type == 3)
{
script += "\n" + gap + header;
push(sorter, Pair(script, id));
}
}
temp++;
}
for(int i = 0; i < win; i++)
{
const int n = ChartIndicatorsTotal(id, i);
for(int k = 0; k < n; k++)
{
string ind = StringFormat("%s <%d;%d>", ChartIndicatorName(id, i, k), i, k);
if(type == 0) header += "\n" + gap + "[I] " + ind;
else if(type == 1)
{
ind += "\n" + gap + header;
push(sorter, Pair(ind, id));
}
indicators++;
if(i > 0) subs++;
temp++;
}
}
if(type == 0)
{
push(sorter, Pair(header, id));
}
count++;
if(temp > 0)
{
used++;
}
id = ChartNext(id);
}
ComparePairs cmp;
SORT::Sort(sorter, cmp);
const int n = ArraySize(sorter);
ArrayResize(results, n);
ArrayResize(ids, n);
for(int i = 0; i < n; i++)
{
results[i] = sorter[i].s;
ids[i] = sorter[i].id;
}
//Print("Total charts number: ", count, ", with MQL-programs: ", used);
//Print("Experts: ", experts, ", Scripts: ", scripts, ", Indicators: ", indicators, " (main: ", indicators - subs, " / sub: ", subs, ")");
return n;
}
class TabButton: public CButton
{
public:
virtual bool OnEnable(void) override
{
m_button.Z_Order(0);
ColorBackground(CONTROLS_BUTTON_COLOR_BG);
return true;
}
virtual bool OnDisable(void) override
{
m_button.Z_Order(-100);
ColorBackground(CONTROLS_LISTITEM_COLOR_BG);
return true;
}
};
class ChartBrowserForm;
class DefaultLayoutStyleable: public StdLayoutStyleable
{
public:
virtual void apply(CWnd *control, const STYLER_PHASE phase) override
{
CButton *button = dynamic_cast<CButton *>(control);
if(button != NULL)
{
button.ColorBorder(CONTROLS_LISTITEM_COLOR_BG);
}
}
};
class MyStdLayoutCache: public StdLayoutCache
{
protected:
ChartBrowserForm *parent;
DefaultLayoutStyleable styler;
TabButton *group[];
ListViewResizable *list;
int currentTab;
public:
MyStdLayoutCache(ChartBrowserForm *owner): parent(owner), list(NULL), currentTab(-1) {}
virtual bool onEvent(const int event, CWnd *control) override
{
if(control != NULL)
{
// debug
// Print(control._rtti, " / ", control.Name(), " / ", event);
// CWndContainer *container = dynamic_cast<CWndContainer *>(findParent(control));
// if(container != NULL)
// Print(container._rtti, " / ", container.Name());
TabButton *button = dynamic_cast<TabButton *>(control);
if(button != NULL)
{
const int cmd = adjustGroup(button);
fillList(cmd);
return true;
}
else
{
CButton *go = dynamic_cast<CButton *>(control);
if(go != NULL)
{
const long index = list.Value();
// Print("Selected:", index);
if(index == LONG_MAX)
{
if(list.Count() > 0)
{
MessageBox("Please, select an item in the list");
}
else
{
MessageBox("Nothing to select here");
}
}
else
{
ChartSetInteger(list.Value(), CHART_BRING_TO_TOP, true);
ChartGetInteger(list.Value(), CHART_WINDOW_HANDLE);
}
}
}
}
return false; // not processed here, so give a chance to process in other handlers
}
virtual StdLayoutStyleable *getStyler() const override
{
return (StdLayoutStyleable *)&styler;
}
// custom stuff
void registerList(ListViewResizable *ptr)
{
list = ptr;
}
void registerGroupButton(TabButton *ptr)
{
const int n = ArraySize(group);
ArrayResize(group, n + 1);
group[n] = ptr;
}
private:
int adjustGroup(TabButton *pressed)
{
const int n = ArraySize(group);
int index = -1;
for(int i = 0; i < n; i++)
{
if(group[i] == pressed)
{
pressed.Disable();
index = i;
}
else group[i].Enable();
}
return index;
}
int expand(const string &a1[], const long &ids[], string &a2[], long &sdi[])
{
string lines[];
const int n = ArraySize(a1);
for(int i = 0; i < n; i++)
{
const int m = StringSplit(a1[i], '\n', lines);
long temp[];
ArrayResize(temp, m);
ArrayFill(temp, 0, m, ids[i]);
ArrayCopy(a2, lines, ArraySize(a2), 0, m);
ArrayCopy(sdi, temp, ArraySize(sdi), 0, m);
}
return ArraySize(a2);
}
public:
void fillList(const int type = TAB_CURRENT)
{
if(type != TAB_CURRENT)
{
currentTab = type;
}
string results[];
long ids[];
const int t = listCharts(currentTab, results, ids);
parent.Caption(DIALOG_TITLE + ":" + (string)t + " " + tabs[currentTab]);
string expanded[];
long charts[];
const int n = expand(results, ids, expanded, charts);
list.ItemsClear();
for(int i = 0; i < n; i++)
{
list.ItemAdd(expanded[i], charts[i]);
}
list.adjustVSize();
//list.forceVScroll();
}
};
//+-----------------------------------------------------------------------+
//| Main dialog window with controls |
//+-----------------------------------------------------------------------+
class ChartBrowserForm: public AppDialogResizable
{
private:
MyStdLayoutCache *cache;
CBox *pMain;
public:
ChartBrowserForm(void);
~ChartBrowserForm(void);
bool CreateLayout(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2);
// general handler for event map
virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
MyStdLayoutCache *getCache(void) const
{
return cache;
}
virtual bool OnChartChange(const long &lparam, const double &dparam, const string &sparam) override
{
const bool result = AppDialogResizable::OnChartChange(lparam, dparam, sparam);
if(this.m_minimized && ChartGetInteger(0, CHART_IS_MAXIMIZED))
{
this.Restore();
cache.fillList();
}
return result;
}
protected:
CBox *GetMainContainer(void);
virtual void SelfAdjustment(const bool restore = false) override;
bool OnRefresh();
};
//+------------------------------------------------------------------+
//| Event handling |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(ChartBrowserForm)
ON_EVENT_LAYOUT_ARRAY(ON_CLICK, cache)
ON_NO_ID_EVENT(ON_LAYOUT_REFRESH, OnRefresh)
EVENT_MAP_END(AppDialogResizable)
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ChartBrowserForm::ChartBrowserForm(void)
{
RTTI;
pMain = NULL;
cache = new MyStdLayoutCache(&this);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ChartBrowserForm::~ChartBrowserForm(void)
{
delete cache;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool ChartBrowserForm::CreateLayout(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2)
{
StdLayoutBase::setCache(cache);
{
_layout<ChartBrowserForm> dialog(this, name, x1, y1, x2, y2);
// ------------------
// GUI Layout for MQL app (standard controls library)
{
_layout<CBoxV> main("main", ClientAreaWidth(), ClientAreaHeight(), WND_ALIGN_CLIENT);
main <= PackedRect(0, 0, 0, 0);
{
{
_layout<CBoxH> Controls("Controls", 192, 30, (ENUM_WND_ALIGN_FLAGS)(WND_ALIGN_CONTENT|(ENUM_WND_ALIGN_FLAGS)(WND_ALIGN_WIDTH|WND_ALIGN_TOP)));
Controls <= PackedRect(5, 0, 5, 0) <= HORIZONTAL_ALIGN_STACK;
{
{
_layout<TabButton> ChartsButton("ChartsButton", 64, 20, (ENUM_WND_ALIGN_FLAGS)WND_ALIGN_BOTTOM);
ChartsButton <= tabs[TAB_CHARTS] <= PackedRect(0, 0, 0, 0);
ChartsButton["enable"] <= false;
cache.registerGroupButton(ChartsButton.get());
}
{
_layout<TabButton> IndicatorsButton("IndicatorsButton", 64, 20, (ENUM_WND_ALIGN_FLAGS)WND_ALIGN_BOTTOM);
IndicatorsButton <= tabs[TAB_INDICATORS] <= PackedRect(0, 0, 0, 0);
cache.registerGroupButton(IndicatorsButton.get());
}
{
_layout<TabButton> ExpertsButton("ExpertsButton", 64, 20, (ENUM_WND_ALIGN_FLAGS)WND_ALIGN_BOTTOM);
ExpertsButton <= tabs[TAB_EXPERTS] <= PackedRect(0, 0, 0, 0);
cache.registerGroupButton(ExpertsButton.get());
}
{
_layout<TabButton> ScriptsButton("ScriptsButton", 64, 20, (ENUM_WND_ALIGN_FLAGS)WND_ALIGN_BOTTOM);
ScriptsButton <= tabs[TAB_SCRIPTS] <= PackedRect(0, 0, 0, 0);
cache.registerGroupButton(ScriptsButton.get());
}
{
_layout<CButton> GoButton("GoButton", 50, 20, (ENUM_WND_ALIGN_FLAGS)WND_ALIGN_RIGHT);
GoButton <= "Go" <= PackedRect(0, 0, 0, 0) <= clrWhite;
GoButton["background"] <= clrDodgerBlue;
GoButton["font"] <= "Arial Black";
}
}
}
{
_layout<CBoxH> listContainer("listContainer", 192, 304, (ENUM_WND_ALIGN_FLAGS)(WND_ALIGN_CONTENT|WND_ALIGN_CLIENT));
listContainer <= PackedRect(0, 30, 0, 0);
{
{
_layout<ListViewResizable> list("list", 190, 304, WND_ALIGN_HEIGHT);
list <= PackedRect(0, 0, 0, 0);
cache.registerList(list.get());
cache.fillList(TAB_CHARTS);
}
}
}
}
}
// ----------------------
}
SelfAdjustment();
EventChartCustom(CONTROLS_SELF_MESSAGE, ON_LAYOUT_REFRESH, 0, 0.0, NULL);
return true;
}
CBox *ChartBrowserForm::GetMainContainer(void)
{
for(int i = 0; i < ControlsTotal(); i++)
{
CWndClient *client = dynamic_cast<CWndClient *>(Control(i));
if(client != NULL)
{
for(int j = 0; j < client.ControlsTotal(); j++)
{
CBox *box = dynamic_cast<CBox *>(client.Control(j));
if(box != NULL)
{
return box;
}
}
}
}
return NULL;
}
void ChartBrowserForm::SelfAdjustment(const bool restore = false)
{
if(pMain == NULL)
{
pMain = GetMainContainer();
}
if(pMain)
{
pMain.Show();
pMain.Pack();
Rebound(Rect());
}
}
bool ChartBrowserForm::OnRefresh()
{
SelfAdjustment();
return true;
}
ChartBrowserForm *form;
int OnInit()
{
form = new ChartBrowserForm();
ChartSetInteger(0, CHART_SHOW_ONE_CLICK, false);
// ChartSetInteger(0, CHART_SHOW_TICKER, false);
if(!form.CreateLayout(0, DIALOG_TITLE, 0, 20, 20, 400, 324))
return (INIT_FAILED);
form.IniFileLoad();
if(!form.Run())
return (INIT_FAILED);
return (INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
form.Destroy(reason);
delete form;
}
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
form.ChartEvent(id, lparam, dparam, sparam);
}
//+------------------------------------------------------------------+
Comments