Article-17457-MQL5-Optimiza.../Table.mqh

651 行
67 KiB
MQL5

2026-03-24 15:23:43 +07:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Table.mqh |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#include <Arrays\ArrayObj.mqh>
#include <Canvas\Canvas.mqh>
//+------------------------------------------------------------------+
//| ;0AA OG59:8 B01;8FK |
//+------------------------------------------------------------------+
class CTableCell : public CObject
{
private:
int m_row; // !B@>:0
int m_col; // !B>;15F
int m_x; // >>@48=0B0 X
int m_y; // >>@48=0B0 Y
int m_w; // (8@8=0
int m_h; // KA>B0
string m_text; // "5:AB 2 OG59:5
color m_fore_color; // &25B B5:AB0 2 OG59:5
public:
//--- 5B>4K CAB0=>2:8 7=0G5=89
void SetRow(const uint row) { this.m_row=(int)row; }
void SetColumn(const uint col) { this.m_col=(int)col; }
void SetX(const uint x) { this.m_x=(int)x; }
void SetY(const uint y) { this.m_y=(int)y; }
void SetXY(const uint x,const uint y)
{
this.m_x=(int)x;
this.m_y=(int)y;
}
void SetWidth(const uint w) { this.m_w=(int)w; }
void SetHeight(const uint h) { this.m_h=(int)h; }
void SetSize(const uint w,const uint h)
{
this.m_w=(int)w;
this.m_h=(int)h;
}
void SetText(const string text) { this.m_text=text; }
//--- 5B>4K ?>;CG5=8O 7=0G5=89
int Row(void) const { return this.m_row; }
int Column(void) const { return this.m_col; }
int X(void) const { return this.m_x; }
int Y(void) const { return this.m_y; }
int Width(void) const { return this.m_w; }
int Height(void) const { return this.m_h; }
string Text(void) const { return this.m_text; }
//--- K2>48B B5:AB, 70?8A0==K9 2 A2>9AB20E OG59:8 =0 :0=20A, C:070B5;L =0 :>B>@K9 ?5@540= 2 <5B>4
void TextOut(CCanvas *canvas, const int x_shift, const int y_shift, const color bg_color=clrNONE, const uint flags=0, const uint alignment=0)
{
if(canvas==NULL)
return;
//--- 0?><=8< B5:CI85 D;038 H@8DB0
uint flags_prev=canvas.FontFlagsGet();
//--- #AB0=>28< F25B D>=0
uint clr=(bg_color==clrNONE ? 0x00FFFFFF : ::ColorToARGB(bg_color));
//--- 0;LQ< CAB0=>2;5==K< F25B>< D>=0 OG59:C (A>B@Q< ?@>H;CN =04?8AL)
canvas.FillRectangle(this.m_x+1, this.m_y+1, this.m_x+this.m_w-1, this.m_y+this.m_h-1, clr);
//--- #AB0=>28< D;038 H@8DB0
canvas.FontFlagsSet(flags);
//--- K2545< B5:AB 2 OG59:C
canvas.TextOut(this.m_x+x_shift, this.m_y+y_shift, this.m_text, ::ColorToARGB(this.m_fore_color), alignment);
//--- >72@0I05< @0=55 70?><=5==K5 D;038 H@8DB0 8 >1=>2;O5< :0=20A
canvas.FontFlagsSet(flags_prev);
canvas.Update(false);
}
//--- 8@BC0;L=K9 <5B>4 A@02=5=8O 42CE >1J5:B>2
virtual int Compare(const CObject *node,const int mode=0) const
{
const CTableCell *compared=node;
return(this.Column()>compared.Column() ? 1 : this.Column()<compared.Column() ? -1 : 0);
}
//--- >=AB@C:B>@/45AB@C:B>@
CTableCell(const int row,const int column) : m_row(row),m_col(column){}
~CTableCell(void){}
};
//+------------------------------------------------------------------+
//| ;0AA AB@>: B01;8F |
//+------------------------------------------------------------------+
class CTableRow : public CObject
{
private:
CArrayObj m_list_cell; // !?8A>: OG55:
int m_row; // ><5@ AB@>:8
int m_y; // >>@48=0B0 Y
public:
//--- >72@0I05B A?8A>: OG55: B01;8FK 2 AB@>:5
CArrayObj *GetListCell(void) { return &this.m_list_cell; }
//--- >72@0I05B (1) :>;8G5AB2> OG55: B01;8FK 2 AB@>:5 (2) 8=45:A AB@>:8 2 B01;8F5
int CellsTotal(void) const { return this.m_list_cell.Total(); }
int Row(void) const { return this.m_row; }
//--- (1) #AB0=02;8205B, (2) 2>72@0I05B :>>@48=0BC Y AB@>:8
void SetY(const int y) { this.m_y=y; }
int Y(void) const { return this.m_y; }
//--- >102;O5B =>2CN OG59:C B01;8FK 2 AB@>:C
bool AddCell(CTableCell *cell)
{
this.m_list_cell.Sort();
if(this.m_list_cell.Search(cell)!=WRONG_VALUE)
{
::PrintFormat("%s: Table cell with index %lu is already in the list",__FUNCTION__,cell.Column());
return false;
}
if(!this.m_list_cell.InsertSort(cell))
{
::PrintFormat("%s: Failed to add table cell with index %lu to list",__FUNCTION__,cell.Column());
return false;
}
return true;
}
//--- >72@0I05B C:070B5;L =0 C:070==CN OG59:C 2 AB@>:5
CTableCell *GetCell(const int column)
{
const CTableCell *obj=new CTableCell(this.m_row,column);
int index=this.m_list_cell.Search(obj);
delete obj;
return this.m_list_cell.At(index);
}
//--- 8@BC0;L=K9 <5B>4 A@02=5=8O 42CE >1J5:B>2
virtual int Compare(const CObject *node,const int mode=0) const
{
const CTableRow *compared=node;
return(this.Row()>compared.Row() ? 1 : this.Row()<compared.Row() ? -1 : 0);
}
//--- >=AB@C:B>@/45AB@C:B>@
CTableRow(const int row) : m_row(row) { this.m_list_cell.Clear(); }
~CTableRow(void) { this.m_list_cell.Clear(); }
};
//+------------------------------------------------------------------+
//| ;0AA 40==KE B01;8F |
//+------------------------------------------------------------------+
class CTableData : public CObject
{
private:
CArrayObj m_list_rows; // !?8A>: AB@>:
int m_id; // 45=B8D8:0B>@ B01;8FK
int m_x1; // >>@48=0B0 X1
int m_y1; // >>@48=0B0 Y1
int m_x2; // >>@48=0B0 X2
int m_y2; // >>@48=0B0 Y2
int m_w; // (8@8=0
int m_h; // KA>B0
string m_name; // 08<5=>20=85 B01;8FK
public:
//--- #AB0=02;8205B (1) 845=B8D8:0B>@, (2) =08<5=>20=85 B01;8FK
void SetID(const int id) { this.m_id=id; }
void SetName(const string name) { this.m_name=name; }
//--- >72@0I05B (1) 845=B8D8:0B>@, (2) =08<5=>20=85 B01;8FK
int ID(void) const { return this.m_id; }
string Name(void) const { return this.m_name; }
//--- #AB0=02;8205B :>>@48=0BC (1) X1, (2) X2
void SetX1(const int x1) { this.m_x1=x1; }
void SetX2(const int x2) { this.m_x2=x2; }
//--- #AB0=02;8205B :>>@48=0BC (1) Y1, (2) Y2
void SetY1(const int y1) { this.m_y1=y1; }
void SetY2(const int y2) { this.m_y2=y2; }
//--- #AB0=02;8205B :>>@48=0BK B01;8FK
void SetCoords(const int x1,const int y1,const int x2,const int y2)
{
this.SetX1(x1);
this.SetY1(y1);
this.SetX2(x2);
this.SetY2(y2);
}
//--- >72@0I05B :>>@48=0BC (1) X1, (2) X2
int X1(void) const { return this.m_x1; }
int X2(void) const { return this.m_x2; }
//--- >72@0I05B :>>@48=0BC (1) Y1, (2) Y2
int Y1(void) const { return this.m_y1; }
int Y2(void) const { return this.m_y2; }
//--- >72@0I05B (1) H8@8=C, (2) 2KA>BC
int Width(void) const { return this.m_x2-this.m_x1+1; }
int Height(void) const { return this.m_y2-this.m_y1+1; }
//--- >72@0I05B A?8A>: AB@>: B01;8FK
CArrayObj *GetListRows(void) { return &this.m_list_rows; }
//--- >102;O5B =>2CN AB@>:C 2 B01;8FC
bool AddRow(CTableRow *row)
{
//--- #AB0=02;8205< D;03 A>@B8@>20==>3> A?8A:0
this.m_list_rows.Sort();
//--- A;8 B0:>9 >1J5:B C65 5ABL 2 A?8A:5 (?>8A: 25@=C; 8=45:A >1J5:B0, 0 =5 -1),
//--- A>>1I05< >1 MB>< 2 6C@=0; 8 2>72@0I05< false
if(this.m_list_rows.Search(row)!=WRONG_VALUE)
{
::PrintFormat("%s: Table row with index %lu is already in the list",__FUNCTION__,row.Row());
return false;
}
//--- A;8 =5 C40;>AL 4>1028BL C:070B5;L 2 A>@B8@>20==K9 A?8A>: - A>>1I05< >1 MB>< 2 6C@=0; 8 2>72@0I05< false
if(!this.m_list_rows.InsertSort(row))
{
::PrintFormat("%s: Failed to add table cell with index %lu to list",__FUNCTION__,row.Row());
return false;
}
//--- #A?5H=> - 2>72@0I05< true
return true;
}
//--- >72@0I05B C:070B5;L =0 (1) C:070==CN AB@>:C, (2) C:070==CN OG59:C 2 C:070==>9 AB@>:5 B01;8FK
CTableRow *GetRow(const int index) { return this.m_list_rows.At(index);}
CTableCell *GetCell(const int row,const int column)
{
//--- >;CG05< C:070B5;L =0 >1J5:B-AB@>:C 2 A?8A:5 AB@>:
CTableRow *row_obj=this.GetRow(row);
//--- A;8 >1J5:B ?>;CG8BL =5 C40;>AL - 2>72@0I05< NULL
if(row_obj==NULL)
return NULL;
//--- >;CG05< C:070B5;L =0 >1J5:B-OG59:C 2 AB@>:5 ?> =><5@C AB>;1F0 8
CTableCell *cell=row_obj.GetCell(column);
//--- 2>72@0I05< @57C;LB0B (C:070B5;L =0 >1J5:B, ;81> NULL)
return cell;
}
//--- 0?8AK205B 2 ?5@540==K5 2 <5B>4 ?5@5<5==K5 :>>@48=0BK X 8 Y C:070==>9 OG59:8 B01;8FK
void CellXY(const uint row,const uint column, int &x, int &y)
{
x=WRONG_VALUE;
y=WRONG_VALUE;
CTableCell *cell=this.GetCell(row,column);
if(cell==NULL)
return;
x=cell.X();
y=cell.Y();
}
//--- >72@0I05B :>>@48=0BC X C:070==>9 OG59:8 B01;8FK
int CellX(const uint row,const uint column)
{
CTableCell *cell=this.GetCell(row,column);
return(cell!=NULL ? cell.X() : WRONG_VALUE);
}
//--- >72@0I05B :>>@48=0BC Y C:070==>9 OG59:8 B01;8FK
int CellY(const uint row,const uint column)
{
CTableCell *cell=this.GetCell(row,column);
return(cell!=NULL ? cell.Y() : WRONG_VALUE);
}
//--- >72@0I05B :>;8G5AB2> (1) AB@>:, (2) AB>;1F>2 2 C:070==>9 AB@>:5
int RowsTotal(void) { return this.m_list_rows.Total(); }
int ColumnsInRow(const int row_index)
{
//--- A;8 2 A?8A:5 =5B =8 >4=>9 AB@>:8 - 2>72@0I05< 0
if(this.RowsTotal()==0)
return 0;
//--- >;CG05< C:070B5;L =0 C:070==CN AB@>:C 8 2>72@0I05< :>;8G5AB2> OG55: 2 =59
CTableRow *row=this.GetRow(row_index);
return(row!=NULL ? row.CellsTotal() : 0);
}
//--- >72@0I05B >1I55 :>;8G5AB2> OG55: B01;8FK
int CellsTotal(void)
{
//--- A;8 2 A?8A:5 =5B =8 >4=>9 AB@>:8 - 2>72@0I05< 0
if(this.RowsTotal()==0)
return 0;
//---
int num=0;
int total=this.RowsTotal();
for(int i=0;i<total;i++)
num+=this.ColumnsInRow(i);
return num;
}
//--- G8I05B A?8A:8 AB@>: 8 OG55: B01;8FK
void Clear(void)
{
//---  F8:;5 ?> :>;8G5AB2C AB@>: 2 A?8A:5 AB@>: B01;8FK
for(int i=0;i<this.m_list_rows.Total();i++)
{
//--- ?>;CG05< C:070B5;L =0 >G5@54=CN AB@>:C
CTableRow *row=this.m_list_rows.At(i);
if(row==NULL)
continue;
//--- 87 ?>;CG5==>3> >1J5:B0-AB@>:8 ?>;CG05< A?8A>: OG55:,
CArrayObj *list_cell=row.GetListCell();
//--- >G8I05< A?8A>: OG55:
if(list_cell!=NULL)
list_cell.Clear();
}
//--- G8I05< A?8A>: AB@>:
this.m_list_rows.Clear();
}
//--- 0A?5G0BK205B 2 6C@=0; 40==K5 OG55: B01;8FK
void Print(const uint tabulation=0)
{
//--- 5G0B05< 2 6C@=0; 703>;>2>:
::PrintFormat("Table %lu: Rows: %lu, Columns: %lu",this.m_id,this.RowsTotal(),this.CellsTotal()/(this.RowsTotal()!=0 ? this.RowsTotal() : 1));
//---  F8:;5 ?> AB@>:0< B01;8FK
for(int r=0;r<this.RowsTotal();r++)
//--- 2 F8:;5 ?> OG59:0< >G5@54=>9 AB@>:8
for(int c=0;c<this.ColumnsInRow(r);c++)
{
//--- ?>;CG05< C:070B5;L =0 >G5@54=CN OG59:C 8 2K2>48< 2 6C@=0; 5Q 40==K5
CTableCell *cell=this.GetCell(r,c);
if(cell!=NULL)
::PrintFormat("%*s%-5s %-4lu %-8s %-6lu %-8s %-6lu %-8s %-4lu",tabulation,"","Row",r,"Column",c,"Cell X:",cell.X(),"Cell Y:",cell.Y());
}
}
//--- 8@BC0;L=K9 <5B>4 A@02=5=8O 42CE >1J5:B>2
virtual int Compare(const CObject *node,const int mode=0) const
{
const CTableData *compared=node;
if(mode==0)
return(this.ID()>compared.ID() ? 1 : this.ID()<compared.ID() ? -1 : 0);
else
return(this.Name()==compared.Name() ? 0 : this.Name()>compared.Name() ? 1 : -1);
}
//--- >=AB@C:B>@/45AB@C:B>@
CTableData(void) : m_id(-1) { this.m_list_rows.Clear(); this.m_name=""; }
CTableData(const uint id) : m_id((int)id) { this.m_list_rows.Clear(); this.m_name=""; }
~CTableData(void) { this.m_list_rows.Clear(); }
};
//+------------------------------------------------------------------+
//| ;0AA C?@02;5=8O B01;8F0<8 |
//+------------------------------------------------------------------+
class CTableDataControl : public CTableData
{
protected:
uchar m_alpha;
color m_fore_color;
//--- @5>1@07C5B RGB 2 color
color RGBToColor(const double r,const double g,const double b) const;
//--- 0?8AK205B 2 ?5@5<5==K5 7=0G5=8O :><?>=5=B>2 RGB
void ColorToRGB(const color clr,double &r,double &g,double &b);
//--- >72@0I05B A>AB02;ONICN F25B0 (1) Red, (2) Green, (3) Blue
double GetR(const color clr) { return clr&0xff ; }
double GetG(const color clr) { return(clr>>8)&0xff; }
double GetB(const color clr) { return(clr>>16)&0xff; }
//--- >72@0I05B =>2K9 F25B
color NewColor(color base_color, int shift_red, int shift_green, int shift_blue);
public:
//--- >72@0I05B C:070B5;L =0 A51O
CTableDataControl*Get(void) { return &this; }
//--- (1) #AB0=02;8205B, (2) 2>72@0I05B ?@>7@0G=>ABL
void SetAlpha(const uchar alpha) { this.m_alpha=alpha; }
uchar Alpha(void) const { return this.m_alpha; }
//--- 8AC5B (1) D>=>2CN A5B:C, (2) A 02B><0B8G5A:8< @07<5@>< OG55:
void DrawGrid(CCanvas *canvas,const int x,const int y,const uint header_h,const uint rows,const uint columns,const uint row_size,const uint col_size,
const color line_color=clrNONE,bool alternating_color=true);
void DrawGridAutoFill(CCanvas *canvas,const uint border,const uint header_h,const uint rows,const uint columns,const color line_color=clrNONE,bool alternating_color=true);
//--- K2>48B (1) B5:AB>2>5 A>>1I5=85, (2) 70:@0H5==K9 ?@O<>C3>;L=8: 2 C:070==K5 :>>@48=0BK
void DrawText(CCanvas *canvas,const string text,const int x,const int y,const color clr=clrNONE,const uint align=0,const int width=WRONG_VALUE,const int height=WRONG_VALUE);
void DrawRectangleFill(CCanvas *canvas,const int x,const int y,const int width,const int height,const color clr,const uchar alpha);
//--- >=AB@C:B>@K/5AB@C:B>@
CTableDataControl (const uint id) : CTableData(id), m_fore_color(clrDimGray), m_alpha(255) {}
CTableDataControl (void) : m_alpha(255) {}
~CTableDataControl (void) {}
};
//+------------------------------------------------------------------+
//| 8AC5B D>=>2CN A5B:C |
//+------------------------------------------------------------------+
void CTableDataControl::DrawGrid(CCanvas *canvas,const int x,const int y,const uint header_h,const uint rows,const uint columns,const uint row_size,const uint col_size,
const color line_color=clrNONE,bool alternating_color=true)
{
//--- G8I05< 2A5 A?8A:8 >1J5:B0 B01;8G=KE 40==KE (C40;O5< OG59:8 87 AB@>: 8 2A5 AB@>:8)
this.Clear();
//--- KA>B0 AB@>:8 =5 <>65B 1KBL <5=LH5 2
int row_h=int(row_size<2 ? 2 : row_size);
//--- (8@8=0 AB>;1F0 =5 <>65B 1KBL <5=LH5 2
int col_w=int(col_size<2 ? 2 : col_size);
//--- 520O :>>@48=0B0 (X1) B01;8FK
int x1=x;
//--- 0AAG8BK205< :>>@48=0BC X2 (A?@020) 2 7028A8<>AB8 >B :>;8G5AB20 AB>;1F>2 8 8E H8@8=K
int x2=x1+col_w*int(columns>0 ? columns : 1);
//--- >>@48=0B0 Y1 =0E>48BAO ?>4 >1;0ABLN 703>;>2:0 ?0=5;8
int y1=(int)header_h+y;
//--- 0AAG8BK205< :>>@48=0BC Y2 (A=87C) 2 7028A8<>AB8 >B :>;8G5AB20 AB@>: 8 8E 2KA>BK
int y2=y1+row_h*int(rows>0 ? rows : 1);
//--- #AB0=02;8205< :>>@48=0BK B01;8FK
this.SetCoords(x1,y1-header_h,x2,y2-header_h);
//--- >;CG05< F25B ;8=89 A5B:8 B01;8FK, ;81> ?> C<>;G0=8N, ;81> ?5@540==K9 2 <5B>4
color clr=(line_color==clrNONE ? C'200,200,200' : line_color);
//--- 8AC5< @0<:C B01;8FK
canvas.Rectangle(x1,y1,x2,y2,::ColorToARGB(clr,this.m_alpha));
//---  F8:;5 ?> AB@>:0< B01;8FK
for(int i=0;i<(int)rows;i++)
{
//--- @0AAG8BK205< :>>@48=0BC Y >G5@54=>9 3>@87>=B0;L=>9 ;8=88 A5B:8 (:>>@48=0B0 Y >G5@54=>9 AB@>:8 B01;8FK)
int row_y=y1+row_h*i;
//--- 5A;8 ?5@540= D;03 "G5@54CNI8EAO" F25B>2 AB@>: 8 AB@>:0 GQB=0O
if(alternating_color && i%2==0)
{
//--- >A25B;O5< F25B D>=0 B01;8FK 8 @8AC5< D>=>2K9 ?@O<>C3>;L=8:
color new_color=this.NewColor(clr,45,45,45);
canvas.FillRectangle(x1+1,row_y+1,x2-1,row_y+row_h-1,::ColorToARGB(new_color,this.m_alpha));
}
//--- 8AC5< 3>@87>=B0;L=CN ;8=8N A5B:8 B01;8FK
canvas.Line(x1,row_y,x2,row_y,::ColorToARGB(clr,this.m_alpha));
//--- !>740Q< =>2K9 >1J5:B AB@>:8 B01;8FK
CTableRow *row_obj=new CTableRow(i);
if(row_obj==NULL)
{
::PrintFormat("%s: Failed to create table row object at index %lu",(string)__FUNCTION__,i);
continue;
}
//--- >102;O5< 53> 2 A?8A>: AB@>: >1J5:B0 B01;8G=KE 40==KE
//--- (5A;8 4>1028BL >1J5:B =5 C40;>AL - C40;O5< A>740==K9 >1J5:B)
if(!this.AddRow(row_obj))
delete row_obj;
//--- #AB0=02;8205< 2 A>740==>< >1J5:B5-AB@>:5 53> :>>@48=0BC Y A CGQB>< A<5I5=8O >B 703>;>2:0 ?0=5;8
row_obj.SetY(row_y-header_h);
}
//---  F8:;5 ?> AB>;1F0< B01;8FK
for(int i=0;i<(int)columns;i++)
{
//--- @0AAG8BK205< :>>@48=0BC X >G5@54=>9 25@B8:0;L=>9 ;8=88 A5B:8 (:>>@48=0B0 X >G5@54=>3> AB>;1F0 B01;8FK)
int col_x=x1+col_w*i;
//--- A;8 ;8=8O A5B:8 2KH;0 70 ?@545;K ?0=5;8 - ?@5@K205< F8:;
if(x1==1 && col_x>=x1+canvas.Width()-2)
break;
//--- 8AC5< 25@B8:0;L=CN ;8=8N A5B:8 B01;8FK
canvas.Line(col_x,y1,col_x,y2,::ColorToARGB(clr,this.m_alpha));
//--- >;CG05< 87 >1J5:B0 B01;8G=KE 40==KE :>;8G5AB2> A>740==KE AB@>:
int total=this.RowsTotal();
//---  F8:;5 ?> AB@>:0< B01;8FK
for(int j=0;j<total;j++)
{
//--- ?>;CG05< >G5@54=CN AB@>:C
CTableRow *row=this.GetRow(j);
if(row==NULL)
continue;
//--- !>740Q< =>2CN OG59:C B01;8FK
CTableCell *cell=new CTableCell(row.Row(),i);
if(cell==NULL)
{
::PrintFormat("%s: Failed to create table cell object at index %lu",(string)__FUNCTION__,i);
continue;
}
//--- >102;O5< A>740==CN OG59:C 2 AB@>:C
//--- (5A;8 4>1028BL >1J5:B =5 C40;>AL - C40;O5< A>740==K9 >1J5:B)
if(!row.AddCell(cell))
{
delete cell;
continue;
}
//--- #AB0=02;8205< 2 A>740==>< >1J5:B5-OG59:5 53> :>>@48=0BC X 8 :>>@48=0BC Y 87 >1J5:B0-AB@>:8
cell.SetXY(col_x,row.Y());
cell.SetSize(col_w, row_h);
}
}
//--- 1=>2;O5< :0=20A 157 ?5@5@8A>2:8 3@0D8:0
canvas.Update(false);
}
//+------------------------------------------------------------------+
//| 8AC5B D>=>2CN A5B:C A 02B><0B8G5A:8< @07<5@>< OG55: |
//+------------------------------------------------------------------+
void CTableDataControl::DrawGridAutoFill(CCanvas *canvas,const uint border,const uint header_h,const uint rows,const uint columns,const color line_color=clrNONE,bool alternating_color=true)
{
//--- >>@48=0B0 X1 (;520O) B01;8FK
int x1=(int)border;
//--- >>@48=0B0 X2 (?@020O) B01;8FK
int x2=canvas.Width()-(int)border-1;
//--- >>@48=0B0 Y1 (25@E=OO) B01;8FK
int y1=int(header_h+border-1);
//--- >>@48=0B0 Y2 (=86=OO) B01;8FK
int y2=canvas.Height()-(int)border-1;
//--- #AB0=02;8205< :>>@48=0BK B01;8FK
this.SetCoords(x1,y1,x2,y2);
//--- >;CG05< F25B ;8=89 A5B:8 B01;8FK, ;81> ?> C<>;G0=8N, ;81> ?5@540==K9 2 <5B>4
color clr=(line_color==clrNONE ? C'200,200,200' : line_color);
//--- A;8 >BABC? >B :@0O ?0=5;8 1>;LH5 =C;O - @8AC5< @0<:C B01;8FK
//--- 8=0G5 - @0<:>9 B01;8FK 2KABC?05B @0<:0 ?0=5;8
if(border>0)
canvas.Rectangle(x1,y1,x2,y2,::ColorToARGB(clr,this.m_alpha));
//--- KA>B0 2A59 A5B:8 B01;8FK
int greed_h=y2-y1;
//--- 0AAG8BK205< 2KA>BC AB@>:8 2 7028A8<>AB8 >B 2KA>BK B01;8FK 8 :>;8G5AB20 AB@>:
int row_h=(int)::round((double)greed_h/(double)rows);
//---  F8:;5 ?> :>;8G5AB2C AB@>:
for(int i=0;i<(int)rows;i++)
{
//--- @0AAG8BK205< :>>@48=0BC Y >G5@54=>9 3>@87>=B0;L=>9 ;8=88 A5B:8 (:>>@48=0B0 Y >G5@54=>9 AB@>:8 B01;8FK)
int row_y=y1+row_h*i;
//--- 5A;8 ?5@540= D;03 "G5@54CNI8EAO" F25B>2 AB@>: 8 AB@>:0 GQB=0O
if(alternating_color && i%2==0)
{
//--- >A25B;O5< F25B D>=0 B01;8FK 8 @8AC5< D>=>2K9 ?@O<>C3>;L=8:
color new_color=this.NewColor(clr,45,45,45);
canvas.FillRectangle(x1+1,row_y+1,x2-1,row_y+row_h-1,::ColorToARGB(new_color,this.m_alpha));
}
//--- 8AC5< 3>@87>=B0;L=CN ;8=8N A5B:8 B01;8FK
canvas.Line(x1,row_y,x2,row_y,::ColorToARGB(clr,this.m_alpha));
//--- !>740Q< =>2K9 >1J5:B AB@>:8 B01;8FK
CTableRow *row_obj=new CTableRow(i);
if(row_obj==NULL)
{
::PrintFormat("%s: Failed to create table row object at index %lu",(string)__FUNCTION__,i);
continue;
}
//--- >102;O5< 53> 2 A?8A>: AB@>: >1J5:B0 B01;8G=KE 40==KE
//--- (5A;8 4>1028BL >1J5:B =5 C40;>AL - C40;O5< A>740==K9 >1J5:B)
if(!this.AddRow(row_obj))
delete row_obj;
//--- #AB0=02;8205< 2 A>740==>< >1J5:B5-AB@>:5 53> :>>@48=0BC Y A CGQB>< A<5I5=8O >B 703>;>2:0 ?0=5;8
row_obj.SetY(row_y-header_h);
}
//--- (8@8=0 A5B:8 B01;8FK
int greed_w=x2-x1;
//--- 0AAG8BK205< H8@8=C AB>;1F0 2 7028A8<>AB8 >B H8@8=K B01;8FK 8 :>;8G5AB20 AB>;1F>2
int col_w=(int)::round((double)greed_w/(double)columns);
//---  F8:;5 ?> AB>;1F0< B01;8FK
for(int i=0;i<(int)columns;i++)
{
//--- @0AAG8BK205< :>>@48=0BC X >G5@54=>9 25@B8:0;L=>9 ;8=88 A5B:8 (:>>@48=0B0 X >G5@54=>3> AB>;1F0 B01;8FK)
int col_x=x1+col_w*i;
//--- A;8 MB> =5 A0<0O ?5@20O 25@B8:0;L=0O ;8=8O - @8AC5< 5Q
//--- (?5@2>9 25@B8:0;L=>9 ;8=859 2KABC?05B ;81> @0<:0 B01;8FK, ;81> @0<:0 ?0=5;8)
if(i>0)
canvas.Line(col_x,y1,col_x,y2,::ColorToARGB(clr,this.m_alpha));
//--- >;CG05< 87 >1J5:B0 B01;8G=KE 40==KE :>;8G5AB2> A>740==KE AB@>:
int total=this.RowsTotal();
//---  F8:;5 ?> AB@>:0< B01;8FK
for(int j=0;j<total;j++)
{
//--- ?>;CG05< >G5@54=CN AB@>:C
CTableRow *row=this.GetRow(j);
if(row==NULL)
continue;
//--- !>740Q< =>2CN OG59:C B01;8FK
CTableCell *cell=new CTableCell(row.Row(),i);
if(cell==NULL)
{
::PrintFormat("%s: Failed to create table cell object at index %lu",(string)__FUNCTION__,i);
continue;
}
//--- >102;O5< A>740==CN OG59:C 2 AB@>:C
//--- (5A;8 4>1028BL >1J5:B =5 C40;>AL - C40;O5< A>740==K9 >1J5:B)
if(!row.AddCell(cell))
{
delete cell;
continue;
}
//--- #AB0=02;8205< 2 A>740==>< >1J5:B5-OG59:5 53> :>>@48=0BC X 8 :>>@48=0BC Y 87 >1J5:B0-AB@>:8
cell.SetXY(col_x,row.Y());
cell.SetSize(col_w, row_h);
}
}
//--- 1=>2;O5< :0=20A 157 ?5@5@8A>2:8 3@0D8:0
canvas.Update(false);
}
//+------------------------------------------------------------------+
//| >72@0I05B F25B A =>2>9 F25B>2>9 A>AB02;ONI59 |
//+------------------------------------------------------------------+
color CTableDataControl::NewColor(color base_color, int shift_red, int shift_green, int shift_blue)
{
double clR=0, clG=0, clB=0;
this.ColorToRGB(base_color,clR,clG,clB);
double clRn=(clR+shift_red < 0 ? 0 : clR+shift_red > 255 ? 255 : clR+shift_red);
double clGn=(clG+shift_green< 0 ? 0 : clG+shift_green> 255 ? 255 : clG+shift_green);
double clBn=(clB+shift_blue < 0 ? 0 : clB+shift_blue > 255 ? 255 : clB+shift_blue);
return this.RGBToColor(clRn,clGn,clBn);
}
//+------------------------------------------------------------------+
//| @5>1@07C5B RGB 2 color |
//+------------------------------------------------------------------+
color CTableDataControl::RGBToColor(const double r,const double g,const double b) const
{
int int_r=(int)::round(r);
int int_g=(int)::round(g);
int int_b=(int)::round(b);
int clr=0;
clr=int_b;
clr<<=8;
clr|=int_g;
clr<<=8;
clr|=int_r;
//---
return (color)clr;
}
//+------------------------------------------------------------------+
//| >;CG5=85 7=0G5=89 :><?>=5=B>2 RGB |
//+------------------------------------------------------------------+
void CTableDataControl::ColorToRGB(const color clr,double &r,double &g,double &b)
{
r=GetR(clr);
g=GetG(clr);
b=GetB(clr);
}
//+------------------------------------------------------------------+
//| K2>48B B5:AB>2>5 A>>1I5=85 2 C:070==K5 :>>@48=0BK |
//+------------------------------------------------------------------+
void CTableDataControl::DrawText(CCanvas *canvas,const string text,const int x,const int y,const color clr=clrNONE,const uint align=0,const int width=WRONG_VALUE,const int height=WRONG_VALUE)
{
//--- 1JO28< ?5@5<5==K5 4;O 70?8A8 2 =8E H8@8=K 8 2KA>BK B5:AB0
int w=width;
int h=height;
//--- A;8 H8@8=0 8 2KA>B0 B5:AB0, ?5@540==K5 2 <5B>4, 8<5NB =C;52K5 7=0G5=8O,
//--- B> ?>;=>ABLN >G8I05BAO 2AQ ?@>AB@0=AB2> :0=20A0 ?@>7@0G=K< F25B><
if(width==0 && height==0)
canvas.Erase(0x00FFFFFF);
//--- =0G5
else
{
//--- A;8 ?5@540==K5 H8@8=0 8 2KA>B0 8<5NB 7=0G5=8O ?> C<>;G0=8N (-1) - ?>;CG05< 87 B5:AB0 53> H8@8=C 8 2KA>BC
if(width==WRONG_VALUE && height==WRONG_VALUE)
canvas.TextSize(text,w,h);
//--- 8=0G5,
else
{
//--- 5A;8 H8@8=0, ?5@540==0O 2 <5B>4, 8<55B 7=0G5=85 ?> C<>;G0=8N (-1) - ?>;CG05< H8@8=C 87 B5:AB0, ;81>
//--- 5A;8 H8@8=0, ?5@540==0O 2 <5B>4, 8<55B 7=0G5=85 1>;LH5 =C;O - 8A?>;L7C5< ?5@540==CN 2 <5B>4 H8@8=C, ;81>
//--- 5A;8 H8@8=0, ?5@540==0O 2 <5B>4, 8<55B =C;52>5 7=0G5=85, 8A?>;L7C5< 7=0G5=85 1 4;O H8@8=K
w=(width ==WRONG_VALUE ? canvas.TextWidth(text) : width>0 ? width : 1);
//--- 5A;8 2KA>B0, ?5@540==0O 2 <5B>4, 8<55B 7=0G5=85 ?> C<>;G0=8N (-1) - ?>;CG05< 2KA>BC 87 B5:AB0, ;81>
//--- 5A;8 2KA>B0, ?5@540==0O 2 <5B>4, 8<55B 7=0G5=85 1>;LH5 =C;O - 8A?>;L7C5< ?5@540==CN 2 <5B>4 2KA>BC, ;81>
//--- 5A;8 2KA>B0, ?5@540==0O 2 <5B>4, 8<55B =C;52>5 7=0G5=85, 8A?>;L7C5< 7=0G5=85 1 4;O 2KA>BK
h=(height==WRONG_VALUE ? canvas.TextHeight(text) : height>0 ? height : 1);
}
//--- 0?>;=O5< ?@>AB@0=AB2> ?> C:070==K< :>>@48=0B0< 8 ?>;CG5==>9 H8@8=>9 8 2KA>B>9 ?@>7@0G=K< F25B>< (AB8@05< ?@>H;CN 70?8AL)
canvas.FillRectangle(x,y,x+w,y+h,0x00FFFFFF);
}
//--- K2>48< B5:AB =0 >G8I5==>5 >B ?@>H;>3> B5:AB0 <5AB> 8 >1=>2;O5< @01>GCN >1;0ABL 157 ?5@5@8A>2:8 M:@0=0
canvas.TextOut(x,y,text,::ColorToARGB(clr==clrNONE ? this.m_fore_color : clr),align);
canvas.Update(false);
}
//+------------------------------------------------------------------+
//| K2>48B 70:@0H5==K9 ?@O<>C3>;L=8: 2 C:070==K5 :>>@48=0BK |
//+------------------------------------------------------------------+
void CTableDataControl::DrawRectangleFill(CCanvas *canvas,const int x,const int y,const int width,const int height,const color clr,const uchar alpha)
{
canvas.FillRectangle(x,y,x+width,y+height,::ColorToARGB(clr,alpha));
canvas.Update();
}
//+------------------------------------------------------------------+