First commit [09/03/2018]

This commit is contained in:
Pierre8rTeam
2018-03-09 16:43:19 +01:00
commit 25e9006a0b
375 changed files with 294601 additions and 0 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+347
View File
@@ -0,0 +1,347 @@
//+------------------------------------------------------------------+
//| HistogramChart.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "ChartCanvas.mqh"
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| 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(w<m_bar_min_size)
w=m_bar_min_size;
int x=x1+(int)(m_bar_gap+w*idx);
//--- set font
string fontname;
int fontsize=0;
uint fontflags=0;
uint fontangle=0;
if(IS_SHOW_VALUE)
{
FontGet(fontname,fontsize,fontflags,fontangle);
FontSet(fontname,-10*(w-3),fontflags,900);
}
//--- prepare gradient fill
GradientBrush(w,clr);
//--- draw
for(int i=0;i<total;i++,x+=dx)
{
int y,h;
double val=data[i];
if(val==EMPTY_VALUE)
continue;
if(m_accumulative)
value+=val;
else
value=val;
// int val=(int)(value*m_scale_y);
if(value>0)
{
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)<w)
FillRectangle(x+1,y+1,w-x-2,h-y-2,clr);
else
{
for(int i=1;i<h;i++)
ArrayCopy(m_pixels,m_fill_brush,(y+i)*m_width+x+1,0,w);
}
//--- draw bar border
if(m_bar_border!=0)
Rectangle(x,y,x+w-1,y+h-1,m_color_border);
}
//+------------------------------------------------------------------+
//| Creates brush for gradient fill |
//+------------------------------------------------------------------+
void CHistogramChart::GradientBrush(const int size,const uint fill_clr)
{
//--- to prepare gradient fill, we will use Bresenham's circle algorithm
//--- X coordinate - size of the fill,
//--- Y coordinate - color brightness
if(m_gradient)
{
//--- adjust gradient radius if necessary
int r=size;
//--- check
if(r<1)
return;
if(r!=ArrayResize(m_fill_brush,r))
return;
//--- initialize brush
ArrayInitialize(m_fill_brush,m_color_background);
//--- variables
int f =1-r;
int dd_x=1;
int dd_y=-2*r;
int dx =0;
int dy =r;
int i1,i2;
uint clr,dclr;
//---
i1=i2=r>>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);
}
//+------------------------------------------------------------------+
+383
View File
@@ -0,0 +1,383 @@
//+------------------------------------------------------------------+
//| LineChart.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "ChartCanvas.mqh"
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| 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;i<m_data_total;i++)
{
CArrayDouble *data=m_values.At(i);
if(data==NULL)
continue;
int total=data.Total();
if(total<=1)
continue;
s[i]=CalcArea(i);
}
int index=ArrayMaximum(s);
while(index!=-1 && s[index]!=0.0)
{
//--- draw in area descending order
DrawData(index);
s[index]=0.0;
index=ArrayMaximum(s);
}
}
else
for(uint i=0;i<m_data_total;i++)
DrawData(i);
}
//+------------------------------------------------------------------+
//| Draws lines |
//+------------------------------------------------------------------+
void CLineChart::DrawData(const uint index)
{
double value=0.0;
//--- check
CArrayDouble *data=m_values.At(index);
if(data==NULL)
return;
int total=data.Total();
if(total<=1)
return;
//--- calculate
int dx=m_data_area.Width()/(total-1);
int x=m_data_area.left+1;
int y1=0;
int y2=(int)(m_y_0-data[0]*m_scale_y);
//--- draw
for(int i=1;i<total;i++,x+=dx)
{
y1=y2;
double val=data[i];
if(val==EMPTY_VALUE)
continue;
if(m_accumulative)
value+=val;
else
value=val;
y2=(int)(m_y_0-value*m_scale_y);
if(m_filled)
{
if((y1>m_y_0 && y2<m_y_0) || (y1<m_y_0 && y2>m_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(y1<m_y_0 || y2<m_y_0)
{
if(y1>y2)
FillTriangle(x,y1,x+dx,y2,x+dx,y1,(uint)m_colors[index]);
if(y1<y2)
{
FillTriangle(x,y1,x+dx,y2,x,y2,(uint)m_colors[index]);
y1=y2;
}
}
if(y1>m_y_0 || y2>m_y_0)
{
if(y1<y2)
FillTriangle(x,y1,x+dx,y2,x+dx,y1,(uint)m_colors[index]);
if(y1>y2)
{
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;i<total;i++)
{
y1=y2;
double val=data[i];
if(val==EMPTY_VALUE)
continue;
if(m_accumulative)
value+=val;
else
value=val;
y2=(int)(m_y_0-value*m_scale_y);
if((y1>m_y_0 && y2<m_y_0) || (y1<m_y_0 && y2>m_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(y1<m_y_0 || y2<m_y_0)
{
//--- both values are greater than zero
if(y1>y2)
{
//--- add area of triangle
area+=dx*(y1-y2)/2;
//--- add area of rectangle
area+=dx*(m_y_0-y2);
}
if(y1<y2)
{
//--- add area of triangle
area+=dx*(y2-y1)/2;
//--- add area of rectangle
area+=dx*(m_y_0-y1);
}
}
if(y1>m_y_0 || y2>m_y_0)
{
//--- both values are less than zero
if(y1<y2)
{
//--- add area of triangle
area+=dx*(y2-y1)/2;
//--- add area of rectangle
area+=dx*(y1-m_y_0);
}
if(y1>y2)
{
//--- add area of triangle
area+=dx*(y1-y2)/2;
//--- add area of rectangle
area+=dx*(y2-m_y_0);
}
}
}
//---
return(area);
}
//+------------------------------------------------------------------+
+414
View File
@@ -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_index_size;i++)
{
index=m_index[i];
double val=m_values[index];
double d_a=2*M_PI*val/m_sum;
DrawPie(angle,angle+d_a,i,p0,m_colors[index]);
angle+=d_a;
angle=MathMod(angle,2*M_PI);
}
if(m_data_total!=m_index_size)
DrawPie(angle,angle+2*M_PI*m_others/m_sum,m_index_size,p0,COLOR2RGB(clrBlack));
for(uint i=0;i<=m_index_size;i++)
Line(m_x0,m_y0,p0[i].x,p0[i].y,m_color_border);
Circle(m_x0,m_y0,m_r,m_color_border);
}
//--- draw descriptors
angle=M_PI*(m_data_offset%360)/180;
int r1=(int)round(1.1*m_r);
if(ArrayResize(p1,m_data_total)==-1)
return;
//--- calculations
for(uint i=0;i<m_index_size;i++)
{
index=m_index[i];
angle+=M_PI*m_values[index]/m_sum;
//--- lines
p0[i].x=m_x0+(int)round(m_r*cos(angle));
p0[i].y=m_y0-(int)round(m_r*sin(angle));
p1[i].x=m_x0+(int)round(r1*cos(angle));
p1[i].y=m_y0-(int)round(r1*sin(angle));
angle+=M_PI*m_values[index]/m_sum;
}
if(m_data_total!=m_index_size)
{
index=(int)m_data_total-1;
angle+=M_PI*m_others/m_sum;
p0[index].x=m_x0+(int)round(m_r*cos(angle));
p0[index].y=m_y0-(int)round(m_r*sin(angle));
p1[index].x=m_x0+(int)round(r1*cos(angle));
p1[index].y=m_y0-(int)round(r1*sin(angle));
}
int x,y;
//--- draw descriptors to the left
for(uint i=0;i<m_index_size;i++)
if(p0[i].x<m_x0)
{
x=p1[i].x-10;
y=p1[i].y;
index=m_index[i];
text=LabelMake(m_descriptors[index],m_values[index],true);
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_RIGHT|TA_VCENTER);
}
}
//--- draw descriptors to the right
for(uint i=0;i<m_index_size;i++)
if(p0[i].x>=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);
}
//+------------------------------------------------------------------+
+751
View File
@@ -0,0 +1,751 @@
//+------------------------------------------------------------------+
//| FlameCanvas.mqh |
//| Copyright 2009-2017, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Canvas.mqh"
#include <Controls\Defines.mqh>
//+------------------------------------------------------------------+
//| 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(width<m_width)
width=m_width;
if(width<=0)
return(false);
Resize(width,height);
//--- resize flame buffer
ArrayResize(m_flame,width*height);
ArrayInitialize(m_flame,0);
ArrayInitialize(m_pixels,0);
//--- restore parameters
if(m_pb1!=0.0)
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CFlameCanvas::RatesTotal(const int value)
{
if(value==0)
return;
if(m_rates_total==0)
m_rates_total=value;
else
{
if(m_rates_total!=value)
{
//--- move object
ObjectSetInteger(0,m_objname,OBJPROP_TIME,0,
ObjectGetInteger(0,m_objname,OBJPROP_TIME)+(value-m_rates_total)*PeriodSeconds());
m_rates_total=value;
}
}
}
//+------------------------------------------------------------------+
//| Adjusts to the chart scale |
//+------------------------------------------------------------------+
void CFlameCanvas::ChartScale(void)
{
m_chart_scale=(uint)ChartGetInteger(0,CHART_SCALE);
//--- set params
switch(m_chart_scale)
{
case 0:
m_bar_gap =1;
m_bar_width=1;
break;
case 1:
m_bar_gap =2;
m_bar_width=1;
break;
case 2:
m_bar_gap =4;
m_bar_width=2;
break;
case 3:
m_bar_gap =8;
m_bar_width=4;
break;
case 4:
m_bar_gap =16;
m_bar_width=10;
break;
case 5:
m_bar_gap =32;
m_bar_width=22;
break;
default:
return;
}
}
//+------------------------------------------------------------------+
//| Sets palette |
//+------------------------------------------------------------------+
void CFlameCanvas::PaletteSet(uint clr)
{
//--- create palette
double g=0,b=0,dg=1.45,db=0.63;
//---
for(uint a,i=0;i<256;i++)
{
//--- the first 32 values ??of flame are completely transparent
a=uchar(i<32?0:i-32);
//--- generate color for the i value of flame
m_palette[i]=(a<<24)|(uint(255)<<16)|(uint(g+0.5)<<8)|uint(b+0.5);
//--- increment the color components
//--- the red color gets gradient due to transparency
if(i>80) 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<total;i++)
{
xe=(int)(i*m_bar_gap);
if(m_cloud_axis[i]==DBL_MAX)
continue;
yem=m_cloud_axis[i];
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);
xb=xe;
if(xb>=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;i<total;i++)
m_cloud_axis[i]=int(a*i+b+c*sin(i/d));
//--- draw
FlameDraw(w,l,sword,flame);
}
//+------------------------------------------------------------------+
//| Calculates and renders frame |
//+------------------------------------------------------------------+
void CFlameCanvas::FlameCalculate(void)
{
//--- calculate new frame
int c;
int idx;
//--- draw body of flame to the right
for(int x=0,x_tot=m_width-1;x<x_tot;x++)
{
//--- separately for y==0
c=m_flame[x]+m_flame[x+m_width];
c+=+m_flame[x]+m_flame[x+m_width];
m_flame[x]=uchar(c/4);
//---
for(int y=1,y_tot=m_height-1;y<y_tot;y++)
{
idx=y*m_width+x;
c=m_flame[idx-m_width]+m_flame[idx]+m_flame[idx+m_width];
idx++;
c+=m_flame[idx-m_width]+m_flame[idx]+m_flame[idx+m_width];
m_flame[idx]=uchar(c/6);
}
//--- separately for y==m_height-1
idx=(m_height-1)*m_width+x;
c=m_flame[idx-m_width]+m_flame[idx];
idx++;
c+=m_flame[idx-m_width]+m_flame[idx];
m_flame[idx]=uchar(c/4);
}
//--- move flame to the resource buffer
for(int y=0;y<m_height;y++)
{
for(int x=0;x<m_width;x++)
{
idx=y*m_width+x;
m_pixels[idx]=m_palette[m_flame[idx]];
}
}
//---
}
//+------------------------------------------------------------------+
//| Draws "cloud" |
//+------------------------------------------------------------------+
void CFlameCanvas::CloudDraw(const double &prices[],const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[],const uchar t_level,const bool custom_gradient)
{
//--- check
int total=ArraySize(prices);
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
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<total;i++)
{
xe=(int)(i*m_bar_gap);
if(prices[i]==DBL_MAX)
continue;
ChartTimePriceToXY(0,0,0,prices[i],xx,yem);
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);
xb=xe;
if(xb>=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<xe)? 1 : -1;
int sy1=(yb1<ye1)? 1 : -1;
int sy2=(yb2<ye2)? 1 : -1;
int er1=dx-dy1;
int er2=dx-dy2;
//--- extreme colors
uint clr_first=gradient[0].clr;
uint clr_last =gradient[ArraySize(gradient)-1].clr;
//--- draw the first line
while(x1!=xe || y1!=ye1)
{
//--- calculate coordinates of next pixel of the first line
if((er1<<1)>-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)<dx)
{
er2+=dx;
if(y2!=ye2)
y2+=sy2;
}
//--- draw the first line
if(x1!=x2)
break;
}
er1-=dy1;
if(x1!=xe)
x1+=sx;
}
if((er1<<1)<dx)
{
er1+=dx;
if(y1!=ye1)
y1+=sy1;
}
}
//--- gradient fill
GradientVerticalLine(x1,ye1,ye2,gradient);
}
//+------------------------------------------------------------------+
//| Draws gradient vertical line |
//+------------------------------------------------------------------+
void CFlameCanvas::GradientVerticalLineMonochrome(int x,int y1,int y2,uint clr1,uint clr2)
{
//---
double dc;
int dd,dy=y2-y1;
//--- check
if(dy==0)
return;
//--- extract components from the first color
uchar clr=(uchar)clr1;
//--- parameters of pixels iteration
if(dy>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<m_width && y1>=0 && y1<m_height)
if(m_flame[idx]<(uchar)(clr+dc*i))
m_flame[idx]=(uchar)(clr+dc*i);
}
}
//+------------------------------------------------------------------+
//| Draws vertical line with specified gradient |
//+------------------------------------------------------------------+
void CFlameCanvas::GradientVerticalLine(int x,int y1,int y2,const GRADIENT_COLOR &gradient[])
{
//--- it is assumed that the colors array has sufficient size and positions are already sorted in ascending order
int total=ArraySize(gradient);
int dy=y2-y1;
//--- draw segments
for(int i=0;i<total-1;i++)
GradientVerticalLineMonochrome(x,y1+dy*gradient[i].pos/100,y1+dy*gradient[i+1].pos/100,gradient[i].clr,gradient[i+1].clr);
}
//+------------------------------------------------------------------+
//| Event handler |
//+------------------------------------------------------------------+
void CFlameCanvas::ChartEventHandler(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- events filter
switch(id)
{
case CHARTEVENT_CHART_CHANGE:
//--- handle only chart modification events
if(m_chart_scale!=(uint)ChartGetInteger(0,CHART_SCALE))
{
Delay(20);
//--- changed horizontal scale
ChartScale();
if(m_pb1!=0.0)
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
return;
}
if(m_height!=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS))
{
//--- changed vertical size
Delay(20);
if(m_pb1!=0.0)
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
return;
}
if(m_chart_price_min!=ChartGetDouble(0,CHART_PRICE_MIN) ||
m_chart_price_max!=ChartGetDouble(0,CHART_PRICE_MAX))
{
//--- changed vertical scale
Delay(20);
if(m_pb1!=0.0)
FlameSet(m_tb1,m_pb1,m_te1,m_pe1,m_tb2,m_pb2,m_te2,m_pe2);
return;
}
break;
//--- organize custom timer
case CHARTEVENT_CUSTOM+1302:
//--- time to draw the new frame?
if(GetTickCount()>m_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());
}
//+------------------------------------------------------------------+