650 lines
67 KiB
MQL5
650 lines
67 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Класс ячейки таблицы |
|
|
//+------------------------------------------------------------------+
|
|
class CTableCell : public CObject
|
|
{
|
|
private:
|
|
int m_row; // Строка
|
|
int m_col; // Столбец
|
|
int m_x; // Координата X
|
|
int m_y; // Координата Y
|
|
int m_w; // Ширина
|
|
int m_h; // Высота
|
|
string m_text; // Текст в ячейке
|
|
color m_fore_color; // Цвет текста в ячейке
|
|
public:
|
|
//--- Методы установки значений
|
|
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; }
|
|
|
|
//--- Методы получения значений
|
|
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; }
|
|
|
|
//--- Выводит текст, записанный в свойствах ячейки на канвас, указатель на который передан в метод
|
|
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;
|
|
//--- Запомним текущие флаги шрифта
|
|
uint flags_prev=canvas.FontFlagsGet();
|
|
//--- Установим цвет фона
|
|
uint clr=(bg_color==clrNONE ? 0x00FFFFFF : ::ColorToARGB(bg_color));
|
|
//--- Зальём установленным цветом фона ячейку (сотрём прошлую надпись)
|
|
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);
|
|
//--- Установим флаги шрифта
|
|
canvas.FontFlagsSet(flags);
|
|
//--- Выведем текст в ячейку
|
|
canvas.TextOut(this.m_x+x_shift, this.m_y+y_shift, this.m_text, ::ColorToARGB(this.m_fore_color), alignment);
|
|
//--- Возвращаем ранее запомненные флаги шрифта и обновляем канвас
|
|
canvas.FontFlagsSet(flags_prev);
|
|
canvas.Update(false);
|
|
}
|
|
|
|
//--- Виртуальный метод сравнения двух объектов
|
|
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);
|
|
}
|
|
|
|
//--- Конструктор/деструктор
|
|
CTableCell(const int row,const int column) : m_row(row),m_col(column){}
|
|
~CTableCell(void){}
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Класс строк таблиц |
|
|
//+------------------------------------------------------------------+
|
|
class CTableRow : public CObject
|
|
{
|
|
private:
|
|
CArrayObj m_list_cell; // Список ячеек
|
|
int m_row; // Номер строки
|
|
int m_y; // Координата Y
|
|
public:
|
|
//--- Возвращает список ячеек таблицы в строке
|
|
CArrayObj *GetListCell(void) { return &this.m_list_cell; }
|
|
//--- Возвращает (1) количество ячеек таблицы в строке (2) индекс строки в таблице
|
|
int CellsTotal(void) const { return this.m_list_cell.Total(); }
|
|
int Row(void) const { return this.m_row; }
|
|
//--- (1) Устанавливает, (2) возвращает координату Y строки
|
|
void SetY(const int y) { this.m_y=y; }
|
|
int Y(void) const { return this.m_y; }
|
|
//--- Добавляет новую ячейку таблицы в строку
|
|
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;
|
|
}
|
|
//--- Возвращает указатель на указанную ячейку в строке
|
|
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);
|
|
}
|
|
//--- Виртуальный метод сравнения двух объектов
|
|
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);
|
|
}
|
|
//--- Конструктор/деструктор
|
|
CTableRow(const int row) : m_row(row) { this.m_list_cell.Clear(); }
|
|
~CTableRow(void) { this.m_list_cell.Clear(); }
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Класс данных таблиц |
|
|
//+------------------------------------------------------------------+
|
|
class CTableData : public CObject
|
|
{
|
|
private:
|
|
CArrayObj m_list_rows; // Список строк
|
|
int m_id; // Идентификатор таблицы
|
|
int m_x1; // Координата X1
|
|
int m_y1; // Координата Y1
|
|
int m_x2; // Координата X2
|
|
int m_y2; // Координата Y2
|
|
int m_w; // Ширина
|
|
int m_h; // Высота
|
|
string m_name; // Наименование таблицы
|
|
public:
|
|
//--- Устанавливает (1) идентификатор, (2) наименование таблицы
|
|
void SetID(const int id) { this.m_id=id; }
|
|
void SetName(const string name) { this.m_name=name; }
|
|
//--- Возвращает (1) идентификатор, (2) наименование таблицы
|
|
int ID(void) const { return this.m_id; }
|
|
string Name(void) const { return this.m_name; }
|
|
|
|
//--- Устанавливает координату (1) X1, (2) X2
|
|
void SetX1(const int x1) { this.m_x1=x1; }
|
|
void SetX2(const int x2) { this.m_x2=x2; }
|
|
//--- Устанавливает координату (1) Y1, (2) Y2
|
|
void SetY1(const int y1) { this.m_y1=y1; }
|
|
void SetY2(const int y2) { this.m_y2=y2; }
|
|
//--- Устанавливает координаты таблицы
|
|
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);
|
|
}
|
|
|
|
//--- Возвращает координату (1) X1, (2) X2
|
|
int X1(void) const { return this.m_x1; }
|
|
int X2(void) const { return this.m_x2; }
|
|
//--- Возвращает координату (1) Y1, (2) Y2
|
|
int Y1(void) const { return this.m_y1; }
|
|
int Y2(void) const { return this.m_y2; }
|
|
|
|
//--- Возвращает (1) ширину, (2) высоту
|
|
int Width(void) const { return this.m_x2-this.m_x1+1; }
|
|
int Height(void) const { return this.m_y2-this.m_y1+1; }
|
|
|
|
//--- Возвращает список строк таблицы
|
|
CArrayObj *GetListRows(void) { return &this.m_list_rows; }
|
|
//--- Добавляет новую строку в таблицу
|
|
bool AddRow(CTableRow *row)
|
|
{
|
|
//--- Устанавливаем флаг сортированного списка
|
|
this.m_list_rows.Sort();
|
|
//--- Если такой объект уже есть в списке (поиск вернул индекс объекта, а не -1),
|
|
//--- сообщаем об этом в журнал и возвращаем 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;
|
|
}
|
|
//--- Если не удалось добавить указатель в сортированный список - сообщаем об этом в журнал и возвращаем 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;
|
|
}
|
|
//--- Успешно - возвращаем true
|
|
return true;
|
|
}
|
|
//--- Возвращает указатель на (1) указанную строку, (2) указанную ячейку в указанной строке таблицы
|
|
CTableRow *GetRow(const int index) { return this.m_list_rows.At(index);}
|
|
CTableCell *GetCell(const int row,const int column)
|
|
{
|
|
//--- Получаем указатель на объект-строку в списке строк
|
|
CTableRow *row_obj=this.GetRow(row);
|
|
//--- Если объект получить не удалось - возвращаем NULL
|
|
if(row_obj==NULL)
|
|
return NULL;
|
|
//--- Получаем указатель на объект-ячейку в строке по номеру столбца и
|
|
CTableCell *cell=row_obj.GetCell(column);
|
|
//--- возвращаем результат (указатель на объект, либо NULL)
|
|
return cell;
|
|
}
|
|
//--- Записывает в переданные в метод переменные координаты X и Y указанной ячейки таблицы
|
|
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();
|
|
}
|
|
//--- Возвращает координату X указанной ячейки таблицы
|
|
int CellX(const uint row,const uint column)
|
|
{
|
|
CTableCell *cell=this.GetCell(row,column);
|
|
return(cell!=NULL ? cell.X() : WRONG_VALUE);
|
|
}
|
|
//--- Возвращает координату Y указанной ячейки таблицы
|
|
int CellY(const uint row,const uint column)
|
|
{
|
|
CTableCell *cell=this.GetCell(row,column);
|
|
return(cell!=NULL ? cell.Y() : WRONG_VALUE);
|
|
}
|
|
//--- Возвращает количество (1) строк, (2) столбцов в указанной строке
|
|
int RowsTotal(void) { return this.m_list_rows.Total(); }
|
|
int ColumnsInRow(const int row_index)
|
|
{
|
|
//--- Если в списке нет ни одной строки - возвращаем 0
|
|
if(this.RowsTotal()==0)
|
|
return 0;
|
|
//--- Получаем указатель на указанную строку и возвращаем количество ячеек в ней
|
|
CTableRow *row=this.GetRow(row_index);
|
|
return(row!=NULL ? row.CellsTotal() : 0);
|
|
}
|
|
//--- Возвращает общее количество ячеек таблицы
|
|
int CellsTotal(void)
|
|
{
|
|
//--- Если в списке нет ни одной строки - возвращаем 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;
|
|
}
|
|
//--- Очищает списки строк и ячеек таблицы
|
|
void Clear(void)
|
|
{
|
|
//--- В цикле по количеству строк в списке строк таблицы
|
|
for(int i=0;i<this.m_list_rows.Total();i++)
|
|
{
|
|
//--- получаем указатель на очередную строку
|
|
CTableRow *row=this.m_list_rows.At(i);
|
|
if(row==NULL)
|
|
continue;
|
|
//--- из полученного объекта-строки получаем список ячеек,
|
|
CArrayObj *list_cell=row.GetListCell();
|
|
//--- очищаем список ячеек
|
|
if(list_cell!=NULL)
|
|
list_cell.Clear();
|
|
}
|
|
//--- Очищаем список строк
|
|
this.m_list_rows.Clear();
|
|
}
|
|
//--- Распечатывает в журнал данные ячеек таблицы
|
|
void Print(const uint tabulation=0)
|
|
{
|
|
//--- Печатаем в журнал заголовок
|
|
::PrintFormat("Table %lu: Rows: %lu, Columns: %lu",this.m_id,this.RowsTotal(),this.CellsTotal()/(this.RowsTotal()!=0 ? this.RowsTotal() : 1));
|
|
//--- В цикле по строкам таблицы
|
|
for(int r=0;r<this.RowsTotal();r++)
|
|
//--- в цикле по ячейкам очередной строки
|
|
for(int c=0;c<this.ColumnsInRow(r);c++)
|
|
{
|
|
//--- получаем указатель на очередную ячейку и выводим в журнал её данные
|
|
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());
|
|
}
|
|
}
|
|
//--- Виртуальный метод сравнения двух объектов
|
|
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);
|
|
}
|
|
//--- Конструктор/деструктор
|
|
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(); }
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Класс управления таблицами |
|
|
//+------------------------------------------------------------------+
|
|
class CTableDataControl : public CTableData
|
|
{
|
|
protected:
|
|
uchar m_alpha;
|
|
color m_fore_color;
|
|
|
|
//--- Преобразует RGB в color
|
|
color RGBToColor(const double r,const double g,const double b) const;
|
|
//--- Записывает в переменные значения компонентов RGB
|
|
void ColorToRGB(const color clr,double &r,double &g,double &b);
|
|
//--- Возвращает составляющую цвета (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; }
|
|
|
|
//--- Возвращает новый цвет
|
|
color NewColor(color base_color, int shift_red, int shift_green, int shift_blue);
|
|
|
|
public:
|
|
//--- Возвращает указатель на себя
|
|
CTableDataControl*Get(void) { return &this; }
|
|
|
|
//--- (1) Устанавливает, (2) возвращает прозрачность
|
|
void SetAlpha(const uchar alpha) { this.m_alpha=alpha; }
|
|
uchar Alpha(void) const { return this.m_alpha; }
|
|
|
|
//--- Рисует (1) фоновую сетку, (2) с автоматическим размером ячеек
|
|
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);
|
|
|
|
//--- Выводит (1) текстовое сообщение, (2) закрашенный прямоугольник в указанные координаты
|
|
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);
|
|
|
|
|
|
//--- Конструкторы/Деструктор
|
|
CTableDataControl (const uint id) : CTableData(id), m_fore_color(clrDimGray), m_alpha(255) {}
|
|
CTableDataControl (void) : m_alpha(255) {}
|
|
~CTableDataControl (void) {}
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Рисует фоновую сетку |
|
|
//+------------------------------------------------------------------+
|
|
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)
|
|
{
|
|
//--- Очищаем все списки объекта табличных данных (удаляем ячейки из строк и все строки)
|
|
this.Clear();
|
|
//--- Высота строки не может быть меньше 2
|
|
int row_h=int(row_size<2 ? 2 : row_size);
|
|
//--- Ширина столбца не может быть меньше 2
|
|
int col_w=int(col_size<2 ? 2 : col_size);
|
|
|
|
//--- Левая координата (X1) таблицы
|
|
int x1=x;
|
|
//--- Рассчитываем координату X2 (справа) в зависимости от количества столбцов и их ширины
|
|
int x2=x1+col_w*int(columns>0 ? columns : 1);
|
|
//--- Координата Y1 находится под областью заголовка панели
|
|
int y1=(int)header_h+y;
|
|
|
|
//--- Рассчитываем координату Y2 (снизу) в зависимости от количества строк и их высоты
|
|
int y2=y1+row_h*int(rows>0 ? rows : 1);
|
|
//--- Устанавливаем координаты таблицы
|
|
this.SetCoords(x1,y1-header_h,x2,y2-header_h);
|
|
|
|
//--- Получаем цвет линий сетки таблицы, либо по умолчанию, либо переданный в метод
|
|
color clr=(line_color==clrNONE ? C'200,200,200' : line_color);
|
|
//--- Рисуем рамку таблицы
|
|
canvas.Rectangle(x1,y1,x2,y2,::ColorToARGB(clr,this.m_alpha));
|
|
//--- В цикле по строкам таблицы
|
|
for(int i=0;i<(int)rows;i++)
|
|
{
|
|
//--- рассчитываем координату Y очередной горизонтальной линии сетки (координата Y очередной строки таблицы)
|
|
int row_y=y1+row_h*i;
|
|
//--- если передан флаг "чередующихся" цветов строк и строка чётная
|
|
if(alternating_color && i%2==0)
|
|
{
|
|
//--- осветляем цвет фона таблицы и рисуем фоновый прямоугольник
|
|
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));
|
|
}
|
|
//--- Рисуем горизонтальную линию сетки таблицы
|
|
canvas.Line(x1,row_y,x2,row_y,::ColorToARGB(clr,this.m_alpha));
|
|
|
|
//--- Создаём новый объект строки таблицы
|
|
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;
|
|
}
|
|
//--- Добавляем его в список строк объекта табличных данных
|
|
//--- (если добавить объект не удалось - удаляем созданный объект)
|
|
if(!this.AddRow(row_obj))
|
|
delete row_obj;
|
|
//--- Устанавливаем в созданном объекте-строке его координату Y с учётом смещения от заголовка панели
|
|
row_obj.SetY(row_y-header_h);
|
|
}
|
|
|
|
//--- В цикле по столбцам таблицы
|
|
for(int i=0;i<(int)columns;i++)
|
|
{
|
|
//--- рассчитываем координату X очередной вертикальной линии сетки (координата X очередного столбца таблицы)
|
|
int col_x=x1+col_w*i;
|
|
//--- Если линия сетки вышла за пределы панели - прерываем цикл
|
|
if(x1==1 && col_x>=x1+canvas.Width()-2)
|
|
break;
|
|
//--- Рисуем вертикальную линию сетки таблицы
|
|
canvas.Line(col_x,y1,col_x,y2,::ColorToARGB(clr,this.m_alpha));
|
|
|
|
//--- Получаем из объекта табличных данных количество созданных строк
|
|
int total=this.RowsTotal();
|
|
//--- В цикле по строкам таблицы
|
|
for(int j=0;j<total;j++)
|
|
{
|
|
//--- получаем очередную строку
|
|
CTableRow *row=this.GetRow(j);
|
|
if(row==NULL)
|
|
continue;
|
|
//--- Создаём новую ячейку таблицы
|
|
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;
|
|
}
|
|
//--- Добавляем созданную ячейку в строку
|
|
//--- (если добавить объект не удалось - удаляем созданный объект)
|
|
if(!row.AddCell(cell))
|
|
{
|
|
delete cell;
|
|
continue;
|
|
}
|
|
//--- Устанавливаем в созданном объекте-ячейке его координату X и координату Y из объекта-строки
|
|
cell.SetXY(col_x,row.Y());
|
|
cell.SetSize(col_w, row_h);
|
|
}
|
|
}
|
|
//--- Обновляем канвас без перерисовки графика
|
|
canvas.Update(false);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рисует фоновую сетку с автоматическим размером ячеек |
|
|
//+------------------------------------------------------------------+
|
|
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)
|
|
{
|
|
//--- Координата X1 (левая) таблицы
|
|
int x1=(int)border;
|
|
//--- Координата X2 (правая) таблицы
|
|
int x2=canvas.Width()-(int)border-1;
|
|
//--- Координата Y1 (верхняя) таблицы
|
|
int y1=int(header_h+border-1);
|
|
//--- Координата Y2 (нижняя) таблицы
|
|
int y2=canvas.Height()-(int)border-1;
|
|
//--- Устанавливаем координаты таблицы
|
|
this.SetCoords(x1,y1,x2,y2);
|
|
|
|
//--- Получаем цвет линий сетки таблицы, либо по умолчанию, либо переданный в метод
|
|
color clr=(line_color==clrNONE ? C'200,200,200' : line_color);
|
|
//--- Если отступ от края панели больше нуля - рисуем рамку таблицы
|
|
//--- иначе - рамкой таблицы выступает рамка панели
|
|
if(border>0)
|
|
canvas.Rectangle(x1,y1,x2,y2,::ColorToARGB(clr,this.m_alpha));
|
|
|
|
//--- Высота всей сетки таблицы
|
|
int greed_h=y2-y1;
|
|
//--- Рассчитываем высоту строки в зависимости от высоты таблицы и количества строк
|
|
int row_h=(int)::round((double)greed_h/(double)rows);
|
|
//--- В цикле по количеству строк
|
|
for(int i=0;i<(int)rows;i++)
|
|
{
|
|
//--- рассчитываем координату Y очередной горизонтальной линии сетки (координата Y очередной строки таблицы)
|
|
int row_y=y1+row_h*i;
|
|
//--- если передан флаг "чередующихся" цветов строк и строка чётная
|
|
if(alternating_color && i%2==0)
|
|
{
|
|
//--- осветляем цвет фона таблицы и рисуем фоновый прямоугольник
|
|
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));
|
|
}
|
|
//--- Рисуем горизонтальную линию сетки таблицы
|
|
canvas.Line(x1,row_y,x2,row_y,::ColorToARGB(clr,this.m_alpha));
|
|
|
|
//--- Создаём новый объект строки таблицы
|
|
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;
|
|
}
|
|
//--- Добавляем его в список строк объекта табличных данных
|
|
//--- (если добавить объект не удалось - удаляем созданный объект)
|
|
if(!this.AddRow(row_obj))
|
|
delete row_obj;
|
|
//--- Устанавливаем в созданном объекте-строке его координату Y с учётом смещения от заголовка панели
|
|
row_obj.SetY(row_y-header_h);
|
|
}
|
|
|
|
//--- Ширина сетки таблицы
|
|
int greed_w=x2-x1;
|
|
//--- Рассчитываем ширину столбца в зависимости от ширины таблицы и количества столбцов
|
|
int col_w=(int)::round((double)greed_w/(double)columns);
|
|
//--- В цикле по столбцам таблицы
|
|
for(int i=0;i<(int)columns;i++)
|
|
{
|
|
//--- рассчитываем координату X очередной вертикальной линии сетки (координата X очередного столбца таблицы)
|
|
int col_x=x1+col_w*i;
|
|
//--- Если это не самая первая вертикальная линия - рисуем её
|
|
//--- (первой вертикальной линией выступает либо рамка таблицы, либо рамка панели)
|
|
if(i>0)
|
|
canvas.Line(col_x,y1,col_x,y2,::ColorToARGB(clr,this.m_alpha));
|
|
|
|
//--- Получаем из объекта табличных данных количество созданных строк
|
|
int total=this.RowsTotal();
|
|
//--- В цикле по строкам таблицы
|
|
for(int j=0;j<total;j++)
|
|
{
|
|
//--- получаем очередную строку
|
|
CTableRow *row=this.GetRow(j);
|
|
if(row==NULL)
|
|
continue;
|
|
//--- Создаём новую ячейку таблицы
|
|
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;
|
|
}
|
|
//--- Добавляем созданную ячейку в строку
|
|
//--- (если добавить объект не удалось - удаляем созданный объект)
|
|
if(!row.AddCell(cell))
|
|
{
|
|
delete cell;
|
|
continue;
|
|
}
|
|
//--- Устанавливаем в созданном объекте-ячейке его координату X и координату Y из объекта-строки
|
|
cell.SetXY(col_x,row.Y());
|
|
cell.SetSize(col_w, row_h);
|
|
}
|
|
}
|
|
//--- Обновляем канвас без перерисовки графика
|
|
canvas.Update(false);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает цвет с новой цветовой составляющей |
|
|
//+------------------------------------------------------------------+
|
|
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);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Преобразует RGB в 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;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Получение значений компонентов RGB |
|
|
//+------------------------------------------------------------------+
|
|
void CTableDataControl::ColorToRGB(const color clr,double &r,double &g,double &b)
|
|
{
|
|
r=GetR(clr);
|
|
g=GetG(clr);
|
|
b=GetB(clr);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Выводит текстовое сообщение в указанные координаты |
|
|
//+------------------------------------------------------------------+
|
|
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)
|
|
{
|
|
//--- Объявим переменные для записи в них ширины и высоты текста
|
|
int w=width;
|
|
int h=height;
|
|
//--- Если ширина и высота текста, переданные в метод, имеют нулевые значения,
|
|
//--- то полностью очищается всё пространство канваса прозрачным цветом
|
|
if(width==0 && height==0)
|
|
canvas.Erase(0x00FFFFFF);
|
|
//--- Иначе
|
|
else
|
|
{
|
|
//--- Если переданные ширина и высота имеют значения по умолчанию (-1) - получаем из текста его ширину и высоту
|
|
if(width==WRONG_VALUE && height==WRONG_VALUE)
|
|
canvas.TextSize(text,w,h);
|
|
//--- иначе,
|
|
else
|
|
{
|
|
//--- если ширина, переданная в метод, имеет значение по умолчанию (-1) - получаем ширину из текста, либо
|
|
//--- если ширина, переданная в метод, имеет значение больше нуля - используем переданную в метод ширину, либо
|
|
//--- если ширина, переданная в метод, имеет нулевое значение, используем значение 1 для ширины
|
|
w=(width ==WRONG_VALUE ? canvas.TextWidth(text) : width>0 ? width : 1);
|
|
//--- если высота, переданная в метод, имеет значение по умолчанию (-1) - получаем высоту из текста, либо
|
|
//--- если высота, переданная в метод, имеет значение больше нуля - используем переданную в метод высоту, либо
|
|
//--- если высота, переданная в метод, имеет нулевое значение, используем значение 1 для высоты
|
|
h=(height==WRONG_VALUE ? canvas.TextHeight(text) : height>0 ? height : 1);
|
|
}
|
|
//--- Заполняем пространство по указанным координатам и полученной шириной и высотой прозрачным цветом (стираем прошлую запись)
|
|
canvas.FillRectangle(x,y,x+w,y+h,0x00FFFFFF);
|
|
}
|
|
//--- Выводим текст на очищенное от прошлого текста место и обновляем рабочую область без перерисовки экрана
|
|
canvas.TextOut(x,y,text,::ColorToARGB(clr==clrNONE ? this.m_fore_color : clr),align);
|
|
canvas.Update(false);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Выводит закрашенный прямоугольник в указанные координаты |
|
|
//+------------------------------------------------------------------+
|
|
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();
|
|
}
|
|
//+------------------------------------------------------------------+
|