First commit [09/03/2018]
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -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());
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user