diff --git a/.gitignore b/.gitignore index e854dce..131a03f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,21 +9,14 @@ experts.dat /Logs /Include/Experts/ -/Include/Arrays/ -/Include/Canvas/ -/Include/ChartObjects/ -/Include/Charts/ /Include/Generic/ -/Include/Controls/ /Include/Expert/ -/Include/Files/ /Include/Graphics/ /Include/Indicators/ /Include/Math/ /Include/MovingAverages.mqh /Include/OpenCL/ /Include/Strings/ -/Include/Tools/ /Include/VirtualKeys.mqh /Scripts/ diff --git a/Include/Arrays/Array.mqh b/Include/Arrays/Array.mqh new file mode 100644 index 0000000..b78f528 --- /dev/null +++ b/Include/Arrays/Array.mqh @@ -0,0 +1,182 @@ +//+------------------------------------------------------------------+ +//| Array.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +//+------------------------------------------------------------------+ +//| 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 + int Minimum(const T &data[],const int start,const int count) const; + template + 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 +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 +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 + } +//+------------------------------------------------------------------+ diff --git a/Include/Arrays/ArrayChar.mqh b/Include/Arrays/ArrayChar.mqh new file mode 100644 index 0000000..73bc39e --- /dev/null +++ b/Include/Arrays/ArrayChar.mqh @@ -0,0 +1,771 @@ +//+------------------------------------------------------------------+ +//| ArrayChar.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "Array.mqh" +//+------------------------------------------------------------------+ +//| Class CArrayChar. | +//| Purpose: Class of dynamic array of variables | +//| of char or uchar type. | +//| Derives from class CArray. | +//+------------------------------------------------------------------+ +class CArrayChar : public CArray + { +protected: + char m_data[]; // data array + +public: + CArrayChar(void); + ~CArrayChar(void); + //--- method of identifying the object + virtual int Type(void) const { return(TYPE_CHAR); } + //--- 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 char element); + bool AddArray(const char &src[]); + bool AddArray(const CArrayChar *src); + bool Insert(const char element,const int pos); + bool InsertArray(const char &src[],const int pos); + bool InsertArray(const CArrayChar *src,const int pos); + bool AssignArray(const char &src[]); + bool AssignArray(const CArrayChar *src); + //--- method of access to the array + char At(const int index) const; + char 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(Minimum(m_data,start,count)); } + int Maximum(const int start,const int count) const { return(Maximum(m_data,start,count)); } + //--- methods of changing + bool Update(const int index,const char 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 char &array[]) const; + bool CompareArray(const CArrayChar *array) const; + //--- methods for working with the sorted array + bool InsertSort(const char element); + int Search(const char element) const; + int SearchGreat(const char element) const; + int SearchLess(const char element) const; + int SearchGreatOrEqual(const char element) const; + int SearchLessOrEqual(const char element) const; + int SearchFirst(const char element) const; + int SearchLast(const char element) const; + int SearchLinear(const char element) const; + +protected: + virtual void QuickSort(int beg,int end,const int mode=0); + int QuickSearch(const char element) const; + int MemMove(const int dest,const int src,int count); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CArrayChar::CArrayChar(void) + { +//--- initialize protected data + m_data_max=ArraySize(m_data); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CArrayChar::~CArrayChar(void) + { + if(m_data_max!=0) + Shutdown(); + } +//+------------------------------------------------------------------+ +//| Moving the memory within a single array | +//+------------------------------------------------------------------+ +int CArrayChar::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=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 CArrayChar::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayChar::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 CArrayChar::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 CArrayChar::Add(const char 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 CArrayChar::AddArray(const char &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(CHAR_MAX); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayChar::Update(const int index,const char 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 CArrayChar::Shift(const int index,const int shift) + { + char tmp_char; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_char=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_char; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayChar::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || 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 CArrayChar::CompareArray(const char &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_char=m_data[(beg+end)>>1]; + while(ip_char) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_char=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_char; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + 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 CArrayChar::SearchLinear(const char element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_char=m_data[m]; + if(t_char==element) + break; + if(t_char>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayChar::Search(const char 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 CArrayChar::SearchGreat(const char 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 CArrayChar::SearchLess(const char 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 CArrayChar::SearchGreatOrEqual(const char element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);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 CArrayChar::SearchLessOrEqual(const char 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 CArrayChar::SearchFirst(const char 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 CArrayChar::SearchLast(const char 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 CArrayChar::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;im_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=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 CArrayDouble::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayDouble::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 CArrayDouble::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 CArrayDouble::Add(const double 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 CArrayDouble::AddArray(const double &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(DBL_MAX); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayDouble::Update(const int index,const double 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 CArrayDouble::Shift(const int index,const int shift) + { + double tmp_double; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_double=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_double; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayDouble::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || 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 CArrayDouble::CompareArray(const double &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_double=m_data[(beg+end)>>1]; + while(ip_double) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_double=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_double; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + 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 CArrayDouble::SearchLinear(const double element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_double=m_data[m]; + //--- compare with delta + if(MathAbs(t_double-element)<=m_delta) + break; + if(t_double>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayDouble::Search(const double element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + if(MathAbs(m_data[pos]-element)<=m_delta) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than | +//| specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayDouble::SearchGreat(const double element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + while(m_data[pos]<=element+m_delta) + 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 CArrayDouble::SearchLess(const double element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + while(m_data[pos]>=element-m_delta) + 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 CArrayDouble::SearchGreatOrEqual(const double element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);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 CArrayDouble::SearchLessOrEqual(const double 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 CArrayDouble::SearchFirst(const double element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + //--- compare with delta + while(MathAbs(m_data[pos]-element)<=m_delta) + if(pos--==0) + break; + return(pos+1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of last appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayDouble::SearchLast(const double element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + //--- compare with delta + while(MathAbs(m_data[pos]-element)<=m_delta) + if(++pos==m_data_total) + break; + return(pos-1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Writing array to file | +//+------------------------------------------------------------------+ +bool CArrayDouble::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;im_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=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 CArrayFloat::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayFloat::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 CArrayFloat::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 CArrayFloat::Add(const float 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 CArrayFloat::AddArray(const float &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(FLT_MAX); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayFloat::Update(const int index,const float 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 CArrayFloat::Shift(const int index,const int shift) + { + float tmp_float; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_float=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_float; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayFloat::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || 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 CArrayFloat::CompareArray(const float &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_float=m_data[(beg+end)>>1]; + while(ip_float) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_float=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_float; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + 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 CArrayFloat::SearchLinear(const float element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_float=m_data[m]; + //--- compare with delta + if(MathAbs(t_float-element)<=m_delta) + break; + if(t_float>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayFloat::Search(const float element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + if(MathAbs(m_data[pos]-element)<=m_delta) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than | +//| specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayFloat::SearchGreat(const float element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + while(m_data[pos]<=element+m_delta) + 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 CArrayFloat::SearchLess(const float element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + while(m_data[pos]>=element-m_delta) + 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 CArrayFloat::SearchGreatOrEqual(const float element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);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 CArrayFloat::SearchLessOrEqual(const float 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 CArrayFloat::SearchFirst(const float element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + //--- compare with delta + while(MathAbs(m_data[pos]-element)<=m_delta) + if(pos--==0) + break; + return(pos+1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of last appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayFloat::SearchLast(const float element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + //--- compare with delta + while(MathAbs(m_data[pos]-element)<=m_delta) + if(++pos==m_data_total) + break; + return(pos-1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Writing array to file | +//+------------------------------------------------------------------+ +bool CArrayFloat::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;im_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=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); + } +//+------------------------------------------------------------------+ +//| 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=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(indexto || 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>1" is quick division by 2 + p_int=m_data[(beg+end)>>1]; + while(ip_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(begelement) + 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=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=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;im_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=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); + } +//+------------------------------------------------------------------+ +//| 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=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(indexto || 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>1" is quick division by 2 + p_long=m_data[(beg+end)>>1]; + while(ip_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(begelement) + 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=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=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;im_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=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); + } +//+------------------------------------------------------------------+ +//| 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) + 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=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(indexto || 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>1" is quick division by 2 + p_node=m_data[(beg+end)>>1]; + while(i0) + { + //--- 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(beg0) + 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=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;im_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=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 CArrayShort::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayShort::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 CArrayShort::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 CArrayShort::Add(const short 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 CArrayShort::AddArray(const short &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(SHORT_MAX); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayShort::Update(const int index,const short 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 CArrayShort::Shift(const int index,const int shift) + { + short tmp_short; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_short=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_short; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayShort::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || 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 CArrayShort::CompareArray(const short &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_short=m_data[(beg+end)>>1]; + while(ip_short) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_short=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_short; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + 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 CArrayShort::SearchLinear(const short element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_short=m_data[m]; + if(t_short==element) + break; + if(t_short>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayShort::Search(const short 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 CArrayShort::SearchGreat(const short 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 CArrayShort::SearchLess(const short 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 CArrayShort::SearchGreatOrEqual(const short element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);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 CArrayShort::SearchLessOrEqual(const short 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 CArrayShort::SearchFirst(const short 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 CArrayShort::SearchLast(const short 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 CArrayShort::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;im_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=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); + } +//+------------------------------------------------------------------+ +//| 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=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(indexto || 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>1" is quick division by 2 + p_string=m_data[(beg+end)>>1]; + while(ip_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(begelement) + 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=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=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 +//+------------------------------------------------------------------+ +//| Class CList. | +//| Purpose: Provides the possibility of working with the list of | +//| CObject instances and its dervivatives | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CList : public CObject + { +protected: + CObject *m_first_node; // pointer to the first element of the list + CObject *m_last_node; // pointer to the last element of the list + CObject *m_curr_node; // pointer to the current element of the list + int m_curr_idx; // index of the current list item + int m_data_total; // number of elements + bool m_free_mode; // flag of the necessity of "physical" deletion of object + bool m_data_sort; // flag if the list is sorted or not + int m_sort_mode; // mode of sorting of array + +public: + CList(void); + ~CList(void); + //--- methods of access to protected data + bool FreeMode(void) const { return(m_free_mode); } + void FreeMode(bool mode) { m_free_mode=mode; } + int Total(void) const { return(m_data_total); } + bool IsSorted(void) const { return(m_data_sort); } + int SortMode(void) const { return(m_sort_mode); } + //--- method of identifying the object + virtual int Type(void) const { return(0x7779); } + //--- 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 the list + virtual CObject *CreateElement(void) { return(NULL); } + //--- methods of filling the list + int Add(CObject *new_node); + int Insert(CObject *new_node,int index); + //--- methods for navigating + int IndexOf(CObject *node); + CObject *GetNodeAtIndex(int index); + CObject *GetFirstNode(void); + CObject *GetPrevNode(void); + CObject *GetCurrentNode(void); + CObject *GetNextNode(void); + CObject *GetLastNode(void); + //--- methods for deleting + CObject *DetachCurrent(void); + bool DeleteCurrent(void); + bool Delete(int index); + void Clear(void); + //--- method for comparing lists + bool CompareList(CList *List); + //--- methods for changing + void Sort(int mode); + bool MoveToIndex(int index); + bool Exchange(CObject *node1,CObject *node2); + //--- method for searching + CObject *Search(CObject *element); +protected: + void QuickSort(int beg,int end,int mode); + CObject *QuickSearch(CObject *element); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CList::CList(void) : m_first_node(NULL), + m_last_node(NULL), + m_curr_node(NULL), + m_curr_idx(-1), + m_data_total(0), + m_free_mode(true), + m_data_sort(false), + m_sort_mode(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CList::~CList(void) + { + Clear(); + } +//+------------------------------------------------------------------+ +//| Method QuickSort | +//+------------------------------------------------------------------+ +void CList::QuickSort(int beg,int end,int mode) + { + int i,j,k; + CObject *i_ptr,*j_ptr,*k_ptr; +//--- + i_ptr=GetNodeAtIndex(i=beg); + j_ptr=GetNodeAtIndex(j=end); + while(i>1" is quick division by 2 + k_ptr=GetNodeAtIndex(k=(beg+end)>>1); + while(i0) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + j_ptr=j_ptr.Prev(); + } + if(i<=j) + { + Exchange(i_ptr,j_ptr); + i++; + i_ptr=GetNodeAtIndex(i); + //--- control the output of the array bounds + if(j==0) + break; + else + { + j--; + j_ptr=GetNodeAtIndex(j); + } + } + } + if(begm_data_total || index<0) + return(-1); +//--- adjust + if(index==-1) + { + if(m_curr_node==NULL) + return(Add(new_node)); + } + else + { + if(GetNodeAtIndex(index)==NULL) + return(Add(new_node)); + } +//--- no need to check m_curr_node + tmp_node=m_curr_node.Prev(); + new_node.Prev(tmp_node); + if(tmp_node!=NULL) + tmp_node.Next(new_node); + else + m_first_node=new_node; + new_node.Next(m_curr_node); + m_curr_node.Prev(new_node); + m_data_total++; + m_data_sort=false; + m_curr_node=new_node; +//--- result + return(index); + } +//+------------------------------------------------------------------+ +//| Get a pointer to the position of element in the list | +//+------------------------------------------------------------------+ +CObject *CList::GetNodeAtIndex(int index) + { + int i; + bool revers; + CObject *result; +//--- check + if(index>=m_data_total) + return(NULL); + if(index==m_curr_idx) + return(m_curr_node); +//--- optimize bust list + if(indexindex;i--) + { + result=result.Prev(); + if(result==NULL) + return(NULL); + } + } + else + { + //--- search from left to right + for(;i=m_data_total || !CheckPointer(m_curr_node)) + return(false); +//--- tune + if(m_curr_idx==index) + return(true); + if(m_curr_idx=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_node=GetNodeAtIndex(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; + t_node=NULL; + } +//--- result + return(t_node); + } +//+------------------------------------------------------------------+ +//| Search position of an element in a sorted list | +//+------------------------------------------------------------------+ +CObject *CList::Search(CObject *element) + { + CObject *result; +//--- check + if(!CheckPointer(element) || !m_data_sort) + return(NULL); +//--- search + result=QuickSearch(element); +//--- result + return(result); + } +//+------------------------------------------------------------------+ +//| Writing list to file | +//+------------------------------------------------------------------+ +bool CList::Save(const int file_handle) + { + CObject *node; + bool result=true; +//--- check + if(!CheckPointer(m_curr_node) || file_handle==INVALID_HANDLE) + return(false); +//--- write start marker - 0xFFFFFFFFFFFFFFFF + if(FileWriteLong(file_handle,-1)!=sizeof(long)) + return(false); +//--- write type + if(FileWriteInteger(file_handle,Type(),INT_VALUE)!=INT_VALUE) + return(false); +//--- write list size + if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE) + return(false); +//--- sequential scannning of elements in the list using the call of method Save() + node=m_first_node; + while(node!=NULL) + { + result&=node.Save(file_handle); + node=node.Next(); + } +//--- successful + return(result); + } +//+------------------------------------------------------------------+ +//| Reading list from file | +//+------------------------------------------------------------------+ +bool CList::Load(const int file_handle) + { + uint i,num; + CObject *node; + bool result=true; +//--- check + if(file_handle==INVALID_HANDLE) + return(false); +//--- read and checking begin marker - 0xFFFFFFFFFFFFFFFF + if(FileReadLong(file_handle)!=-1) + return(false); +//--- read and checking type + if(FileReadInteger(file_handle,INT_VALUE)!=Type()) + return(false); +//--- read list size + num=FileReadInteger(file_handle,INT_VALUE); +//--- sequential creation of list items using the call of method Load() + Clear(); + for(i=0;i0) + p_node.Left(new_node); + else + p_node.Right(new_node); + new_node.Parent(p_node); + Balance(p_node); + } + else + m_root_node=new_node; +//--- result + return(result); + } +//+------------------------------------------------------------------+ +//| Method of removing a node from the tree | +//+------------------------------------------------------------------+ +bool CTree::Delete(CTreeNode *node) + { +//--- check + if(!CheckPointer(node)) + return(false); +//--- delete + if(Detach(node) && CheckPointer(node)==POINTER_DYNAMIC) + delete node; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Method of detaching node from the tree | +//+------------------------------------------------------------------+ +bool CTree::Detach(CTreeNode *node) + { + CTreeNode *curr_node,*tmp_node; + CTreeNode *nodeA,*nodeB; +//--- check + curr_node=node; + if(!CheckPointer(curr_node)) + return(false); +//--- detach + if(curr_node.BalanceL()>curr_node.BalanceR()) + { + nodeA=curr_node.Left(); + while(nodeA.Right()!=NULL) + nodeA=nodeA.Right(); + nodeB=nodeA.Parent(); + if(nodeB!=curr_node) + { + nodeB.Right(nodeA.Left()); + tmp_node=nodeB.Right(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeB); + tmp_node=curr_node.Left(); + nodeA.Left(tmp_node); + tmp_node.Parent(nodeA); + } + //--- left link of curr_node is already installed as it should be + curr_node.Left(NULL); + //--- transferring the right link of curr_node to nodeA + nodeA.Right(curr_node.Right()); + tmp_node=curr_node.Right(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + curr_node.Right(NULL); + //--- transferring the root link of curr_node to nodeA + tmp_node=curr_node.Parent(); + nodeA.Parent(tmp_node); + if(tmp_node!=NULL) + { + if(tmp_node.Left()==curr_node) + tmp_node.Left(nodeA); + else + tmp_node.Right(nodeA); + } + else + { + curr_node.Parent(NULL); + m_root_node=nodeA; + tmp_node=nodeA; + } + Balance(tmp_node); + } + else + { + if(curr_node.BalanceR()>0) + { + nodeA=curr_node.Right(); + while(nodeA.Left()!=NULL) + nodeA=nodeA.Left(); + nodeB=nodeA.Parent(); + if(nodeB!=curr_node) + { + nodeB.Left(nodeA.Right()); + tmp_node=nodeB.Left(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeB); + tmp_node=curr_node.Right(); + nodeA.Right(tmp_node); + tmp_node.Parent(nodeA); + } + //--- right link of curr_node is already installed as it should be + curr_node.Right(NULL); + //--- transferring the left link of curr_node to nodeA + nodeA.Left(curr_node.Left()); + tmp_node=curr_node.Left(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + curr_node.Left(NULL); + //--- transferring the root link of curr_node to nodeA + tmp_node=curr_node.Parent(); + nodeA.Parent(tmp_node); + if(tmp_node!=NULL) + { + if(tmp_node.Left()==curr_node) + tmp_node.Left(nodeA); + else + tmp_node.Right(nodeA); + } + else + { + curr_node.Parent(NULL); + m_root_node=nodeA; + tmp_node=nodeA; + } + Balance(tmp_node); + } + else + { + //--- node list + if(curr_node.Parent()==NULL) + m_root_node=NULL; + else + { + tmp_node=curr_node.Parent(); + if(tmp_node.Left()==curr_node) + tmp_node.Left(NULL); + else + tmp_node.Right(NULL); + curr_node.Parent(NULL); + } + Balance(curr_node.Parent()); + } + } +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Method of cleaning the tree | +//+------------------------------------------------------------------+ +void CTree::Clear(void) + { + if(CheckPointer(m_root_node)==POINTER_DYNAMIC) + delete m_root_node; + m_root_node=NULL; + } +//+------------------------------------------------------------------+ +//| Method of searching for a node in the tree | +//+------------------------------------------------------------------+ +CTreeNode *CTree::Find(const CTreeNode *node) + { + CTreeNode *result=m_root_node; +//--- find + while(result!=NULL && result.Compare(node)!=0) + result=result.GetNext(node); +//--- result + return(result); + } +//+------------------------------------------------------------------+ +//| Method of balancing the tree | +//+------------------------------------------------------------------+ +void CTree::Balance(CTreeNode *node) + { + CTreeNode *nodeA,*nodeB,*nodeC,*curr_node,*tmp_node; +//--- + curr_node=node; + while(curr_node!=NULL) + { + curr_node.RefreshBalance(); + if(MathAbs(curr_node.BalanceL()-curr_node.BalanceR())<=1) + curr_node=curr_node.Parent(); + else + { + if(curr_node.BalanceR()>curr_node.BalanceL()) + { + //--- rotation to the right + tmp_node=curr_node.Right(); + if(tmp_node.BalanceL()>tmp_node.BalanceR()) + { + //--- great rotation to the right + nodeA=curr_node; + nodeB=nodeA.Right(); + nodeC=nodeB.Left(); + nodeC.Parent(nodeA.Parent()); + tmp_node=nodeC.Parent(); + if(tmp_node!=NULL) + { + if(tmp_node.Right()==nodeA) + tmp_node.Right(nodeC); + else + tmp_node.Left(nodeC); + } + else + m_root_node=nodeC; + nodeA.Parent(nodeC); + nodeB.Parent(nodeC); + nodeA.Right(nodeC.Left()); + tmp_node=nodeA.Right(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + nodeC.Left(nodeA); + nodeB.Left(nodeC.Right()); + tmp_node=nodeB.Left(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeB); + nodeC.Right(nodeB); + if(m_root_node==nodeA) + m_root_node=nodeC; + curr_node=nodeC.Parent(); + } + else + { + //--- slight rotation to the right + nodeA=curr_node; + nodeB=nodeA.Right(); + nodeB.Parent(nodeA.Parent()); + tmp_node=nodeB.Parent(); + if(tmp_node!=NULL) + { + if(tmp_node.Right()==nodeA) + tmp_node.Right(nodeB); + else + tmp_node.Left(nodeB); + } + else + m_root_node=nodeB; + nodeA.Parent(nodeB); + nodeA.Right(nodeB.Left()); + tmp_node=nodeA.Right(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + nodeB.Left(nodeA); + if(m_root_node==nodeA) + m_root_node=nodeB; + curr_node=nodeB.Parent(); + } + } + else + { + //--- rotation to the left + tmp_node=curr_node.Left(); + if(tmp_node.BalanceR()>tmp_node.BalanceL()) + { + //--- great rotation to the left + nodeA=curr_node; + nodeB=nodeA.Left(); + nodeC=nodeB.Right(); + nodeC.Parent(nodeA.Parent()); + tmp_node=nodeC.Parent(); + if(tmp_node!=NULL) + { + if(tmp_node.Right()==nodeA) + tmp_node.Right(nodeC); + else + tmp_node.Left(nodeC); + } + else + m_root_node=nodeC; + nodeA.Parent(nodeC); + nodeB.Parent(nodeC); + nodeA.Left(nodeC.Right()); + tmp_node=nodeA.Left(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + nodeC.Right(nodeA); + nodeB.Right(nodeC.Left()); + tmp_node=nodeB.Right(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeB); + nodeC.Left(nodeB); + if(m_root_node==nodeA) + m_root_node=nodeC; + curr_node=nodeC.Parent(); + } + else + { + //--- small rotation to the left + nodeA=curr_node; + nodeB=nodeA.Left(); + nodeB.Parent(nodeA.Parent()); + tmp_node=nodeB.Parent(); + if(tmp_node!=NULL) + { + if(tmp_node.Right()==nodeA) + tmp_node.Right(nodeB); + else + tmp_node.Left(nodeB); + } + else + m_root_node=nodeB; + nodeA.Parent(nodeB); + nodeA.Left(nodeB.Right()); + tmp_node=nodeA.Left(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + nodeB.Right(nodeA); + if(m_root_node==nodeA) + m_root_node=nodeB; + curr_node=nodeB.Parent(); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Writing tree to file | +//+------------------------------------------------------------------+ +bool CTree::Save(const int file_handle) + { +//--- check + if(file_handle==INVALID_HANDLE) + return(false); + if(m_root_node==NULL) + return(true); +//--- result + return(m_root_node.SaveNode(file_handle)); + } +//+------------------------------------------------------------------+ +//| Reading tree from file | +//+------------------------------------------------------------------+ +bool CTree::Load(const int file_handle) + { +//--- check + if(file_handle==INVALID_HANDLE) + return(false); +//--- create root node only + Clear(); + Insert(CreateElement()); +//--- result + return(m_root_node.LoadNode(file_handle,m_root_node)); + } +//+------------------------------------------------------------------+ diff --git a/Include/Arrays/TreeNode.mqh b/Include/Arrays/TreeNode.mqh new file mode 100644 index 0000000..fde1633 --- /dev/null +++ b/Include/Arrays/TreeNode.mqh @@ -0,0 +1,174 @@ +//+------------------------------------------------------------------+ +//| TreeNode.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +//+------------------------------------------------------------------+ +//| Class CTreeNode. | +//| Purpose: Base class of node of binary tree CTree. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CTreeNode : public CObject + { +private: + CTreeNode *m_p_node; // link to node up + CTreeNode *m_l_node; // link to node left + CTreeNode *m_r_node; // link to node right + //--- variables + int m_balance; // balance of node + int m_l_balance; // balance of the left branch + int m_r_balance; // balance of the right branch + +public: + CTreeNode(void); + ~CTreeNode(void); + //--- methods of access to protected data + CTreeNode* Parent(void) const { return(m_p_node); } + void Parent(CTreeNode *node) { m_p_node=node; } + CTreeNode* Left(void) const { return(m_l_node); } + void Left(CTreeNode *node) { m_l_node=node; } + CTreeNode* Right(void) const { return(m_r_node); } + void Right(CTreeNode *node) { m_r_node=node; } + int Balance(void) const { return(m_balance); } + int BalanceL(void) const { return(m_l_balance); } + int BalanceR(void) const { return(m_r_balance); } + //--- method of identifying the object + virtual int Type(void) const { return(0x8888); } + //--- methods for controlling + int RefreshBalance(void); + CTreeNode *GetNext(const CTreeNode *node); + //--- methods for working with files + bool SaveNode(const int file_handle); + bool LoadNode(const int file_handle,CTreeNode *main); + +protected: + //--- method for creating an instance of class + virtual CTreeNode *CreateSample(void) { return(NULL); } + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CTreeNode::CTreeNode(void) : m_p_node(NULL), + m_l_node(NULL), + m_r_node(NULL), + m_balance(0), + m_l_balance(0), + m_r_balance(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTreeNode::~CTreeNode(void) + { +//--- delete nodes of the next level + if(m_l_node!=NULL) + delete m_l_node; + if(m_r_node!=NULL) + delete m_r_node; + } +//+------------------------------------------------------------------+ +//| Calculating the balance of the node | +//+------------------------------------------------------------------+ +int CTreeNode::RefreshBalance(void) + { +//--- calculate the balance of the left branch + if(m_l_node==NULL) + m_l_balance=0; + else + m_l_balance=m_l_node.RefreshBalance(); +//--- calculate the balance of the right branch + if(m_r_node==NULL) + m_r_balance=0; + else + m_r_balance=m_r_node.RefreshBalance(); +//--- calculate the balance of the node + if(m_r_balance>m_l_balance) + m_balance=m_r_balance+1; + else + m_balance=m_l_balance+1; +//--- result + return(m_balance); + } +//+------------------------------------------------------------------+ +//| Selecting next node | +//+------------------------------------------------------------------+ +CTreeNode *CTreeNode::GetNext(const CTreeNode *node) + { + if(Compare(node)>0) + return(m_l_node); +//--- result + return(m_r_node); + } +//+------------------------------------------------------------------+ +//| Writing node data to file | +//+------------------------------------------------------------------+ +bool CTreeNode::SaveNode(const int file_handle) + { + bool result=true; +//--- check + if(file_handle==INVALID_HANDLE) + return(false); +//--- write left node (if it is available) + if(m_l_node!=NULL) + { + FileWriteInteger(file_handle,'L',SHORT_VALUE); + result&=m_l_node.SaveNode(file_handle); + } + else + FileWriteInteger(file_handle,'X',SHORT_VALUE); +//--- write data of current node + result&=Save(file_handle); +//--- write right node (if it is available) + if(m_r_node!=NULL) + { + FileWriteInteger(file_handle,'R',SHORT_VALUE); + result&=m_r_node.SaveNode(file_handle); + } + else + FileWriteInteger(file_handle,'X',SHORT_VALUE); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Reading node data from file | +//+------------------------------------------------------------------+ +bool CTreeNode::LoadNode(const int file_handle,CTreeNode *main) + { + bool result=true; + short s_val; + CTreeNode *node; +//--- check + if(file_handle==INVALID_HANDLE) + return(false); +//--- read directions + s_val=(short)FileReadInteger(file_handle,SHORT_VALUE); + if(s_val=='L') + { + //--- read left node (if there is data) + node=CreateSample(); + if(node==NULL) + return(false); + m_l_node=node; + node.Parent(main); + result&=node.LoadNode(file_handle,node); + } +//--- read data of current node + result&=Load(file_handle); +//--- read directions + s_val=(short)FileReadInteger(file_handle,SHORT_VALUE); + if(s_val=='R') + { + //--- read right node (if there is data) + node=CreateSample(); + if(node==NULL) + return(false); + m_r_node=node; + node.Parent(main); + result&=node.LoadNode(file_handle,node); + } +//--- result + return(result); + } +//+------------------------------------------------------------------+ diff --git a/Include/Canvas/Canvas.mqh b/Include/Canvas/Canvas.mqh new file mode 100644 index 0000000..3d9c92a --- /dev/null +++ b/Include/Canvas/Canvas.mqh @@ -0,0 +1,4804 @@ +//+------------------------------------------------------------------+ +//| Canvas.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +//+------------------------------------------------------------------+ +#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); + bool Attach(const long chart_id,const string objname,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + bool Attach(const long chart_id,const string objname,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + 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); + +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)(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_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_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=0 && y=0 && x=0 && y=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;i0 && 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 || 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;i0 && 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(xy2) + { + 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=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(er2ArraySize(y)) + total=ArraySize(y); +//--- check + if(total<2) + return; + total--; +//--- draw + for(int i=0;iArraySize(y)) + total=ArraySize(y); +//--- check + if(total<2) + return; + total--; +//--- draw + for(int i=0;i=dx) + { + xx=x+dx; + if(xx>=0 && xx=0 && yy=0 && yy=0 && xx=0 && yy=0 && yy=0 && xx=0 && yy=0 && yy=0 && xx=0 && yy=0 && yy=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=0 && xx=0 && xx=0 && yy=0 && xx=0 && xx=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=0 && xx=0 && xx=0 && yy=0 && xx=0 && xxx2) + { + 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(fi40) || // ray 3 is in the 1st or 2nd quadrant + (fi0) || // 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-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-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-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-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-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-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((fi33*M_PI_2) || // ray 3 is 1 or 4 quadrant + (fi3*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-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-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(fi4ry) + 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=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;iymin) + continue; + if(y[i]==ymin) + { + if(x[i]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<=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_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_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_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<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;iymin) + continue; + if(p[i].y==ymin) + { + if(p[i].xp[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<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 1) + else + { + //--- first point has to have a smaller Y coordinate + if(y2ArraySize(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< 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 1) + else + { + //--- first point has to have a smaller Y coordinate + if(y2ArraySize(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< 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 1) + else + { + //--- first point has to have a smaller Y coordinate + if(y2x1) ? 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<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=(y10) + 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=(x10) + 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<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<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<>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) &0xffffffff; + } +//+------------------------------------------------------------------+ +//| 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; i0.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; t0.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; t0.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 +#include +#include +//--- enumerations +enum ENUM_SHOW_FLAGS + { + FLAG_SHOW_NONE =0, + FLAG_SHOW_LEGEND =1, + FLAG_SHOW_SCALE_LEFT =2, + FLAG_SHOW_SCALE_RIGHT =4, + FLAG_SHOW_SCALE_TOP =8, + FLAG_SHOW_SCALE_BOTTOM=16, + FLAG_SHOW_GRID =32, + FLAG_SHOW_DESCRIPTORS =64, + FLAG_SHOW_VALUE =128, + FLAG_SHOW_PERCENT =256, + FLAGS_SHOW_SCALES =(FLAG_SHOW_SCALE_LEFT+FLAG_SHOW_SCALE_RIGHT+ + FLAG_SHOW_SCALE_TOP+FLAG_SHOW_SCALE_BOTTOM), + FLAGS_SHOW_ALL =(FLAG_SHOW_LEGEND+FLAGS_SHOW_SCALES+FLAG_SHOW_GRID+ + FLAG_SHOW_DESCRIPTORS+FLAG_SHOW_VALUE+FLAG_SHOW_PERCENT) + }; +enum ENUM_ALIGNMENT + { + ALIGNMENT_LEFT = 1, // align by left border + ALIGNMENT_TOP = 2, // align by top border + ALIGNMENT_RIGHT = 4, // align by right border + ALIGNMENT_BOTTOM = 8 // align by bottom border + }; +//--- macro +#define IS_SHOW_LEGEND ((m_show_flags&FLAG_SHOW_LEGEND) !=0) +#define IS_SHOW_SCALES ((m_show_flags&FLAGS_SHOW_SCALES) !=0) +#define IS_SHOW_SCALE_LEFT ((m_show_flags&FLAG_SHOW_SCALE_LEFT) !=0) +#define IS_SHOW_SCALE_RIGHT ((m_show_flags&FLAG_SHOW_SCALE_RIGHT) !=0) +#define IS_SHOW_SCALE_TOP ((m_show_flags&FLAG_SHOW_SCALE_TOP) !=0) +#define IS_SHOW_SCALE_BOTTOM ((m_show_flags&FLAG_SHOW_SCALE_BOTTOM)!=0) +#define IS_SHOW_GRID ((m_show_flags&FLAG_SHOW_GRID) !=0) +#define IS_SHOW_DESCRIPTORS ((m_show_flags&FLAG_SHOW_DESCRIPTORS) !=0) +#define IS_SHOW_VALUE ((m_show_flags&FLAG_SHOW_VALUE) !=0) +#define IS_SHOW_PERCENT ((m_show_flags&FLAG_SHOW_PERCENT) !=0) +//+------------------------------------------------------------------+ +//| Class CChartCanvas | +//| Usage: base class for graphical charts | +//+------------------------------------------------------------------+ +class CChartCanvas : public CCanvas + { +protected: + //--- colors + uint m_color_background; + uint m_color_border; + uint m_color_text; + uint m_color_grid; + //--- adjusted parameters + uint m_max_data; + uint m_max_descr_len; + uint m_allowed_show_flags; + uint m_show_flags; + ENUM_ALIGNMENT m_legend_alignment; + uint m_threshold_drawing; + bool m_accumulative; + //--- parameters for scales and grid + double m_v_scale_min; + double m_v_scale_max; + uint m_num_grid; + int m_scale_digits; + //--- data + int m_data_offset; + uint m_data_total; + CArray *m_data; + CArrayInt m_colors; + CArrayString m_descriptors; + //--- + CArrayInt m_index; + uint m_index_size; + double m_sum; + double m_others; + uint m_max_descr_width; + uint m_max_value_width; + //--- variables + CRect m_data_area; + //--- variables for scaling and scales + double m_scale_x; + int m_x_min; + int m_x_0; + int m_x_max; + int m_dx_grid; + double m_scale_y; + int m_y_min; + int m_y_0; + int m_y_max; + int m_dy_grid; + string m_scale_text[]; + +public: + CChartCanvas(void); + ~CChartCanvas(void); + //--- create + virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + //--- colors + uint ColorBackground(void) const { return(m_color_background); } + void ColorBackground(const uint value); + uint ColorBorder(void) const { return(m_color_border); } + void ColorBorder(const uint value); + uint ColorText(void) const { return(m_color_text); } + void ColorText(const uint value); + uint ColorGrid(void) const { return(m_color_grid); } + void ColorGrid(const uint value) { m_color_grid=value; } + //--- adjusted parameters + uint MaxData(void) const { return(m_max_data); } + void MaxData(const uint value); + uint MaxDescrLen(void) const { return(m_max_descr_len); } + void MaxDescrLen(const uint value); + //--- show flags + void AllowedShowFlags(const uint flags); + bool ShowFlags(void) const { return(m_show_flags); } + void ShowFlags(const uint flags); + bool IsShowLegend(void) const { return(IS_SHOW_LEGEND); } + bool IsShowScaleLeft(void) const { return(IS_SHOW_SCALE_LEFT); } + bool IsShowScaleRight(void) const { return(IS_SHOW_SCALE_RIGHT); } + bool IsShowScaleTop(void) const { return(IS_SHOW_SCALE_TOP); } + bool IsShowScaleBottom(void) const { return(IS_SHOW_SCALE_BOTTOM); } + bool IsShowGrid(void) const { return(IS_SHOW_GRID); } + bool IsShowDescriptors(void) const { return(IS_SHOW_DESCRIPTORS); } + bool IsShowPercent(void) const { return(IS_SHOW_PERCENT); } + void ShowLegend(const bool flag=true); + void ShowScaleLeft(const bool flag=true); + void ShowScaleRight(const bool flag=true); + void ShowScaleTop(const bool flag=true); + void ShowScaleBottom(const bool flag=true); + void ShowGrid(const bool flag=true); + void ShowDescriptors(const bool flag=true); + void ShowValue(const bool flag=true); + void ShowPercent(const bool flag=true); + void LegendAlignment(const ENUM_ALIGNMENT value); + void Accumulative(const bool flag=true); + //--- for scales and grid + double VScaleMin(void) const { return(m_v_scale_min); } + void VScaleMin(const double value); + double VScaleMax(void) const { return(m_v_scale_max); } + void VScaleMax(const double value); + uint NumGrid(void) const { return(m_num_grid); } + void NumGrid(const uint value); + void VScaleParams(const double max,const double min,const uint grid); + //--- state + int DataOffset(void) const { return(m_data_offset); } + void DataOffset(const int value); + //--- data + uint DataTotal(void) const { return(m_data_total); } + bool DescriptorUpdate(const uint pos,const string descr); + bool ColorUpdate(const uint pos,const uint clr); + +protected: + virtual void ValuesCheck(void); + virtual void Redraw(void); + virtual void DrawBackground(void); + virtual void DrawLegend(void); + int DrawLegendVertical(const int w,const int h); + int DrawLegendHorizontal(const int w,const int h); + virtual void CalcScales(void); + virtual void DrawScales(void); + virtual int DrawScaleLeft(const bool draw=true); + virtual int DrawScaleRight(const bool draw=true); + virtual int DrawScaleTop(const bool draw=true); + virtual int DrawScaleBottom(const bool draw=true); + virtual void DrawGrid(void); + virtual void DrawDescriptors(void) {} + virtual void DrawChart(void); + virtual void DrawData(const uint idx=0) {} + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CChartCanvas::CChartCanvas(void) : m_color_background(XRGB(0xFF,0xFF,0xFF)), + m_color_border(XRGB(0x9F,0x9F,0x9F)), + m_color_text(XRGB(0x3F,0x3F,0x3F)), + m_color_grid(XRGB(0xCF,0xCF,0xCF)), + m_max_data(10), + m_max_descr_len(10), + m_allowed_show_flags(FLAGS_SHOW_ALL), + m_show_flags(FLAG_SHOW_NONE), + m_legend_alignment(ALIGNMENT_BOTTOM), + m_threshold_drawing(2), + m_accumulative(false), + m_data_offset(0), + m_data_total(0), + m_data(NULL), + m_v_scale_min(0.0), + m_v_scale_max(10.0), + m_num_grid(5), + m_scale_digits(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CChartCanvas::~CChartCanvas(void) + { + if(m_data!=NULL) + delete m_data; + } +//+------------------------------------------------------------------+ +//| Create dynamic resource | +//+------------------------------------------------------------------+ +bool CChartCanvas::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { +//--- call method of parent class + if(!CCanvas::Create(name,width,height,clrfmt)) + return(false); +//--- set font + FontSet("Tahoma",-100); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Sets background color | +//+------------------------------------------------------------------+ +void CChartCanvas::ColorBackground(const uint value) + { + m_color_background=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets border color | +//+------------------------------------------------------------------+ +void CChartCanvas::ColorBorder(const uint value) + { + m_color_border=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets text color | +//+------------------------------------------------------------------+ +void CChartCanvas::ColorText(const uint value) + { + m_color_text=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets maximum amount of data | +//+------------------------------------------------------------------+ +void CChartCanvas::MaxData(const uint value) + { +//--- check + if((value==0) || (m_data_total==value)) + return; +//--- save + m_max_data=value; + if(m_data_total>m_max_data) + { + m_data_total=value; + m_colors.Resize(value); + m_descriptors.Resize(value); + } + } +//+------------------------------------------------------------------+ +//| Sets maximum length of descriptor | +//+------------------------------------------------------------------+ +void CChartCanvas::MaxDescrLen(const uint value) + { + m_max_descr_len=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets allowed visibility flags | +//+------------------------------------------------------------------+ +void CChartCanvas::AllowedShowFlags(const uint flags) + { + m_allowed_show_flags=flags; + m_show_flags&=m_allowed_show_flags; + } +//+------------------------------------------------------------------+ +//| Sets visibility flags | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowFlags(const uint flags) + { + m_show_flags=flags&m_allowed_show_flags; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for "legend" | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowLegend(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_LEGEND)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_LEGEND; + else + m_show_flags&=~FLAG_SHOW_LEGEND; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for left scale | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowScaleLeft(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_SCALE_LEFT)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_SCALE_LEFT; + else + m_show_flags&=~FLAG_SHOW_SCALE_LEFT; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for right scale | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowScaleRight(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_SCALE_RIGHT)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_SCALE_RIGHT; + else + m_show_flags&=~FLAG_SHOW_SCALE_RIGHT; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for top scale | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowScaleTop(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_SCALE_TOP)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_SCALE_TOP; + else + m_show_flags&=~FLAG_SHOW_SCALE_TOP; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for bottom scale | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowScaleBottom(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_SCALE_BOTTOM)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_SCALE_BOTTOM; + else + m_show_flags&=~FLAG_SHOW_SCALE_BOTTOM; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for grid | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowGrid(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_GRID)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_GRID; + else + m_show_flags&=~FLAG_SHOW_GRID; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for descriptors | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowDescriptors(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_DESCRIPTORS)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_DESCRIPTORS; + else + m_show_flags&=~FLAG_SHOW_DESCRIPTORS; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for value | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowValue(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_VALUE)!=0) + { + if(flag) + { + m_show_flags|=FLAG_SHOW_VALUE; + m_show_flags&=~FLAG_SHOW_PERCENT; + } + else + m_show_flags&=~FLAG_SHOW_VALUE; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for percentage | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowPercent(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_PERCENT)!=0) + { + if(flag) + { + m_show_flags|=FLAG_SHOW_PERCENT; + m_show_flags&=~FLAG_SHOW_VALUE; + } + else + m_show_flags&=~FLAG_SHOW_PERCENT; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets legend alignment | +//+------------------------------------------------------------------+ +void CChartCanvas::LegendAlignment(const ENUM_ALIGNMENT value) + { + m_legend_alignment=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets accumulative flag | +//+------------------------------------------------------------------+ +void CChartCanvas::Accumulative(const bool flag=true) + { + m_accumulative=flag; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets lower limit for vertical scale | +//+------------------------------------------------------------------+ +void CChartCanvas::VScaleMin(const double value) + { +//--- check + if(value==m_v_scale_max) + return; +//--- save + m_v_scale_min=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets upper limit for vertical scale | +//+------------------------------------------------------------------+ +void CChartCanvas::VScaleMax(const double value) + { + if(value==m_v_scale_min) + return; +//--- save + m_v_scale_max=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets number of vertical scale divisions | +//+------------------------------------------------------------------+ +void CChartCanvas::NumGrid(const uint value) + { +//--- check + if(value==0) + return; +//--- save + m_num_grid=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets parameters for vertical scale | +//+------------------------------------------------------------------+ +void CChartCanvas::VScaleParams(const double max,const double min,const uint grid) + { +//--- check + if(grid==0) + return; + if(max<=min) + return; +//--- save + m_v_scale_max=max; + m_v_scale_min=min; + m_num_grid =grid; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets data offset | +//+------------------------------------------------------------------+ +void CChartCanvas::DataOffset(const int value) + { + m_data_offset=value; +//--- redraw + Redraw(); + } +//+------------------------------------------------------------------+ +//| Updates parameter descriptor only (in specified position) | +//+------------------------------------------------------------------+ +bool CChartCanvas::DescriptorUpdate(const uint pos,const string descr) + { +//--- update + if(descr!=NULL && !m_descriptors.Update(pos,descr)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates parameter color only (in specified position) | +//+------------------------------------------------------------------+ +bool CChartCanvas::ColorUpdate(const uint pos,const uint clr) + { +//--- update + if(clr!=0 && !m_colors.Update(pos,clr)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Checks values for insignificance | +//+------------------------------------------------------------------+ +void CChartCanvas::ValuesCheck(void) + { + string text; + uint w,h; +//--- clear + m_max_value_width=0; + m_sum =0; + m_others =0; + m_index_size =0; + m_index.Clear(); +//--- check + if(m_data==NULL) + return; + if(m_data.Type()==TYPE_DOUBLE) + { + //--- single-series chart + //--- calculate sum of all values + for(uint i=0;im_height) + { + cols++; + rows=(int)m_index_size/cols; + if((int)m_index_size%cols!=0) + rows++; + } +//--- draw + int x0=(m_legend_alignment==ALIGNMENT_RIGHT) ? width-w*cols+h : h; + int x=0; + int y =-h/2; + int i; + if(m_data_total==m_index_size) + { + for(i=0;i<(int)m_data_total;i++,x+=w) + { + if(i%cols==0) + { + x=x0; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,(uint)m_colors[i]); + TextOut(x+h,y," - "+m_descriptors[i],m_color_text); + } + } + else + { + for(i=0;i<(int)m_index_size;i++,x+=w) + { + int index=m_index[i]; + if(i%cols==0) + { + x=x0; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,(uint)m_colors[index]); + TextOut(x+h,y," - "+m_descriptors[index],m_color_text); + } + if(i%cols==0) + { + x=x0; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,COLOR2RGB(clrBlack)); + TextOut(x+h,y," - Others",m_color_text); + } +//--- width + return(w*cols); + } +//+------------------------------------------------------------------+ +//| Draw horizontal "legend" | +//+------------------------------------------------------------------+ +int CChartCanvas::DrawLegendHorizontal(const int w,const int h) + { + int width =m_data_area.Width(); + int height=m_data_area.Height(); + int rows =1; + int cols =(int)m_index_size; +//--- calculate + while(w*cols>m_width) + { + rows++; + cols=(int)m_index_size/rows; + if((int)m_index_size%rows!=0) + cols++; + } +//--- draw + int dx=width/(cols+1); + int x =dx-w/2+h; + int dy=(int)(1.5*h); + int y =(m_legend_alignment==ALIGNMENT_BOTTOM) ? height-dy*(rows+1) : -h/2; + int i; + if(m_data_total==m_index_size) + { + for(i=0;i<(int)m_data_total;i++,x+=dx) + { + if(i%cols==0) + { + x=dx-w/2+h; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,(uint)m_colors[i]); + TextOut(x+h,y," - "+m_descriptors[i],m_color_text); + } + } + else + { + for(i=0;i<(int)m_index_size;i++,x+=dx) + { + int index=m_index[i]; + if(i%cols==0) + { + x=dx-w/2+h; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,(uint)m_colors[index]); + TextOut(x+h,y," - "+m_descriptors[index],m_color_text); + } + if(i%cols==0) + { + x=dx-w/2+h; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,COLOR2RGB(clrBlack)); + TextOut(x+h,y," - Others",m_color_text); + } +//--- height + return(dy*(rows+1)); + } +//+------------------------------------------------------------------+ +//| Calculates coordinates of scales | +//+------------------------------------------------------------------+ +void CChartCanvas::CalcScales(void) + { + int width =m_data_area.Width(); + int height=m_data_area.Height(); +//--- limits + m_y_max=m_data_area.top+DrawScaleTop(false); + m_y_min=m_data_area.bottom-DrawScaleBottom(false); +//--- additional + m_dy_grid=(int)((m_y_min-m_y_max)/m_num_grid); + m_y_max+=(int)(((m_y_min-m_y_max)-m_dy_grid*m_num_grid)/2); + m_y_min=(int)(m_y_max+m_dy_grid*m_num_grid); +//--- normalize + if(m_v_scale_min>=0.0) + m_y_0=m_y_min; + else + { + if(m_v_scale_max<=0.0) + m_y_0=m_y_max; + else + m_y_0=(int)(m_y_max+(m_y_min-m_y_max)*m_v_scale_max/(m_v_scale_max-m_v_scale_min)); + } +//--- scale + m_scale_y=(m_v_scale_max!=m_v_scale_min) ? (m_y_min-m_y_max)/(m_v_scale_max-m_v_scale_min) : 1; +//--- labels on scale + if(ArraySize(m_scale_text)!=m_num_grid+1 && ArrayResize(m_scale_text,m_num_grid+1)==-1) + return; + double val=m_v_scale_min; + double dval=(m_v_scale_max-m_v_scale_min)/m_num_grid; + for(uint i=0;i<=m_num_grid;i++,val+=dval) + m_scale_text[i]=DoubleToString(val,m_scale_digits); + } +//+------------------------------------------------------------------+ +//| Redraws scales | +//+------------------------------------------------------------------+ +void CChartCanvas::DrawScales(void) + { +//--- recalculate + CalcScales(); +//--- redraw scales + if(IS_SHOW_SCALE_LEFT) + DrawScaleLeft(); + if(IS_SHOW_SCALE_RIGHT) + DrawScaleRight(); + if(IS_SHOW_SCALE_TOP) + DrawScaleTop(); + if(IS_SHOW_SCALE_BOTTOM) + DrawScaleBottom(); + } +//+------------------------------------------------------------------+ +//| Redraws left scale | +//+------------------------------------------------------------------+ +int CChartCanvas::DrawScaleLeft(const bool draw) + { +//--- check flag + if(!IS_SHOW_SCALE_LEFT) + return(0); +//--- variables + int x1=m_data_area.left; + int x2; + int y=m_y_min; +//--- calculate scale width + int size=0; + for(uint i=0;i<=m_num_grid;i++) + { + if(size +//+------------------------------------------------------------------+ +//| Class CHistogramChart | +//| Usage: generates histogram chart | +//+------------------------------------------------------------------+ +class CHistogramChart : public CChartCanvas + { +private: + //--- colors + uint m_fill_brush[]; + //--- adjusted parameters + bool m_gradient; + uint m_bar_gap; + uint m_bar_min_size; + uint m_bar_border; + //--- data + CArrayObj *m_values; + +public: + CHistogramChart(void); + ~CHistogramChart(void); + //--- create + virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE); + //--- adjusted parameters + void Gradient(const bool flag=true) { m_gradient=flag; } + void BarGap(const uint value) { m_bar_gap=value; } + void BarMinSize(const uint value) { m_bar_min_size=value; } + void BarBorder(const uint value) { m_bar_border=value; } + //--- data + bool SeriesAdd(const double &value[],const string descr="",const uint clr=0); + bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0); + bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0); + bool SeriesDelete(const uint pos); + bool ValueUpdate(const uint series,const uint pos,double value); + +protected: + virtual void DrawData(const uint idx); + void DrawBar(const int x,const int y,const int w,const int h,const uint clr); + void GradientBrush(const int size,const uint fill_clr); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CHistogramChart::CHistogramChart(void) : m_gradient(true), + m_bar_gap(3), + m_bar_min_size(5), + m_bar_border(0) + { + ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CHistogramChart::~CHistogramChart(void) + { + if(ArraySize(m_fill_brush)!=0) + ArrayFree(m_fill_brush); + } +//+------------------------------------------------------------------+ +//| Create dynamic resource | +//+------------------------------------------------------------------+ +bool CHistogramChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { +//--- create object to store data + if((m_values=new CArrayObj)==NULL) + return(false); +//--- pass responsibility for its destruction to the parent class + m_data=m_values; +//--- call method of parent class + if(!CChartCanvas::Create(name,width,height,clrfmt)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Adds data series | +//+------------------------------------------------------------------+ +bool CHistogramChart::SeriesAdd(const double &value[],const string descr,const uint clr) + { +//--- check + if(m_data_total==m_max_data) + return(false); +//--- add + CArrayDouble *arr=new CArrayDouble; + if(!m_values.Add(arr)) + return(false); + if(!arr.AssignArray(value)) + return(false); + if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr)) + return(false); + if(!m_descriptors.Add(descr)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Inserts data series | +//+------------------------------------------------------------------+ +bool CHistogramChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr) + { +//--- check + if(m_data_total==m_max_data) + return(false); + if(pos>=m_data_total) + return(false); +//--- insert + CArrayDouble *arr=new CArrayDouble; + if(!m_values.Insert(arr,pos)) + return(false); + if(!arr.AssignArray(value)) + return(false); + if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos)) + return(false); + if(!m_descriptors.Insert(descr,pos)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates data series | +//+------------------------------------------------------------------+ +bool CHistogramChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr) + { +//--- check + if(pos>=m_data_total) + return(false); + CArrayDouble *data=m_values.At(pos); + if(data==NULL) + return(false); +//--- update + if(!data.AssignArray(value)) + return(false); + if(clr!=0 && !m_colors.Update(pos,clr)) + return(false); + if(descr!=NULL && !m_descriptors.Update(pos,descr)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Deletes data series | +//+------------------------------------------------------------------+ +bool CHistogramChart::SeriesDelete(const uint pos) + { +//--- check + if(pos>=m_data_total && m_data_total!=0) + return(false); +//--- delete + if(!m_values.Delete(pos)) + return(false); + m_data_total--; + if(!m_colors.Delete(pos)) + return(false); + if(!m_descriptors.Delete(pos)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates element in data series | +//+------------------------------------------------------------------+ +bool CHistogramChart::ValueUpdate(const uint series,const uint pos,double value) + { + CArrayDouble *data=m_values.At(series); +//--- check + if(data==NULL) + return(false); +//--- update + if(!data.Update(pos,value)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Draws histogram | +//+------------------------------------------------------------------+ +void CHistogramChart::DrawData(const uint idx) + { + double value=0.0; +//--- check + CArrayDouble *data=m_values.At(idx); + if(data==NULL) + return; + int total=data.Total(); + if(total==0 || (int)idx>=total) + return; +//--- calculate + int x1=m_data_area.left; + int x2=m_data_area.right; + int dx=(x2-x1)/total; + uint clr=m_colors[idx]; + uint w=dx/m_data_total; + if(w0) + { + y=(m_y_0-(int)(value*m_scale_y)); + h=m_y_0-y; + } + else + { + y=m_y_0; + h=-(int)(value*m_scale_y); + } + DrawBar(x,y,w,h,clr); + //--- draw text of value + if(IS_SHOW_VALUE) + { + string text =DoubleToString(value,2); + int width=(int)(TextWidth(text)+w); + if(value>0) + { + if(width>y-m_y_max) + TextOut(x+w/2,y+w,text,m_color_text,TA_RIGHT|TA_VCENTER); + else + TextOut(x+w/2,y-w,text,m_color_text,TA_LEFT|TA_VCENTER); + } + else + { + if(width>m_y_min-y-h) + TextOut(x+w/2,y+h-w,text,m_color_text,TA_LEFT|TA_VCENTER); + else + TextOut(x+w/2,y+h+w,text,m_color_text,TA_RIGHT|TA_VCENTER); + } + } + } + if(IS_SHOW_VALUE) + FontSet(fontname,fontsize,fontflags,fontangle); + } +//+------------------------------------------------------------------+ +//| Draws bar | +//+------------------------------------------------------------------+ +void CHistogramChart::DrawBar(const int x,const int y,const int w,const int h,const uint clr) + { +//--- draw bar + if(!m_gradient || ArraySize(m_fill_brush)>1; + if((r&1)==0) + i1--; + //--- calculate + while(dy>=dx) + { + clr=fill_clr; + dclr=GETRGB(XRGB((r-dy)*GETRGBR(clr)/r,(r-dy)*GETRGBG(clr)/r,(r-dy)*GETRGBB(clr)/r)); + clr-=dclr; + m_fill_brush[i1]=clr; + m_fill_brush[i2]=clr; + //--- + if(f>=0) + { + dy--; + dd_y+=2; + f+=dd_y; + } + dx++; + if(--i1<0) + break; + i2++; + dd_x+=2; + f+=dd_x; + } + } + else + ArrayFree(m_fill_brush); + } +//+------------------------------------------------------------------+ diff --git a/Include/Canvas/Charts/LineChart.mqh b/Include/Canvas/Charts/LineChart.mqh new file mode 100644 index 0000000..c81e9e3 --- /dev/null +++ b/Include/Canvas/Charts/LineChart.mqh @@ -0,0 +1,383 @@ +//+------------------------------------------------------------------+ +//| LineChart.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "ChartCanvas.mqh" +#include +//+------------------------------------------------------------------+ +//| Class CLineChart | +//| Usage: generates line chart | +//+------------------------------------------------------------------+ +class CLineChart : public CChartCanvas + { +private: + //--- data + CArrayObj *m_values; + //--- adjusted parameters + bool m_filled; + +public: + CLineChart(void); + ~CLineChart(void); + //--- create + virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE); + //--- adjusted parameters + void Filled(const bool flag=true) { m_filled=flag; } + //--- set up + bool SeriesAdd(const double &value[],const string descr="",const uint clr=0); + bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0); + bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0); + bool SeriesDelete(const uint pos); + bool ValueUpdate(const uint series,const uint pos,double value); + +protected: + virtual void DrawChart(void); + virtual void DrawData(const uint index=0); + +private: + double CalcArea(const uint index); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CLineChart::CLineChart(void) : m_filled(false) + { + ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CLineChart::~CLineChart(void) + { + } +//+------------------------------------------------------------------+ +//| Create dynamic resource | +//+------------------------------------------------------------------+ +bool CLineChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { +//--- create object to store data + if((m_values=new CArrayObj)==NULL) + return(false); +//--- pass responsibility for its destruction to the parent class + m_data=m_values; +//--- call method of parent class + if(!CChartCanvas::Create(name,width,height,clrfmt)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Adds data series | +//+------------------------------------------------------------------+ +bool CLineChart::SeriesAdd(const double &value[],const string descr,const uint clr) + { +//--- check + if(m_data_total==m_max_data) + return(false); +//--- add + CArrayDouble *arr=new CArrayDouble; + if(!m_values.Add(arr)) + return(false); + if(!arr.AssignArray(value)) + return(false); + if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr)) + return(false); + if(!m_descriptors.Add(descr)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Inserts data series | +//+------------------------------------------------------------------+ +bool CLineChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr) + { +//--- check + if(m_data_total==m_max_data) + return(false); + if(pos>=m_data_total) + return(false); +//--- insert + CArrayDouble *arr=new CArrayDouble; + if(!m_values.Insert(arr,pos)) + return(false); + if(!arr.AssignArray(value)) + return(false); + if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos)) + return(false); + if(!m_descriptors.Insert(descr,pos)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates data series | +//+------------------------------------------------------------------+ +bool CLineChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr) + { +//--- check + if(pos>=m_data_total) + return(false); + CArrayDouble *data=m_values.At(pos); + if(data==NULL) + return(false); +//--- update + if(!data.AssignArray(value)) + return(false); + if(clr!=0 && !m_colors.Update(pos,clr)) + return(false); + if(descr!=NULL && !m_descriptors.Update(pos,descr)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Deletes data series | +//+------------------------------------------------------------------+ +bool CLineChart::SeriesDelete(const uint pos) + { +//--- check + if(pos>=m_data_total && m_data_total!=0) + return(false); +//--- delete + if(!m_values.Delete(pos)) + return(false); + m_data_total--; + if(!m_colors.Delete(pos)) + return(false); + if(!m_descriptors.Delete(pos)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates element in data series | +//+------------------------------------------------------------------+ +bool CLineChart::ValueUpdate(const uint series,const uint pos,double value) + { + CArrayDouble *data=m_values.At(series); +//--- check + if(data==NULL) + return(false); +//--- update + if(!data.Update(pos,value)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Redraws data | +//+------------------------------------------------------------------+ +void CLineChart::DrawChart(void) + { + if(m_filled) + { + //--- calculate areas of filling + double s[]; + ArrayResize(s,m_data_total); + ArrayInitialize(s,0); + for(uint i=0;im_y_0 && y2m_y_0)) + { + //--- draw two triangles + int x3; + if(y1>y2) + { + x3=x+dx*(y1-m_y_0)/(y1-y2); + FillTriangle(x,y1,x3,m_y_0,x,m_y_0,(uint)m_colors[index]); + FillTriangle(x+dx,y2,x3,m_y_0,x+dx,m_y_0,(uint)m_colors[index]); + } + else + { + x3=x+dx*(m_y_0-y1)/(y2-y1); + FillTriangle(x,y1,x3,m_y_0,x,m_y_0,(uint)m_colors[index]); + FillTriangle(x+dx,y2,x3,m_y_0,x+dx,m_y_0,(uint)m_colors[index]); + } + continue; + } + if(y1y2) + FillTriangle(x,y1,x+dx,y2,x+dx,y1,(uint)m_colors[index]); + if(y1m_y_0 || y2>m_y_0) + { + if(y1y2) + { + FillTriangle(x,y1,x+dx,y2,x,y2,(uint)m_colors[index]); + y1=y2; + } + } + FillRectangle(x,m_y_0,x+dx,y1,(uint)m_colors[index]); + } + else + LineAA(x,y1,x+dx,y2,(uint)m_colors[index],STYLE_SOLID); + } + } +//+------------------------------------------------------------------+ +//| Area of filling | +//+------------------------------------------------------------------+ +double CLineChart::CalcArea(const uint index) + { + double area =0; + double value=0; + int dx =100; +//--- + CArrayDouble *data=m_values.At(index); + if(data==NULL) + return(0); + int total=data.Total(); + if(total<=1) + return(0); + int y1=0; + int y2=(int)(m_y_0-data[0]*m_scale_y); + for(int i=0;im_y_0 && y2m_y_0)) + { + //--- line of values crosses the Y axis + int x; + if(y1>y2) + { + //--- from the bottom up + x=dx*(y1-m_y_0)/(y1-y2); + //--- add area of lower triangle + area+=x*(y1-m_y_0)/2; + //--- add area of upper triangle + area+=(dx-x)*(m_y_0-y2)/2; + } + else + { + //--- from top down + x=dx*(m_y_0-y1)/(y2-y1); + //--- add area of upper triangle + area+=x*(m_y_0-y1)/2; + //--- add area of lower triangle + area+=(dx-x)*(y2-m_y_0)/2; + } + continue; + } + if(y1y2) + { + //--- add area of triangle + area+=dx*(y1-y2)/2; + //--- add area of rectangle + area+=dx*(m_y_0-y2); + } + if(y1m_y_0 || y2>m_y_0) + { + //--- both values are less than zero + if(y1y2) + { + //--- add area of triangle + area+=dx*(y1-y2)/2; + //--- add area of rectangle + area+=dx*(y2-m_y_0); + } + } + } +//--- + return(area); + } +//+------------------------------------------------------------------+ diff --git a/Include/Canvas/Charts/PieChart.mqh b/Include/Canvas/Charts/PieChart.mqh new file mode 100644 index 0000000..79be4d1 --- /dev/null +++ b/Include/Canvas/Charts/PieChart.mqh @@ -0,0 +1,414 @@ +//+------------------------------------------------------------------+ +//| PieChart.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "ChartCanvas.mqh" +//+------------------------------------------------------------------+ +//| Class CPieChart | +//| Usage: generates pie chart | +//+------------------------------------------------------------------+ +class CPieChart : public CChartCanvas + { +private: + //--- data + CArrayDouble *m_values; + //--- for draw + int m_x0; + int m_y0; + int m_r; + +public: + CPieChart(void); + ~CPieChart(void); + //--- create + virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + //--- data + bool SeriesSet(const double &value[],const string &text[],const uint &clr[]); + bool ValueAdd(const double value,const string descr="",const uint clr=0); + bool ValueInsert(const uint pos,const double value,const string descr="",const uint clr=0); + bool ValueUpdate(const uint pos,const double value,const string descr=NULL,const uint clr=0); + bool ValueDelete(const uint pos); + +protected: + virtual void DrawChart(void); + void DrawPie(double fi3,double fi4,int idx,CPoint &p[],const uint clr); + string LabelMake(const string text,const double value,const bool to_left); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CPieChart::CPieChart(void) + { + uint flags=FLAG_SHOW_LEGEND|FLAG_SHOW_DESCRIPTORS|FLAG_SHOW_VALUE|FLAG_SHOW_PERCENT; + AllowedShowFlags(flags); + ShowFlags(flags); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CPieChart::~CPieChart(void) + { + } +//+------------------------------------------------------------------+ +//| Create dynamic resource | +//+------------------------------------------------------------------+ +bool CPieChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { +//--- create object to store data + if((m_values=new CArrayDouble)==NULL) + return(false); +//--- pass responsibility for its destruction to the parent class + m_data=m_values; +//--- call method of parent class + if(!CChartCanvas::Create(name,width,height,clrfmt)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Sets displayed parameters | +//+------------------------------------------------------------------+ +bool CPieChart::SeriesSet(const double &value[],const string &text[],const uint &clr[]) + { +//--- !!! user is responsible for correct filling of arrays !!! +//--- check + if(m_values==NULL) + return(false); +//--- set + if(!m_values.AssignArray(value)) + return(false); + if(!m_descriptors.AssignArray(text)) + return(false); + if(!m_colors.AssignArray(clr)) + return(false); + m_data_total=m_values.Total(); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Adds displayed parameter (to the end) | +//+------------------------------------------------------------------+ +bool CPieChart::ValueAdd(const double value,const string descr,const uint clr) + { +//--- check + if((value<=0)) + return(false); +//--- add + if(!m_values.Add(value)) + return(false); + if(!m_descriptors.Add(descr)) + return(false); + if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Inserts displayed parameter (to specified position) | +//+------------------------------------------------------------------+ +bool CPieChart::ValueInsert(const uint pos,const double value,const string descr,const uint clr) + { +//--- check + if((value<=0)) + return(false); +//--- insert + if(!m_values.Insert(value,pos)) + return(false); + if(!m_descriptors.Insert(descr,pos)) + return(false); + if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates displayed parameter (in specified position) | +//+------------------------------------------------------------------+ +bool CPieChart::ValueUpdate(const uint pos,const double value,const string descr,const uint clr) + { +//--- check + if((value<=0)) + return(false); +//--- update + if(!m_values.Update(pos,value)) + return(false); + if(descr!=NULL && !m_descriptors.Update(pos,descr)) + return(false); + if(clr!=0 && !m_colors.Update(pos,clr)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Deletes displayed parameter (from specified position) | +//+------------------------------------------------------------------+ +bool CPieChart::ValueDelete(const uint pos) + { +//--- delete + if(!m_values.Delete(pos)) + return(false); + m_data_total--; + if(!m_descriptors.Delete(pos)) + return(false); + if(!m_colors.Delete(pos)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Draws | +//+------------------------------------------------------------------+ +void CPieChart::DrawChart(void) + { +//--- check + if(m_data_total==0) + return; +//--- variables + string text=""; + double angle=M_PI*(m_data_offset%360)/180; + int width,height; + int dw=0; + int dh=0; + int index; + CPoint p0[]; + CPoint p1[]; +//--- calculate geometry + width =(m_data_area.Width()<<3)/10; + height=(m_data_area.Height()<<3)/10; + if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS) + { + if(IS_SHOW_VALUE) + dw=(int)m_max_value_width; + else + { + if(IS_SHOW_PERCENT) + dw=TextWidth("100.00%"); + } + } + else + { + if(IS_SHOW_DESCRIPTORS) + { + if(IS_SHOW_VALUE) + dw=(int)m_max_value_width+TextWidth(" ()"); + else + { + if(IS_SHOW_PERCENT) + dw=TextWidth(" (100.00%)"); + } + dw+=(int)m_max_descr_width; + } + } +//--- pie chart will always be round + width -=2*dw+10; + height-=20; + m_x0=m_data_area.left+(m_data_area.Width()>>1); + m_y0=m_data_area.top+(m_data_area.Height()>>1); + m_r =(((width>height) ? height : width)>>1); +//--- draw pie chart + if(ArrayResize(p0,m_data_total+1)==-1) + return; + if(m_data_total==1) + { + FillCircle(m_x0,m_y0,m_r,m_colors[0]); + Circle(m_x0,m_y0,m_r,m_color_border); + } + else + { + Circle(m_x0,m_y0,m_r,m_color_border); + for(uint i=0;i=m_x0) + { + x=p1[i].x+10; + y=p1[i].y; + index=m_index[i]; + text=LabelMake(m_descriptors[index],m_values[index],false); + if(text!="") + { + Line(p0[i].x,p0[i].y,p1[i].x,p1[i].y,m_color_border); + Line(p1[i].x,p1[i].y,x,y,m_color_border); + TextOut(x+5,y,text,m_color_text,TA_LEFT|TA_VCENTER); + } + } + if(m_data_total!=m_index_size) + { + index=(int)m_data_total-1; + if(p0[index].x>=m_x0) + { + x=p1[index].x+10; + y=p1[index].y; + text=LabelMake("Others",m_others,true); + TextOut(x+5,y,text,m_color_text,TA_LEFT|TA_VCENTER); + } + else + { + x=p1[index].x-10; + y=p1[index].y; + text=LabelMake("Others",m_others,false); + TextOut(x-5,y,text,m_color_text,TA_RIGHT|TA_VCENTER); + } + if(text!="") + { + Line(p0[index].x,p0[index].y,p1[index].x,p1[index].y,m_color_border); + Line(p1[index].x,p1[index].y,x,y,m_color_border); + } + } + ArrayFree(p1); + ArrayFree(p0); + } +//+------------------------------------------------------------------+ +//| Draw pie | +//+------------------------------------------------------------------+ +void CPieChart::DrawPie(double fi3,double fi4,int idx,CPoint &p[],const uint clr) + { +//--- draw arc + Arc(m_x0,m_y0,m_r,m_r,fi3,fi4,p[idx].x,p[idx].y,p[idx+1].x,p[idx+1].y,clr); +//--- variables + int x3=p[idx].x; + int y3=p[idx].y; + int x4=p[idx+1].x; + int y4=p[idx+1].y; +//--- draw radii + if(idx==0) + Line(m_x0,m_y0,x3,y3,clr); + if(idx!=m_data_total-1) + Line(m_x0,m_y0,x4,y4,clr); +//--- fill + double fi=(fi3+fi4)/2; + int xf=m_x0+(int)(0.99*m_r*cos(fi)); + int yf=m_y0-(int)(0.99*m_r*sin(fi)); + Fill(xf,yf,clr); +//--- for small pie + if(fi4-fi3<=M_PI_4) + Line(m_x0,m_y0,xf,yf,clr); + } +//+------------------------------------------------------------------+ +//| Make label for pie | +//+------------------------------------------------------------------+ +string CPieChart::LabelMake(const string text,const double value,const bool to_left) + { + string label=""; +//--- + if(to_left) + { + if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS) + { + if(IS_SHOW_VALUE) + label=DoubleToString(value,2); + else + { + if(IS_SHOW_PERCENT) + label=DoubleToString(100*value/m_sum,2)+"%"; + } + } + else + { + label=text; + if(IS_SHOW_VALUE) + label+=" ("+DoubleToString(value,2)+")"; + else + { + if(IS_SHOW_PERCENT) + label+=" ("+DoubleToString(100*value/m_sum,2)+"%)"; + } + } + } + else + { + if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS) + { + if(IS_SHOW_VALUE) + label=DoubleToString(value,2); + else + { + if(IS_SHOW_PERCENT) + label=DoubleToString(100*value/m_sum,2)+"%"; + } + } + else + { + if(IS_SHOW_VALUE) + label="("+DoubleToString(value,2)+") "; + else + { + if(IS_SHOW_PERCENT) + label="("+DoubleToString(100*value/m_sum,2)+"%) "; + } + label+=text; + } + } +//--- + return(label); + } +//+------------------------------------------------------------------+ diff --git a/Include/Canvas/FlameCanvas.mqh b/Include/Canvas/FlameCanvas.mqh new file mode 100644 index 0000000..3705caa --- /dev/null +++ b/Include/Canvas/FlameCanvas.mqh @@ -0,0 +1,751 @@ +//+------------------------------------------------------------------+ +//| FlameCanvas.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "Canvas.mqh" +#include +//+------------------------------------------------------------------+ +//| Gradient descriptors | +//+------------------------------------------------------------------+ +struct GRADIENT_COLOR + { + uint clr; // color in ARGB format + uint pos; // position of color in percentage of gradient range + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +struct GRADIENT_SIZE + { + uint size; // width of gradient fill in percentage of base fill + uint pos; // position of color in percentage of gradient length + }; +//+------------------------------------------------------------------+ +//| Class CFlameCanvas | +//| Usage: generates flame | +//+------------------------------------------------------------------+ +class CFlameCanvas : public CCanvas + { +private: + //--- parameters + uint m_bar_gap; + uint m_bar_width; + uint m_chart_scale; + double m_chart_price_min; + double m_chart_price_max; + ENUM_TIMEFRAMES m_timeframe; + string m_symbol; + int m_future_bars; + int m_back_bars; + int m_rates_total; + uint m_palette[256]; // flame palette + uchar m_flame[]; // buffer for calculation of flame + uint m_time_redraw; + uint m_delay; + // bool m_resize_flag; + // int m_tick_cnt; + //--- flame parameters + datetime m_tb1; + double m_pb1; + datetime m_te1; + double m_pe1; + datetime m_tb2; + double m_pb2; + datetime m_te2; + double m_pe2; + //--- equation parameters for flame + int m_cloud_axis[100]; + double m_a1; + double m_b1; + double m_a2; + double m_b2; + int m_xb1; + int m_yb1; + int m_xe1; + int m_ye1; + int m_xb2; + int m_yb2; + int m_xe2; + int m_ye2; + +public: + CFlameCanvas(void); + ~CFlameCanvas(void); + //--- create + bool FlameCreate(const string name,const datetime time,const int future_bars,const int back_bars=0); + void RatesTotal(const int value); + //--- setting + void PaletteSet(uint clr=0xFF0000); + //--- draw + void FlameDraw(const double &prices[],const int width,const int lenght); + void FlameSet(datetime xb1,double yb1,datetime xe1,double ye1,datetime xb2,double yb2,datetime xe2,double ye2); + //--- event handler + void ChartEventHandler(const int id,const long &lparam,const double &dparam,const string &sparam); + +protected: + bool Resize(void); + void ChartScale(void); + void FlameSet(void); + void CloudDraw(const double &prices[],const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[],const uchar t_level=255,const bool custom_gradient=true); + void FlameDraw(const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[]); + void GradientVertical(const int xb,const int xe,const int yb1,const int ye1,const int yb2,const int ye2,const GRADIENT_COLOR &gradient[]); + void GradientVerticalLine(int x,int y1,int y2,const GRADIENT_COLOR &gradient[]); + void GradientVerticalLineMonochrome(int x,int y1,int y2,uint clr1,uint clr2); + void FlameCreate(void); + void FlameCalculate(void); + void Delay(const uint value); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CFlameCanvas::CFlameCanvas(void) : m_bar_gap(16), + m_bar_width(8), + m_chart_scale(1), + m_chart_price_min(0.0), + m_chart_price_max(0.0), + m_timeframe(PERIOD_CURRENT), + m_symbol(NULL), + m_future_bars(0), + m_back_bars(0), + m_rates_total(0), + m_time_redraw(0), + m_delay(50), + m_tb1(0), + m_pb1(0), + m_te1(0), + m_pe1(0), + m_tb2(0), + m_pb2(0), + m_te2(0), + m_pe2(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CFlameCanvas::~CFlameCanvas(void) + { + Destroy(); + } +//+------------------------------------------------------------------+ +//| Creates dynamic resource with object | +//+------------------------------------------------------------------+ +bool CFlameCanvas::FlameCreate(const string name,const datetime time,const int future_bars,const int back_bars) + { +//--- get chart parameters + ChartScale(); +//--- create + int width =(int)m_bar_gap*(future_bars+back_bars); + int height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); + if(!CreateBitmap(0,0,name,time-back_bars*PeriodSeconds(),m_chart_price_max,width,height,COLOR_FORMAT_ARGB_NORMALIZE)) + return(false); + ArrayResize(m_flame,width*height); +//--- save parameters + m_future_bars=future_bars; + m_back_bars =back_bars; +//--- settings + PaletteSet(); + m_timeframe =Period(); + m_symbol =Symbol(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Resize | +//+------------------------------------------------------------------+ +bool CFlameCanvas::Resize(void) + { + int x,y; +//--- get limits + double min=ChartGetDouble(0,CHART_PRICE_MIN); + double max=ChartGetDouble(0,CHART_PRICE_MAX); + if(m_chart_price_max!=max) + { + //--- move object + ObjectSetDouble(0,m_objname,OBJPROP_PRICE,0,max); + } +//--- check + if(m_chart_price_min==min && m_chart_price_max==max) + return(false); + m_chart_price_min=min; + m_chart_price_max=max; +//--- grt size + ChartTimePriceToXY(0,0,m_tb1,min,x,y); + int width =(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS)-x; + int height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); +//--- resize + if(width80) g+=dg; + if(i>160) b+=db; + } + } +//+------------------------------------------------------------------+ +//| Draws the flame | +//+------------------------------------------------------------------+ +void CFlameCanvas::FlameDraw(const double &prices[],const int width,const int lenght) + { + static GRADIENT_SIZE sword[]={{100,0},{150,70},{0,100}}; + static GRADIENT_COLOR flame[]={{0x00,0},{0x7F7F7F,12},{0xCCCCCC,30},{0xFFFFFF,45},{0xFFFFFF,55},{0xCCCCCC,70},{0x7F7F7F,88},{0x00,100}}; +//--- draw + CloudDraw(prices,width,lenght,sword,flame); +//--- copy flame buffer + FlameCalculate(); +//--- start timer + EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL); + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void CFlameCanvas::FlameDraw(const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[]) + { +//--- check + int total=ArraySize(m_cloud_axis); + if(total<2) + return; + if(total>lenght) + total=lenght; +//--- draw + int xb,xe; // coordinates of the segment + int ybm,yem; // coordinates of the center line + int yb1,ye1; // coordinates of the first line + int yb2,ye2; // coordinates of the second line +//--- for implementation of variable width + int w_total=ArraySize(size); + if(w_total<2) + return; + int w_i =0; + int w_is=(int)size[w_i].pos*total/100; + int w_ie=(int)size[w_i+1].pos*total/100; + double w =size[w_i].size*width/100; + double dw =(size[w_i+1].size*width/100-w)/(w_ie-w_is); +//--- draw from left to right + xb=0; + ybm=m_cloud_axis[0]; + yb1=ybm-(int)(w/2); + yb2=ybm+(int)(w/2); +//--- draw + for(int i=1;i=m_width) + break; + yb1=ye1; + yb2=ye2; + while(i>=w_ie-1 && i!=total-1) + { + w_i++; + w_is=(int)size[w_i].pos*total/100; + w_ie=(int)size[w_i+1].pos*total/100; + w =size[w_i].size*width/100; + if(w_ie==w_is) + { + //--- for "instant" resize + dw=size[w_i+1].size*width/100-w; + w+=dw; + ye1=yem-(int)(w/2); + ye2=yem+(int)(w/2); + //--- draw the segment of 'cloud' + GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient); + yb1=ye1; + yb2=ye2; + } + else + { + dw=(size[w_i+1].size*width/100-w)/(w_ie-w_is); + break; + } + } + } +//--- copy flame buffer + FlameCalculate(); + } +//+------------------------------------------------------------------+ +//| Sets parameters of the flame and starts to draw | +//+------------------------------------------------------------------+ +void CFlameCanvas::FlameSet(void) + { + m_a1=m_bar_gap*((m_ye1-m_yb1)/((double)m_xe1-m_xb1)); + m_a2=m_bar_gap*((m_ye2-m_yb2)/((double)m_xe2-m_xb2)); + } +//+------------------------------------------------------------------+ +//| Sets parameters of the flame and starts to draw | +//+------------------------------------------------------------------+ +void CFlameCanvas::FlameSet(datetime tb1,double pb1, + datetime te1,double pe1, + datetime tb2,double pb2, + datetime te2,double pe2) + { + datetime obj_time =(datetime)ObjectGetInteger(0,m_objname,OBJPROP_TIME); + double obj_price=ObjectGetDouble(0,m_objname,OBJPROP_PRICE); + int dx,dy; +//--- save parameters + m_tb1=tb1; + m_pb1=pb1; + m_te1=te1; + m_pe1=pe1; + m_tb2=tb2; + m_pb2=pb2; + m_te2=te2; + m_pe2=pe2; +//--- resize + Resize(); +//--- convert + if(ChartTimePriceToXY(0,0,obj_time,obj_price,dx,dy)) + { + dy=m_yb1; + if(ChartTimePriceToXY(0,0,tb1,pb1,m_xb1,m_yb1)) + if(ChartTimePriceToXY(0,0,te1,pe1,m_xe1,m_ye1)) + if(ChartTimePriceToXY(0,0,tb2,pb2,m_xb2,m_yb2)) + if(ChartTimePriceToXY(0,0,te2,pe2,m_xe2,m_ye2)) + { + //--- convert to canvas coordinates + m_xb1-=dx; + m_xe1-=dx; + m_xb2-=dx; + m_xe2-=dx; + //--- + FlameSet(); + } + } +//--- start timer + EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL); + } +//+------------------------------------------------------------------+ +//| Generate array that describes the body of flame | +//+------------------------------------------------------------------+ +void CFlameCanvas::FlameCreate(void) + { + static GRADIENT_SIZE sword[]={{100,0},{150,70},{0,100}}; + static GRADIENT_COLOR flame[]={{0x00,0},{0x7F7F7F,12},{0xCCCCCC,30},{0xFFFFFF,45},{0xFFFFFF,55},{0xCCCCCC,70},{0x7F7F7F,88},{0x00,100}}; +//--- + double a=rand(); // parameter of line a*x+b + double b=rand(); // parameter of line a*x+b + double c=rand(); // parameter of sine c*Sin(d*x) + double d=rand(); // parameter of sine c*Sin(d*x) + int w=rand(); // width at the base + int l=rand(); // length +//--- normalize + a=fmod(a,(m_a2-m_a1))+m_a1; + b=(m_yb1+m_yb2)/2; + c=fmod(c,20); + d=fmod(d,3*M_PI)+M_PI; +//--- shape + w%=150; + if(w<10) + w=10; // but no less than 10 + sword[1].size=w; + w=rand(); + l%=50; + sword[1].pos=l+30; + l=rand(); +//--- sizes + w=(m_yb2-m_yb1!=0) ? w%(m_yb2-m_yb1) : 10; // proportional to the starting width + if(w<10) + w=10; // but no less than 10 + l=l%((m_xe1-m_xb1)/(int)m_bar_gap-20)+20; // proportional to length +//--- create + int total=ArraySize(m_cloud_axis); + for(int i=0;ilenght) + total=lenght; +//--- draw + int xb,xe; // coordinates of the segment + int ybm,yem; // coordinates of the center line + int yb1,ye1; // coordinates of the first line + int yb2,ye2; // coordinates of the second line + int xx; +//--- for implementation of variable width + int w_total=ArraySize(size); + if(w_total<2) + return; + int w_i =0; + int w_is=(int)size[w_i].pos*total/100; + int w_ie=(int)size[w_i+1].pos*total/100; + double w =size[w_i].size*width/100; + double dw =(size[w_i+1].size*width/100-w)/(w_ie-w_is); +//--- draw from left to right + xb=0; + ChartTimePriceToXY(0,0,0,prices[0],xx,ybm); + yb1=ybm-(int)(w/2); + yb2=ybm+(int)(w/2); +//--- draw + for(int i=1;i=m_width) + break; + yb1=ye1; + yb2=ye2; + while(i>=w_ie-1 && i!=total-1) + { + w_i++; + w_is=(int)size[w_i].pos*total/100; + w_ie=(int)size[w_i+1].pos*total/100; + w =size[w_i].size*width/100; + if(w_ie==w_is) + { + //--- for "instant" resize + dw=size[w_i+1].size*width/100-w; + w+=dw; + ye1=yem-(int)(w/2); + ye2=yem+(int)(w/2); + //--- draw the segment of 'cloud' + GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient); + yb1=ye1; + yb2=ye2; + } + else + { + dw=(size[w_i+1].size*width/100-w)/(w_ie-w_is); + break; + } + } + } + } +//+------------------------------------------------------------------+ +//| Draws area with vertical fill using specified gradient | +//+------------------------------------------------------------------+ +void CFlameCanvas::GradientVertical(const int xb,const int xe,const int yb1,const int ye1,const int yb2,const int ye2,const GRADIENT_COLOR &gradient[]) + { +//--- it is assumed that the colors array has sufficient size and positions are already sorted in ascending order +//--- get length by X and Y + int x1 =xb; + int y1 =yb1; + int x2 =xb; + int y2 =yb2; + int dx =(xe>xb)? xe-xb : xb-xe; + int dy1=(ye1>yb1)? ye1-yb1 : yb1-ye1; + int dy2=(ye2>yb2)? ye2-yb2 : yb2-ye2; +//--- get direction by X and Y + int sx =(xb-dy1) + { + //--- try to change X coordinate of the first line + //--- draw the second line + while(x2!=xe || y2!=ye2) + { + //--- calculate coordinates of next pixel of the second line + if((er2<<1)>-dy2) + { + //--- try to change X coordinate of the second line + //--- gradient fill + GradientVerticalLine(x1,y1,y2,gradient); + er2-=dy2; + if(x2!=xe) + x2+=sx; + } + if((er2<<1)0) + { + dd=dy; + dy=1; + } + else + { + dd=-dy; + dy=-1; + } +//--- increments for the color components + dc=(double)((uchar)clr2-clr)/dd; +//--- draw + for(int i=0;y1!=y2;i++,y1+=dy) + { + int idx=y1*m_width+x; + //--- check range + if(idx<0 || idx>=ArraySize(m_flame)) + continue; + if(x>=0 && x=0 && y1m_time_redraw) + { + //--- add the body of flame + FlameCreate(); + //--- draw frame + FlameCalculate(); + Update(); + //--- calculate time for the next frame + m_time_redraw=GetTickCount()+m_delay; + } + //--- generate next event for custom timer + EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL); + break; + } + } +//+------------------------------------------------------------------+ +//| Delay | +//+------------------------------------------------------------------+ +void CFlameCanvas::Delay(const uint value) + { +//--- too small + if(value<10) + return; +//--- start delay + uint cnt=GetTickCount()+value; +//--- delay + while(cnt>=GetTickCount()); + } +//+------------------------------------------------------------------+ diff --git a/Include/ChartObjects/ChartObject.mqh b/Include/ChartObjects/ChartObject.mqh new file mode 100644 index 0000000..bde74b8 --- /dev/null +++ b/Include/ChartObjects/ChartObject.mqh @@ -0,0 +1,1000 @@ +//+------------------------------------------------------------------+ +//| ChartObject.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +//+------------------------------------------------------------------+ +//| 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); + //--- 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); } + //--- method of identifying the object + virtual int Type(void) const { return(0x8888); } + //--- 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(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(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(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(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) + 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 +#include +#include +//+------------------------------------------------------------------+ +//| Class CChartObjectPanel. | +//| Purpose: Class for grouping objects for managing a chart | +//+------------------------------------------------------------------+ +class CChartObjectPanel : public CChartObjectButton + { +protected: + CArrayObj m_attachment; // array of attached objects + CArrayInt m_dX; // array of dX attached objects + CArrayInt m_dY; // array of dY attached objects + bool m_expanded; // collapsed/expanded flag + +public: + CChartObjectPanel(); + ~CChartObjectPanel(); + //--- method for attaching objects + bool Attach(CChartObjectLabel *chart_object); + bool X_Distance(const int X); + bool Y_Distance(const int Y); + int X_Size() const; + int Y_Size() const; + virtual bool Timeframes(const int timeframes); + bool State(const bool state); + bool CheckState(); + +protected: + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +void CChartObjectPanel::CChartObjectPanel(void) : m_expanded(true) + { + } +//+------------------------------------------------------------------+ +//| Destructor. | +//+------------------------------------------------------------------+ +void CChartObjectPanel::~CChartObjectPanel(void) + { +//--- All objects added by the method Add(), deleted automatically + } +//+------------------------------------------------------------------+ +//| Method Attach | +//+------------------------------------------------------------------+ +bool CChartObjectPanel::Attach(CChartObjectLabel *chart_object) + { + if(m_attachment.Add(chart_object)) + { + int x,y; + x=chart_object.X_Distance(); + m_dX.Add(chart_object.X_Distance()); + x+=X_Distance(); + chart_object.X_Distance(X_Distance()+chart_object.X_Distance()); + y=CChartObjectButton::Y_Size(); + y+=chart_object.Y_Distance(); + m_dY.Add(chart_object.Y_Distance()+CChartObjectButton::Y_Size()+2); + chart_object.Y_Distance(Y_Distance()+chart_object.Y_Distance()+CChartObjectButton::Y_Size()+2); + return(true); + } +//--- + return(false); + } +//+------------------------------------------------------------------+ +//| Method X_Distance | +//+------------------------------------------------------------------+ +bool CChartObjectPanel::X_Distance(const int X) + { + CChartObjectLabel *chart_object; +//--- + for(int i=0;i +//+------------------------------------------------------------------+ +//| 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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(EMPTY_VALUE); +//--- 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(0); +//--- 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); + } +//+------------------------------------------------------------------+ diff --git a/Include/Controls/BmpButton.mqh b/Include/Controls/BmpButton.mqh new file mode 100644 index 0000000..080541d --- /dev/null +++ b/Include/Controls/BmpButton.mqh @@ -0,0 +1,268 @@ +//+------------------------------------------------------------------+ +//| BmpButton.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "WndObj.mqh" +#include +//+------------------------------------------------------------------+ +//| 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) + { + } +//+------------------------------------------------------------------+ +//| 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()); + } +//+------------------------------------------------------------------+ diff --git a/Include/Controls/Button.mqh b/Include/Controls/Button.mqh new file mode 100644 index 0000000..08d5a76 --- /dev/null +++ b/Include/Controls/Button.mqh @@ -0,0 +1,146 @@ +//+------------------------------------------------------------------+ +//| Button.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "WndObj.mqh" +#include +//+------------------------------------------------------------------+ +//| Class CButton | +//| Usage: control that is displayed by | +//| the CChartObjectButton object | +//+------------------------------------------------------------------+ +class CButton : public CWndObj + { +private: + CChartObjectButton m_button; // chart object + +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); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CButton::CButton(void) + { + m_color =CONTROLS_BUTTON_COLOR; + m_color_background=CONTROLS_BUTTON_COLOR_BG; + m_color_border =CONTROLS_BUTTON_COLOR_BORDER; + } +//+------------------------------------------------------------------+ +//| 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()); + } +//+------------------------------------------------------------------+ diff --git a/Include/Controls/CheckBox.mqh b/Include/Controls/CheckBox.mqh new file mode 100644 index 0000000..e8186fd --- /dev/null +++ b/Include/Controls/CheckBox.mqh @@ -0,0 +1,183 @@ +//+------------------------------------------------------------------+ +//| CheckBox.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "WndContainer.mqh" +#include "BmpButton.mqh" +#include "Edit.mqh" +//+------------------------------------------------------------------+ +//| Resources | +//+------------------------------------------------------------------+ +#resource "res\\CheckBoxOn.bmp" +#resource "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); + }; +//+------------------------------------------------------------------+ +//| 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) + { + } +//+------------------------------------------------------------------+ +//| 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("::res\\CheckBoxOff.bmp","::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()); + } +//+------------------------------------------------------------------+ diff --git a/Include/Controls/CheckGroup.mqh b/Include/Controls/CheckGroup.mqh new file mode 100644 index 0000000..6d5de34 --- /dev/null +++ b/Include/Controls/CheckGroup.mqh @@ -0,0 +1,377 @@ +//+------------------------------------------------------------------+ +//| CheckGroup.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "WndClient.mqh" +#include "CheckBox.mqh" +#include +#include +#include +//+------------------------------------------------------------------+ +//| Class CCheckGroup | +//| Usage: view and edit group of flags | +//+------------------------------------------------------------------+ +class CCheckGroup : public CWndClient + { +private: + //--- 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(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 + 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) + { + } +//+------------------------------------------------------------------+ +//| 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_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=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