//+------------------------------------------------------------------+ //| Dashboard.mqh | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" //--- includes #include #include //+------------------------------------------------------------------+ //| Класс ячейки таблицы | //+------------------------------------------------------------------+ class CTableCell : public CObject { private: int m_row; // Строка int m_col; // Столбец int m_x; // Координата X int m_y; // Координата Y string m_text; // Текст в ячейке 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 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; } string Text(void) const { return this.m_text; } //--- Виртуальный метод сравнения двух объектов virtual int Compare(const CObject *node,const int mode=0) const { const CTableCell *compared=node; return(this.Column()>compared.Column() ? 1 : this.Column()compared.Row() ? 1 : this.Row()compared.ID() ? 1 : this.ID()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(); } }; //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| enums | //+------------------------------------------------------------------+ enum ENUM_MOUSE_STATE { MOUSE_STATE_NOT_PRESSED, MOUSE_STATE_PRESSED_OUTSIDE_WINDOW, MOUSE_STATE_PRESSED_INSIDE_WINDOW, MOUSE_STATE_PRESSED_INSIDE_HEADER, MOUSE_STATE_PRESSED_INSIDE_CLOSE, MOUSE_STATE_PRESSED_INSIDE_MINIMIZE, MOUSE_STATE_PRESSED_INSIDE_PIN, MOUSE_STATE_OUTSIDE_WINDOW, MOUSE_STATE_INSIDE_WINDOW, MOUSE_STATE_INSIDE_HEADER, MOUSE_STATE_INSIDE_CLOSE, MOUSE_STATE_INSIDE_MINIMIZE, MOUSE_STATE_INSIDE_PIN }; //+------------------------------------------------------------------+ //| Класс Dashboard | //+------------------------------------------------------------------+ class CDashboard : public CObject { private: CTableData m_table_tmp; // Объект-таблица для поиска CCanvas m_canvas; // Канвас CCanvas m_workspace; // Рабочая область CArrayObj m_list_table; // Список таблиц CArrayObj m_list_obj; // Список привязанных панелей ENUM_PROGRAM_TYPE m_program_type; // Тип программы ENUM_MOUSE_STATE m_mouse_state; // Состояние кнопок мышки uint m_id; // Идентификатор объекта long m_chart_id; // ChartID int m_chart_w; // Ширина графика int m_chart_h; // Высота графика int m_x; // Координата X int m_y; // Координата Y int m_w; // Ширина int m_h; // Высота int m_x_dock; // Координата X закреплённой свёрнутой панели int m_y_dock; // Координата Y закреплённой свёрнутой панели int m_diff_x; // Смещение локальной координаты X относительно родителя int m_diff_y; // Смещение локальной координаты Y относительно родителя bool m_header; // Флаг наличия заголовка bool m_butt_close; // Флаг наличия кнопки закрытия bool m_butt_minimize; // Флаг наличия кнопки сворачивания/разворачивания bool m_butt_pin; // Флаг наличия кнопки закрепления bool m_wider_wnd; // Флаг превышения горизонтального размера панели ширины окна bool m_higher_wnd; // Флаг превышения вертикального размера панели высоты окна bool m_movable; // Флаг перемещаемости панели int m_header_h; // Высота заголовка int m_wnd; // Номер подокна графика int m_title_x_shift; // Смещение текста заголовка по горизонтали int m_title_y_shift; // Смещение текста заголовка по вертикали uchar m_header_alpha; // Прозрачность заголовка uchar m_header_alpha_c; // Текущая прозрачность заголовка color m_header_back_color; // Цвет фона заголовка color m_header_back_color_c; // Текущий цвет фона заголовка color m_header_fore_color; // Цвет текста заголовка color m_header_fore_color_c; // Текущий цвет текста заголовка color m_header_border_color; // Цвет рамки заголовка color m_header_border_color_c; // Текущий цвет рамки заголовка color m_butt_close_back_color; // Цвет фона кнопки закрытия color m_butt_close_back_color_c; // Текущий цвет фона кнопки закрытия color m_butt_close_fore_color; // Цвет значка кнопки закрытия color m_butt_close_fore_color_c; // Текущий цвет значка кнопки закрытия color m_butt_min_back_color; // Цвет фона кнопки сворачивания/разворачивания color m_butt_min_back_color_c; // Текущий цвет фона кнопки сворачивания/разворачивания color m_butt_min_fore_color; // Цвет значка кнопки сворачивания/разворачивания color m_butt_min_fore_color_c; // Текущий цвет значка кнопки сворачивания/разворачивания color m_butt_pin_back_color; // Цвет фона кнопки закрепления color m_butt_pin_back_color_c; // Текущий цвет фона кнопки закрепления color m_butt_pin_fore_color; // Цвет значка кнопки закрепления color m_butt_pin_fore_color_c; // Текущий цвет значка кнопки закрепления uchar m_alpha; // Прозрачность панели uchar m_alpha_c; // Текущая прозрачность панели uchar m_fore_alpha; // Прозрачность текста uchar m_fore_alpha_c; // Текущая прозрачность текста color m_back_color; // Цвет фона color m_back_color_c; // Текущий цвет фона color m_fore_color; // Цвет текста color m_fore_color_c; // Текущий цвет текста color m_border_color; // Цвет рамки color m_border_color_c; // Текущий цвет рамки string m_title; // Текст заголовка string m_title_font; // Фонт заголовка int m_title_font_size; // Размер шрифта заголовка string m_font; // Фонт int m_font_size; // Размер шрифта bool m_minimized; // Флаг свёрнутого окна панели string m_program_name; // Имя программы string m_name_gv_x; // Наименование глобальной переменной терминала, хранящей координату X string m_name_gv_y; // Наименование глобальной переменной терминала, хранящей координату Y string m_name_gv_m; // Наименование глобальной переменной терминала, хранящей флаг свёрнутости панели string m_name_gv_u; // Наименование глобальной переменной терминала, хранящей флаг закреплённой панели string m_filename_bg; // Наименование файла для сохранения пикселей фона string m_filename_ws; // Наименование файла для сохранения пикселей рабочей области uint m_array_wpx[]; // Массив пикселей для сохранения/восстановления рабочей области uint m_array_ppx[]; // Массив пикселей для сохранения/восстановления фона панели int m_mouse_diff_x; // Смещение курсора относительно угла привязки по X int m_mouse_diff_y; // Смещение курсора относительно угла привязки по Y bool m_slave; // Признак привязанной (зависимой) панели string m_name; // Наименование панели //--- Возвращает флаг превышения (1) высотой, (2) шириной панели соответствующих размеров графика bool HigherWnd(void) const { return(this.m_h+2>this.m_chart_h); } bool WiderWnd(void) const { return(this.m_w+2>this.m_chart_w); } //--- Включает/выключает режимы работы с графиком void SetChartsTool(const bool flag); //--- Сохраняет (1) рабочую область, (2) фон панели в массив пикселей void SaveWorkspace(void); void SaveBackground(void); //--- Восстанавливает (1) рабочую область, (2) фон панели из массива пикселей void RestoreWorkspace(void); void RestoreBackground(void); //--- Сохраняет массив пикселей (1) рабочей области, (2) фона панели в файл bool FileSaveWorkspace(void); bool FileSaveBackground(void); //--- Загружает массив пикселей (1) рабочей области, (2) фона панели из файла bool FileLoadWorkspace(void); bool FileLoadBackground(void); //--- Возвращает номер подокна int GetSubWindow(void) const { return(this.m_program_type==PROGRAM_EXPERT || this.m_program_type==PROGRAM_SCRIPT ? 0 : ::ChartWindowFind()); } protected: //--- Рисует область заголовка void DrawHeaderArea(const string title); //--- Перерисовывает область заголовка с новыми значениями цвета и текста void RedrawHeaderArea(const color new_color=clrNONE,const string title="",const color title_new_color=clrNONE,const ushort new_alpha=USHORT_MAX); //--- Рисует рамку панели void DrawFrame(void); //--- (1) Рисует, (2) перерисовывает кнопку закрытия панели void DrawButtonClose(void); void RedrawButtonClose(const color new_back_color=clrNONE,const color new_fore_color=clrNONE,const ushort new_alpha=USHORT_MAX); //--- (1) Рисует, (2) перерисовывает кнопку сворачивания/разворачивания панели void DrawButtonMinimize(void); void RedrawButtonMinimize(const color new_back_color=clrNONE,const color new_fore_color=clrNONE,const ushort new_alpha=USHORT_MAX); //--- (1) Рисует, (2) перерисовывает кнопку закрепления панели void DrawButtonPin(void); void RedrawButtonPin(const color new_back_color=clrNONE,const color new_fore_color=clrNONE,const ushort new_alpha=USHORT_MAX); //--- Возвращает флаг работы в визуальном тестере bool IsVisualMode(void) const { return (bool)::MQLInfoInteger(MQL_VISUAL_MODE); } //--- Возвращает описание таймфрейма string TimeframeDescription(const ENUM_TIMEFRAMES timeframe) const { return ::StringSubstr(EnumToString(timeframe),7); } //--- Возвращает состояние кнопок мышки ENUM_MOUSE_STATE MouseButtonState(const int x,const int y,bool pressed); //--- Преобразует 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); //--- Рисует панель void Draw(const string title); //--- Устанавливает координату (1) X, (2) Y панели bool SetCoordX(const int coord_x); bool SetCoordY(const int coord_y); //--- Смещает панель на новые координаты void Move(int x,int y); public: //--- Возвращает (1) идентификатор графика, (2) номер подокна long ChartID(void) const { return this.m_chart_id; } int SubWindow(void) const { return this.m_wnd; } //--- (1) Сворачивает, (2) разворачивает панель void Collapse(void); void Expand(void); //--- (1) Скрывает, (2) показывает, (3) переносит на передний план панель void Hide(const bool redraw=false); void Show(const bool redraw=false); void BringToTop(void); //--- Возвращает флаг скрытого объекта bool IsHidden(void); //--- Устанавливает новые цвета заголовка void SetHeaderNewColors(const color new_bg_color=clrNONE, const color title_new_color=clrNONE, const ushort new_alpha=USHORT_MAX) { this.m_header_back_color=(new_bg_color==clrNONE ? this.m_header_back_color : new_bg_color); this.m_header_back_color_c=this.m_header_back_color; this.m_header_fore_color=(title_new_color==clrNONE ? this.m_header_fore_color : title_new_color); this.m_header_fore_color_c=this.m_header_fore_color; this.m_header_alpha=uchar(new_alpha==USHORT_MAX ? this.m_header_alpha : (new_alpha>255 ? 255 : new_alpha)); this.m_header_alpha_c=this.m_header_alpha; } //--- Устанавливает новые свойства заголовка void SetHeaderNewParams(const string title,const color new_bg_color, const color title_new_color, const ushort new_alpha=USHORT_MAX, const int title_x_shift=0,const int title_y_shift=0, const string font_name="Calibri",const int font_size=8,const uint font_flags=0) { this.SetHeaderFontParams(font_name, font_size, font_flags); this.SetTitleShift(title_x_shift,title_y_shift); this.SetHeaderNewColors(new_bg_color,title_new_color,new_alpha); this.RedrawHeaderArea(new_bg_color, title, title_new_color, new_alpha); } //--- Устанавливает (1) ширину, (2) высоту панели bool SetWidth(const int width,const bool redraw=false); bool SetHeight(const int height,const bool redraw=false); //--- Отображает панель void View(const string title) { this.Draw(title); } //--- Возвращает объект (1) CCanvas, (2) рабочую область, (3) идентификатор объекта CCanvas *Canvas(void) { return &this.m_canvas; } CCanvas *Workspace(void) { return &this.m_workspace; } uint ID(void) const { return this.m_id; } //--- Возвращает координату (1) X, (2) Y панели int CoordX(void) const { return this.m_x; } int CoordY(void) const { return this.m_y; } //--- Возвращает (1) ширину, (2) высоту панели int Width(void) const { return this.m_w; } int Height(void) const { return this.m_h; } //--- Возвращает смещение локальной координаты (1) X, (2) Y панели int CoordDiffX(void) const { return this.m_diff_x; } int CoordDiffY(void) const { return this.m_diff_y; } //--- Устанавливает смещение локальной координаты (1) X, (2) Y панели void SetCoordDiffX(const int diff_x) { this.m_diff_x=diff_x; } void SetCoordDiffY(const int diff_y) { this.m_diff_y=diff_y; } //--- Устанавливает смещения текста заголовка по (1) горизонтали, (2) вертикали, (3) оба void SetTitleXShift(const int shift) { this.m_title_x_shift=shift; } void SetTitleYShift(const int shift) { this.m_title_y_shift=shift; } void SetTitleShift(const int x_shift, const int y_shift) { if(this.m_title_x_shift!=x_shift) this.m_title_x_shift=x_shift; if(this.m_title_y_shift!=y_shift) this.m_title_y_shift=y_shift; } //--- Возвращает (1) ширину, (2) высоту, (3) размеры указанного текста int TextWidth(const string text) { return this.m_workspace.TextWidth(text); } int TextHeight(const string text) { return this.m_workspace.TextHeight(text); } void TextSize(const string text,int &width,int &height) { this.m_workspace.TextSize(text,width,height); } //--- Устанавливает флаг (1) наличия, (2) отсутствия заголовка панели void SetPanelHeaderOn(const bool redraw=false); void SetPanelHeaderOff(const bool redraw=false); //--- Устанавливает флаг (1) наличия, (2) отсутствия кнопки закрытия void SetButtonCloseOn(const bool redraw=false); void SetButtonCloseOff(const bool redraw=false); //--- Устанавливает флаг (1) наличия, (2) отсутствия кнопки сворачивания/разворачивания void SetButtonMinimizeOn(const bool redraw=false); void SetButtonMinimizeOff(const bool redraw=false); //--- Устанавливает флаг (1) наличия, (2) отсутствия кнопки закрепления/открепления void SetButtonPinOn(const bool redraw=false); void SetButtonPinOff(const bool redraw=false); //--- Устанавливает координаты панели bool SetCoords(const int x,const int y); //--- Устанавливает размеры панели bool SetSizes(const int w,const int h,const bool update=false); //--- Устанавливает координаты и размеры панели bool SetParams(const int x,const int y,const int w,const int h,const bool update=false); //--- Устанавливает прозрачность (1) заголовка, (2) рабочей области панели void SetHeaderTransparency(const uchar value); void SetTransparency(const uchar value); //--- Устанавливает параметры шрифта (1) панели, (2) заголовка по умолчанию void SetFontParams(const string name,const int size,const uint flags=0,const uint angle=0); void SetHeaderFontParams(const string name,const int size,const uint flags=0,const uint angle=0); //--- Возвращает установленные параметры шрифта (1) панели, (2) заголовка string FontParams(int &size,uint &flags,uint &angle); string FontHeaderParams(int &size,uint &flags,uint &angle); //--- Возвращает установленные (1) шрифт, (2) размер, (3) флаги шрифта панели string FontName(void) const { return this.m_workspace.FontNameGet(); } int FontSize(void) const { return this.m_workspace.FontSizeGet(); } uint FontFlags(void) const { return this.m_workspace.FontFlagsGet(); } //--- Возвращает установленные (1) шрифт, (2) размер, (3) флаги шрифта заголовка string FontHeaderName(void) const { return this.m_canvas.FontNameGet(); } int FontHeaderSize(void) const { return this.m_canvas.FontSizeGet(); } uint FontHeaderFlags(void) const { return this.m_canvas.FontFlagsGet(); } //--- (1) Устанавливает (2) возвращает цвет текста рабочей области панели void SetForeColor(const color clr) { this.m_fore_color=clr; } color ForeColor(void) const { return this.m_fore_color; } //--- Выводит (2) текстовое сообщение, (2) закрашенный прямоугольник в указанные координаты void DrawText(const string text,const int x,const int y,const color clr=clrNONE,const int width=WRONG_VALUE,const int height=WRONG_VALUE); void DrawRectangleFill(const int x,const int y,const int width,const int height,const color clr,const uchar alpha); //--- Создаёт новую таблицу bool CreateNewTable(const int id=WRONG_VALUE); //--- Возвращает объект табличных данных по (1) идентификатору, (2) наименованию, (3) количество таблиц в списке CTableData *GetTable(const uint id); CTableData *GetTable(const string name); int TableTotal(void) const { return this.m_list_table.Total(); } //--- Возвращает флаг наличия таблицы в списке по (1) идентификатору, (2) наименованию bool TableIsExist(const uint id); bool TableIsExist(const string name); //--- Рисует (1) фоновую сетку, (2) с автоматическим размером ячеек void DrawGrid(const uint table_id,const int x,const int y,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(const uint table_id,const uint border,const uint rows,const uint columns,const color line_color=clrNONE,bool alternating_color=true); //--- Стирает всё нарисованное на панели и восстанавливает первоначальный вид void Clear(void) { this.m_canvas.Erase(::ColorToARGB(this.m_back_color,this.m_alpha)); this.DrawFrame(); this.m_workspace.Erase(0x00FFFFFF); } //--- Распечатывает данные сетки (координаты пересечения линий) void GridPrint(const uint table_id,const uint tabulation=0) { CTableData *table=this.GetTable(table_id); if(table==NULL) { ::PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id); return; } table.Print(tabulation); } //--- Записывает в переменные значения координат X и Y указанной ячейки таблицы void CellXY(const uint table_id,const uint row,const uint column, int &x, int &y) { CTableData *table=this.GetTable(table_id); if(table==NULL) { ::PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id); return; } table.CellXY(row,column,x,y); } //--- Возвращает координату (1) X, (2) Y указанной ячейки таблицы int CellX(const uint table_id,const uint row,const uint column) { CTableData *table=this.GetTable(table_id); if(table==NULL) { ::PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id); return WRONG_VALUE; } return table.CellX(row,column); } int CellY(const uint table_id,const uint row,const uint column) { CTableData *table=this.GetTable(table_id); if(table==NULL) { ::PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id); return WRONG_VALUE; } return table.CellY(row,column); } //--- Записывает в переменные значения координат X1 и Y1, X2 и Y2 указанной таблицы void TableCoords(const uint table_id,int &x1,int &y1,int &x2,int &y2) { x1=y1=x2=y2=WRONG_VALUE; CTableData *table=this.GetTable(table_id); if(table==NULL) return; x1=table.X1(); y1=table.Y1(); x2=table.X2(); y2=table.Y2(); } //--- Возвращает координату (1) X1, (2) Y1, (3) X2, (4) Y2 указанной таблицы int TableX1(const uint table_id) { CTableData *table=this.GetTable(table_id); return(table!=NULL ? table.X1() : WRONG_VALUE); } int TableY1(const uint table_id) { CTableData *table=this.GetTable(table_id); return(table!=NULL ? table.Y1() : WRONG_VALUE); } int TableX2(const uint table_id) { CTableData *table=this.GetTable(table_id); return(table!=NULL ? table.X2() : WRONG_VALUE); } int TableY2(const uint table_id) { CTableData *table=this.GetTable(table_id); return(table!=NULL ? table.Y2() : WRONG_VALUE); } //--- Сравнивает два объекта по идентификатору virtual int Compare(const CObject *node,const int mode=0) const { const CDashboard *obj=node; return(this.ID()>obj.ID() ? 1 : this.ID()20 ? h : 21)); if(obj==NULL) return NULL; int diff_x=obj.CoordX()-this.CoordX(); int diff_y=obj.CoordY()-this.CoordY(); this.m_list_obj.Sort(); if(this.m_list_obj.Search(obj)==0 || !this.m_list_obj.Add(obj)) { delete obj; return NULL; } obj.SetCoordDiffX(diff_x); obj.SetCoordDiffY(diff_y); obj.SetAsSlave(); return obj; } //--- Возвращает указатель на панель по (1) идентификатору, (2) наименованию CDashboard *GetPanel(const uint id) { for(int i=0;iWRONG_VALUE); } //--- (1) Устанавливает, (2) возвращает наименование панели void SetName(const string name) { this.m_name=name; } string Name(void) const { return this.m_name; } //--- Возвращает текст заголовка панели string HeaderTitle(void) const { return this.m_title; } //--- Обработчик событий void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- Конструктор/Деструктор CDashboard(const uint id,const int x,const int y, const int w,const int h,const int wnd=-1); ~CDashboard(); }; //+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ CDashboard::CDashboard(const uint id,const int x,const int y, const int w,const int h,const int wnd=-1) : m_id(id), m_chart_id(::ChartID()), m_program_type((ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE)), m_program_name(::MQLInfoString(MQL_PROGRAM_NAME)), m_wnd(wnd==-1 ? GetSubWindow() : wnd), m_chart_w((int)::ChartGetInteger(m_chart_id,CHART_WIDTH_IN_PIXELS,m_wnd)), m_chart_h((int)::ChartGetInteger(m_chart_id,CHART_HEIGHT_IN_PIXELS,m_wnd)), m_mouse_state(MOUSE_STATE_NOT_PRESSED), m_x(x), m_y(::ChartGetInteger(m_chart_id,CHART_SHOW_ONE_CLICK) ? (y<79 ? 79 : y) : y), m_header_h(18), m_h(h), m_w(w), m_x_dock(m_x), m_y_dock(m_y), m_header(true), m_butt_close(true), m_butt_minimize(true), m_butt_pin(true), m_diff_x(0), m_diff_y(0), //--- Оформление заголовка панели m_header_alpha(180), m_header_alpha_c(m_header_alpha), m_header_back_color(C'0,153,188'), m_header_back_color_c(m_header_back_color), m_header_fore_color(C'182,255,244'), m_header_fore_color_c(m_header_fore_color), m_header_border_color(C'167,167,168'), m_header_border_color_c(m_header_border_color), m_title("Dashboard"), m_title_font("Calibri"), m_title_font_size(-100), m_title_x_shift(0), m_title_y_shift(0), //--- кнопка закрытия m_butt_close_back_color(C'0,153,188'), m_butt_close_back_color_c(m_butt_close_back_color), m_butt_close_fore_color(clrWhite), m_butt_close_fore_color_c(m_butt_close_fore_color), //--- кнопка сворачивания/разворачивания m_butt_min_back_color(C'0,153,188'), m_butt_min_back_color_c(m_butt_min_back_color), m_butt_min_fore_color(clrWhite), m_butt_min_fore_color_c(m_butt_min_fore_color), //--- кнопка закрепления m_butt_pin_back_color(C'0,153,188'), m_butt_pin_back_color_c(m_butt_min_back_color), m_butt_pin_fore_color(clrWhite), m_butt_pin_fore_color_c(m_butt_min_fore_color), //--- Оформление панели m_alpha(200), m_alpha_c(m_alpha), m_fore_alpha(255), m_fore_alpha_c(m_fore_alpha), m_back_color(C'240,240,240'), m_back_color_c(m_back_color), m_fore_color(C'53,0,0'), m_fore_color_c(m_fore_color), m_border_color(C'167,167,168'), m_border_color_c(m_border_color), m_font("Calibri"), m_font_size(-100), m_minimized(false), m_movable(true), m_mouse_diff_x(0), m_mouse_diff_y(0), m_slave(false) { //--- Устанавливаем для графика разрешения на отправку сообщений о событиях перемещения и нажатия кнопок мышки, //--- о событиях колёсика мышки и событиях создания и удаления графического объекта ::ChartSetInteger(this.m_chart_id,CHART_EVENT_MOUSE_MOVE,true); ::ChartSetInteger(this.m_chart_id,CHART_EVENT_MOUSE_WHEEL,true); ::ChartSetInteger(this.m_chart_id,CHART_EVENT_OBJECT_CREATE,true); ::ChartSetInteger(this.m_chart_id,CHART_EVENT_OBJECT_DELETE,true); //--- Задаём имена глобальным переменным терминала для хранения координат панели, состояния свёрнуто/развернуто и закрепления this.m_name_gv_x=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_X"; this.m_name_gv_y=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Y"; this.m_name_gv_m=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Minimize"; this.m_name_gv_u=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Unpin"; //--- Задаём имена файлов для сохранения пикселей фона и рабочей области this.m_filename_bg=this.m_program_name+"\\Dashboard"+(string)this.m_id+"\\background.bin"; this.m_filename_ws=this.m_program_name+"\\Dashboard"+(string)this.m_id+"\\workspace.bin"; //--- Если глобальной переменной не существует - создаём её и записываем текущее значение, //--- иначе - считываем в неё значение из глобальной переменной терминала //--- Координата X if(!::GlobalVariableCheck(this.m_name_gv_x)) ::GlobalVariableSet(this.m_name_gv_x,this.m_x); else this.m_x=(int)::GlobalVariableGet(this.m_name_gv_x); //--- Координата Y if(!::GlobalVariableCheck(this.m_name_gv_y)) ::GlobalVariableSet(this.m_name_gv_y,this.m_y); else this.m_y=(int)::GlobalVariableGet(this.m_name_gv_y); //--- Свёрнуто/развёрнуто if(!::GlobalVariableCheck(this.m_name_gv_m)) ::GlobalVariableSet(this.m_name_gv_m,this.m_minimized); else this.m_minimized=(int)::GlobalVariableGet(this.m_name_gv_m); //--- Закреплено/не закреплено if(!::GlobalVariableCheck(this.m_name_gv_u)) ::GlobalVariableSet(this.m_name_gv_u,this.m_movable); else this.m_movable=(int)::GlobalVariableGet(this.m_name_gv_u); //--- Устанавливаем флаги превышения размерами панели размеров окна графика this.m_higher_wnd=this.HigherWnd(); this.m_wider_wnd=this.WiderWnd(); //--- Если графический ресурс панели создан, if(this.m_canvas.CreateBitmapLabel(this.m_chart_id,this.m_wnd,"P"+(string)this.m_id,this.m_x,this.m_y,this.m_w,this.m_h,COLOR_FORMAT_ARGB_NORMALIZE)) { //--- устанавливаем для канваса шрифт и заполняем канвас прозрачным цветом this.m_canvas.FontSet(this.m_title_font,this.m_title_font_size,FW_BOLD); this.m_canvas.Erase(0x00FFFFFF); } //--- иначе - сообщаем о неудачном создании объекта в журнал else ::PrintFormat("%s: Error. CreateBitmapLabel for canvas ID %d failed",(string)__FUNCTION__,this.m_id); //--- Если графический ресурс рабочей области создан, if(this.m_workspace.CreateBitmapLabel(this.m_chart_id,this.m_wnd,"W"+(string)this.m_id,this.m_x,this.m_y+this.m_header_h+1,this.m_w,this.m_h-this.m_header_h-1,COLOR_FORMAT_ARGB_NORMALIZE)) { //--- устанавливаем для рабочей области шрифт и заполняем рабочую область прозрачным цветом this.m_workspace.FontSet(this.m_font,this.m_font_size); this.m_workspace.Erase(0x00FFFFFF); } //--- иначе - сообщаем о неудачном создании объекта в журнал else ::PrintFormat("%s: Error. CreateBitmapLabel for workspace failed",(string)__FUNCTION__); //--- Если стоит флаг свёрнутой панели - загружаем в массивы пиксели фона и рабочей области из файлов if(this.m_minimized) { if(::FileIsExist(this.m_filename_bg)) this.FileLoadBackground(); if(::FileIsExist(this.m_filename_ws)) this.FileLoadWorkspace(); } } //+------------------------------------------------------------------+ //| Деструктор | //+------------------------------------------------------------------+ CDashboard::~CDashboard() { //--- Записываем текущие значения в глобальные переменные терминала ::GlobalVariableSet(this.m_name_gv_x,this.m_x); ::GlobalVariableSet(this.m_name_gv_y,this.m_y); ::GlobalVariableSet(this.m_name_gv_m,this.m_minimized); ::GlobalVariableSet(this.m_name_gv_u,this.m_movable); //--- Если панель свёрнута, //--- разворачиваем панель, сохраняем внешний вид в массивы пикселей и сворачиваем панель if(this.m_minimized) { this.Expand(); this.SaveBackground(); this.SaveWorkspace(); this.Collapse(); } //--- иначе, если панель развёрнута, //--- сохраняем внешний вид в массивы пикселей else { this.SaveBackground(); this.SaveWorkspace(); } //--- Сохраняем массивы пикселей в файлы this.FileSaveBackground(); this.FileSaveWorkspace(); //--- Удаляем объекты панели this.m_canvas.Destroy(); this.m_workspace.Destroy(); } //+------------------------------------------------------------------+ //| Возвращает состояние курсора и кнопки мыши | //+------------------------------------------------------------------+ ENUM_MOUSE_STATE CDashboard::MouseButtonState(const int x,const int y,bool pressed) { //--- Если кнопка нажата if(pressed) { //--- Если уже зафиксировано состояние - уходим if(this.m_mouse_state!=MOUSE_STATE_NOT_PRESSED) return this.m_mouse_state; //--- Если нажата кнопка внутри окна if(x>this.m_x && xthis.m_y && ythis.m_y && y<=this.m_y+this.m_header_h) { //--- Выводим панель на передний план this.BringToTop(); //--- Координаты кнопок закрытия, сворачивания/разворачивания и закрепления int wc=(this.m_butt_close ? this.m_header_h : 0); int wm=(this.m_butt_minimize ? this.m_header_h : 0); int wp=(this.m_butt_pin ? this.m_header_h : 0); //--- Если нажата кнопка закрытия - возвращаем это состояние if(x>this.m_x+this.m_w-wc) return MOUSE_STATE_PRESSED_INSIDE_CLOSE; //--- Если нажата кнопка сворачивания/разворачивания - возвращаем это состояние if(x>this.m_x+this.m_w-wc-wm) return MOUSE_STATE_PRESSED_INSIDE_MINIMIZE; //--- Если нажата кнопка закрепления - возвращаем это состояние if(x>this.m_x+this.m_w-wc-wm-wp) return MOUSE_STATE_PRESSED_INSIDE_PIN; //--- Если кнопка нажата не на управляющих кнопках панели - записываем и возвращаем состояние нажатия кнопки внутри заголовка this.m_mouse_state=MOUSE_STATE_PRESSED_INSIDE_HEADER; return this.m_mouse_state; } //--- Если нажата кнопка внутри окна - записываем состояние в переменную и возвращаем это состояние else if(y>this.m_y+this.m_header_h && ythis.m_x && xthis.m_y && ythis.m_y && y<=this.m_y+this.m_header_h) { //--- Указываем ширину кнопок закрытия, сворачивания/разворачивания и закрепления int wc=(this.m_butt_close ? this.m_header_h : 0); int wm=(this.m_butt_minimize ? this.m_header_h : 0); int wp=(this.m_butt_pin ? this.m_header_h : 0); //--- Если курсор внутри кнопки закрытия - возвращаем это состояние if(x>this.m_x+this.m_w-wc) return MOUSE_STATE_INSIDE_CLOSE; //--- Если курсор внутри кнопки сворачивания/разворачивания - возвращаем это состояние if(x>this.m_x+this.m_w-wc-wm) return MOUSE_STATE_INSIDE_MINIMIZE; //--- Если курсор внутри кнопки закрепления - возвращаем это состояние if(x>this.m_x+this.m_w-wc-wm-wp) return MOUSE_STATE_INSIDE_PIN; //--- Если курсор за пределами кнопок внутри области заголовка - возвращаем это состояние return MOUSE_STATE_INSIDE_HEADER; } //--- Иначе - Курсор внутри рабочей области - возвращаем это состояние else return MOUSE_STATE_INSIDE_WINDOW; } } //--- В любом ином случае возвращаем состояние не нажатой кнопки мышки return MOUSE_STATE_NOT_PRESSED; } //+------------------------------------------------------------------+ //| Обработчик событий | //+------------------------------------------------------------------+ void CDashboard::OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Если создан графический объект if(id==CHARTEVENT_OBJECT_CREATE) { //--- Если созданный объект принадлежит панели - уходим if(this.IsOwnObject(sparam)) return; this.BringToTop(); ::ObjectSetInteger(this.m_chart_id,sparam,OBJPROP_SELECTED,true); } //--- Если график изменён if(id==CHARTEVENT_CHART_CHANGE) { //--- Получаем номер подокна графика, если это не главное окно (номер может измениться при удалении окна какого-либо индикатора) if(this.m_wnd!=0) this.m_wnd=this.GetSubWindow(); //--- Не работаем на неактивном графике long value; ::ResetLastError(); //--- получим значение свойства if(!::ChartGetInteger(this.m_chart_id, CHART_BRING_TO_TOP, this.m_wnd, value)) { //--- выведем сообщение об ошибке в журнал "Эксперты" Print(__FUNCTION__ + ", Error Code = ", ::GetLastError()); return; } // если это не показ графика поверх всех других - выходим if(!value) return; //--- Получаем новые размеры графика int w=(int)::ChartGetInteger(this.m_chart_id,CHART_WIDTH_IN_PIXELS,this.m_wnd); int h=(int)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS,this.m_wnd); //--- Если высота графика изменилась - корректируем расположение панели по вертикали if(this.m_chart_h!=h) { this.m_chart_h=h; int y=this.m_y; if(this.m_y+this.m_h>h-1) y=h-this.m_h-1; if(y<1) y=1; //--- Определяем выход размера панели по высоте за пределы окна графика this.m_higher_wnd=this.HigherWnd(); this.Move(this.m_x,y); } //--- Если ширина графика изменилась - корректируем расположение панели по горизонтали if(this.m_chart_w!=w) { this.m_chart_w=w; int x=this.m_x; if(this.m_x+this.m_w>w-1) x=w-this.m_w-1; if(x<1) x=1; //--- Определяем выход размера панели по ширине за пределы окна графика this.m_wider_wnd=this.WiderWnd(); this.Move(x,this.m_y); } } //--- Сначала обработаем события прикреплённых ведомых объектов if(this.m_list_obj.Total()>0) { for(int i=0;ithis.m_chart_w-1) x=this.m_chart_w-w-1; if(x<1) x=1; } else { if(x>1) x=1; if(xthis.m_chart_h-2) y=this.m_chart_h-h-2; if(y<1) y=1; } //--- Если панель по высоте не входит в размер окна по высоте else { //--- Не даём панели опускаться ниже верхней грани окна с зазором в 1 пиксель if(y>1) y=1; //--- Не даём панели провалиться ниже нижней грани окна с зазором в 1 пиксель if(y255 ? 255 : new_alpha); //--- Координата Y текста расположена по вертикали по центру области заголовка int y=this.m_header_h/2+this.m_title_y_shift; //--- Заполняем область цветом this.m_canvas.FillRectangle(0,0,this.m_w-1,this.m_header_h-1,::ColorToARGB(back_clr,alpha)); //--- Выводим текст заголовка this.m_canvas.TextOut(2+this.m_title_x_shift,y,this.m_title,::ColorToARGB(fore_clr,alpha),TA_LEFT|TA_VCENTER); //--- Запоминаем текущий цвет фона заголовка, текста и прозрачность this.m_header_back_color_c=back_clr; this.m_header_fore_color_c=fore_clr; this.m_header_alpha_c=alpha; //--- Рисуем управляющие элементы (кнопки закрытия, сворачивания/разворачивания и закрепления) и this.RedrawButtonClose(back_clr,clrNONE,alpha); this.RedrawButtonMinimize(back_clr,clrNONE,alpha); this.RedrawButtonPin(back_clr,clrNONE,alpha); //--- обновляем канвас без перерисовки экрана this.m_canvas.Update(true); } //+------------------------------------------------------------------+ //| Рисует рамку панели | //+------------------------------------------------------------------+ void CDashboard::DrawFrame(void) { this.m_canvas.Rectangle(0,0,this.m_w-1,this.m_h-1,::ColorToARGB(this.m_border_color,this.m_alpha)); this.m_border_color_c=this.m_border_color; this.m_canvas.Update(false); } //+------------------------------------------------------------------+ //| Рисует кнопку закрытия панели | //+------------------------------------------------------------------+ void CDashboard::DrawButtonClose(void) { //--- Если кнопка не используется - уходим if(!this.m_butt_close) return; //--- Ширина кнопки равна высоте области заголовка int w=this.m_header_h; //--- Координаты и размеры кнопки int x1=this.m_w-w; int x2=this.m_w-1; int y1=0; int y2=w-1; //--- Смещение левого верхнего угла прямоугольной области рисунка от левого верхнего угла кнопки int shift=4; //--- Рисуем фон кнопки this.m_canvas.FillRectangle(x1,y1,x2,y2,::ColorToARGB(this.m_butt_close_back_color,this.m_header_alpha)); //--- Рисуем "Крестик" закрытия this.m_canvas.LineThick(x1+shift+1,y1+shift+1,x2-shift,y2-shift,::ColorToARGB(this.m_butt_close_fore_color,255),3,STYLE_SOLID,LINE_END_ROUND); this.m_canvas.LineThick(x1+shift+1,y2-shift-1,x2-shift,y1+shift,::ColorToARGB(this.m_butt_close_fore_color,255),3,STYLE_SOLID,LINE_END_ROUND); //--- Запоминаем текущий цвет фона и рисунка кнопки this.m_butt_close_back_color_c=this.m_butt_close_back_color; this.m_butt_close_fore_color_c=this.m_butt_close_fore_color; //--- обновляем канвас без перерисовки экрана this.m_canvas.Update(false); } //+------------------------------------------------------------------+ //| Перерисовывает кнопку закрытия панели | //+------------------------------------------------------------------+ void CDashboard::RedrawButtonClose(const color new_back_color=clrNONE,const color new_fore_color=clrNONE,const ushort new_alpha=USHORT_MAX) { //--- Если кнопка не используется или все переданные параметры имеют значения по умолчанию - уходим if(!this.m_butt_close || (new_back_color==clrNONE && new_fore_color==clrNONE && new_alpha==USHORT_MAX)) return; //--- Ширина кнопки равна высоте области заголовка int w=this.m_header_h; //--- Координаты и размеры кнопки int x1=this.m_w-w; int x2=this.m_w-1; int y1=0; int y2=w-1; //--- Смещение левого верхнего угла прямоугольной области рисунка от левого верхнего угла кнопки int shift=4; //--- Определяем новые цвета фона и текста и прозрачность color back_color=(new_back_color!=clrNONE ? new_back_color : this.m_butt_close_back_color); color fore_color=(new_fore_color!=clrNONE ? new_fore_color : this.m_butt_close_fore_color); uchar alpha=uchar(new_alpha==USHORT_MAX ? this.m_header_alpha : new_alpha>255 ? 255 : new_alpha); //--- Рисуем фон кнопки this.m_canvas.FillRectangle(x1,y1,x2,y2,::ColorToARGB(back_color,alpha)); //--- Рисуем "Крестик" закрытия this.m_canvas.LineThick(x1+shift+1,y1+shift+1,x2-shift,y2-shift,::ColorToARGB(fore_color,255),3,STYLE_SOLID,LINE_END_ROUND); this.m_canvas.LineThick(x1+shift+1,y2-shift-1,x2-shift,y1+shift,::ColorToARGB(fore_color,255),3,STYLE_SOLID,LINE_END_ROUND); //--- Запоминаем текущий цвет фона и рисунка кнопки this.m_butt_close_back_color_c=back_color; this.m_butt_close_fore_color_c=fore_color; //--- обновляем канвас без перерисовки экрана this.m_canvas.Update(false); } //+------------------------------------------------------------------+ //| Рисует кнопку сворачивания/разворачивания панели | //+------------------------------------------------------------------+ void CDashboard::DrawButtonMinimize(void) { //--- Если кнопка не используется - уходим if(!this.m_butt_minimize) return; //--- Ширина кнопки равна высоте области заголовка int w=this.m_header_h; //--- Ширина кнопки закрытия равна нулю, если кнопка не используется int wc=(this.m_butt_close ? w : 0); //--- Координаты и размеры кнопки int x1=this.m_w-wc-w; int x2=this.m_w-wc-1; int y1=0; int y2=w-1; //--- Смещение левого верхнего угла прямоугольной области рисунка от левого верхнего угла кнопки int shift=4; //--- Рисуем фон кнопки this.m_canvas.FillRectangle(x1,y1,x2,y2,::ColorToARGB(this.m_butt_min_back_color,this.m_header_alpha)); //--- Если панель свёрнута - рисуем прямоугольник if(this.m_minimized) this.m_canvas.Rectangle(x1+shift,y1+shift,x2-shift,y2-shift,::ColorToARGB(this.m_butt_min_fore_color,255)); //--- Иначе - панель развёрнута - рисуем отрезок линии else this.m_canvas.LineThick(x1+shift,y2-shift,x2-shift,y2-shift,::ColorToARGB(this.m_butt_min_fore_color,255),3,STYLE_SOLID,LINE_END_ROUND); //--- Запоминаем текущий цвет фона и рисунка кнопки this.m_butt_min_back_color_c=this.m_butt_min_back_color; this.m_butt_min_fore_color_c=this.m_butt_min_fore_color; //--- обновляем канвас без перерисовки экрана this.m_canvas.Update(false); } //+------------------------------------------------------------------+ //| Перерисовывает кнопку сворачивания/разворачивания панели | //+------------------------------------------------------------------+ void CDashboard::RedrawButtonMinimize(const color new_back_color=clrNONE,const color new_fore_color=clrNONE,const ushort new_alpha=USHORT_MAX) { //--- Если кнопка не используется или все переданные параметры имеют значения по умолчанию - уходим if(!this.m_butt_minimize || (new_back_color==clrNONE && new_fore_color==clrNONE && new_alpha==USHORT_MAX)) return; //--- Ширина кнопки равна высоте области заголовка int w=this.m_header_h; //--- Ширина кнопки закрытия равна нулю, если кнопка не используется int wc=(this.m_butt_close ? w : 0); //--- Координаты и размеры кнопки int x1=this.m_w-wc-w; int x2=this.m_w-wc-1; int y1=0; int y2=w-1; //--- Смещение левого верхнего угла прямоугольной области рисунка от левого верхнего угла кнопки int shift=4; //--- Определяем новые цвета фона и текста и прозрачность color back_color=(new_back_color!=clrNONE ? new_back_color : this.m_butt_min_back_color); color fore_color=(new_fore_color!=clrNONE ? new_fore_color : this.m_butt_min_fore_color); uchar alpha=uchar(new_alpha==USHORT_MAX ? this.m_header_alpha : new_alpha>255 ? 255 : new_alpha); //--- Рисуем фон кнопки this.m_canvas.FillRectangle(x1,y1,x2,y2,::ColorToARGB(back_color,alpha)); //--- Если панель свёрнута - рисуем прямоугольник if(this.m_minimized) this.m_canvas.Rectangle(x1+shift,y1+shift,x2-shift,y2-shift,::ColorToARGB(fore_color,255)); //--- Иначе - панель развёрнута - рисуем отрезок линии else this.m_canvas.LineThick(x1+shift,y2-shift,x2-shift,y2-shift,::ColorToARGB(fore_color,255),3,STYLE_SOLID,LINE_END_ROUND); //--- Запоминаем текущий цвет фона и рисунка кнопки this.m_butt_min_back_color_c=back_color; this.m_butt_min_fore_color_c=fore_color; //--- обновляем канвас без перерисовки экрана this.m_canvas.Update(false); } //+------------------------------------------------------------------+ //| Рисует кнопку закрепления панели | //+------------------------------------------------------------------+ void CDashboard::DrawButtonPin(void) { //--- Если кнопка не используется - уходим if(!this.m_butt_pin) return; //--- Ширина кнопки равна высоте области заголовка int w=this.m_header_h; //--- Ширина кнопки закрытия и кнопки сворачивания равна нулю, если кнопка не используется int wc=(this.m_butt_close ? w : 0); int wm=(this.m_butt_minimize ? w : 0); //--- Координаты и размеры кнопки int x1=this.m_w-wc-wm-w; int x2=this.m_w-wc-wm-1; int y1=0; int y2=w-1; //--- Рисуем фон кнопки this.m_canvas.FillRectangle(x1,y1,x2,y2,::ColorToARGB(this.m_butt_pin_back_color,this.m_header_alpha)); //--- Координаты точек ломаной линии int x[]={x1+3, x1+6, x1+3,x1+4,x1+6,x1+9,x1+9,x1+10,x1+15,x1+14,x1+13,x1+10,x1+10,x1+9,x1+6}; int y[]={y1+14,y1+11,y1+8,y1+7,y1+7,y1+4,y1+3,y1+2, y1+7, y1+8, y1+8, y1+11,y1+13,y1+14,y1+11}; //--- Рисуем фигурку "кнопки" this.m_canvas.Polygon(x,y,::ColorToARGB(this.m_butt_pin_fore_color,255)); //--- Если флаг перемещаемости сброшен (закреплено) - перечёркиваем нарисованную кнопку if(!this.m_movable) this.m_canvas.Line(x1+3,y1+2,x1+15,y1+14,::ColorToARGB(this.m_butt_pin_fore_color,255)); //--- Запоминаем текущий цвет фона и рисунка кнопки this.m_butt_pin_back_color_c=this.m_butt_pin_back_color; this.m_butt_pin_fore_color_c=this.m_butt_pin_fore_color; //--- обновляем канвас без перерисовки экрана this.m_canvas.Update(false); } //+------------------------------------------------------------------+ //| Перерисовывает кнопку закрепления панели | //+------------------------------------------------------------------+ void CDashboard::RedrawButtonPin(const color new_back_color=clrNONE,const color new_fore_color=clrNONE,const ushort new_alpha=USHORT_MAX) { //--- Если кнопка не используется или все переданные параметры имеют значения по умолчанию - уходим if(!this.m_butt_pin || (new_back_color==clrNONE && new_fore_color==clrNONE && new_alpha==USHORT_MAX)) return; //--- Ширина кнопки равна высоте области заголовка int w=this.m_header_h; //--- Ширина кнопки закрытия и кнопки сворачивания равна нулю, если кнопка не используется int wc=(this.m_butt_close ? w : 0); int wm=(this.m_butt_minimize ? w : 0); //--- Координаты и размеры кнопки int x1=this.m_w-wc-wm-w; int x2=this.m_w-wc-wm-1; int y1=0; int y2=w-1; //--- Определяем новые цвета фона и текста и прозрачность color back_color=(new_back_color!=clrNONE ? new_back_color : this.m_butt_pin_back_color); color fore_color=(new_fore_color!=clrNONE ? new_fore_color : this.m_butt_pin_fore_color); uchar alpha=uchar(new_alpha==USHORT_MAX ? this.m_header_alpha : new_alpha>255 ? 255 : new_alpha); //--- Рисуем фон кнопки this.m_canvas.FillRectangle(x1,y1,x2,y2,::ColorToARGB(back_color,alpha)); //--- Координаты точек ломаной линии int x[]={x1+3, x1+6, x1+3,x1+4,x1+6,x1+9,x1+9,x1+10,x1+15,x1+14,x1+13,x1+10,x1+10,x1+9,x1+6}; int y[]={y1+14,y1+11,y1+8,y1+7,y1+7,y1+4,y1+3,y1+2, y1+7, y1+8, y1+8, y1+11,y1+13,y1+14,y1+11}; //--- Рисуем фигурку "кнопки" this.m_canvas.Polygon(x,y,::ColorToARGB(this.m_butt_pin_fore_color,255)); //--- Если флаг перемещаемости сброшен (закреплено) - перечёркиваем нарисованную кнопку if(!this.m_movable) this.m_canvas.Line(x1+3,y1+2,x1+15,y1+14,::ColorToARGB(this.m_butt_pin_fore_color,255)); //--- Запоминаем текущий цвет фона и рисунка кнопки this.m_butt_pin_back_color_c=back_color; this.m_butt_pin_fore_color_c=fore_color; //--- обновляем канвас без перерисовки экрана this.m_canvas.Update(false); } //+------------------------------------------------------------------+ //| Рисует панель | //+------------------------------------------------------------------+ void CDashboard::Draw(const string title) { //--- Устанавливаем текст заголовка this.m_title=title; //--- Если флаг свёрнутости не установлен - разворачиваем панель if(!this.m_minimized) this.Expand(); //--- Иначе - сворачиваем панель else this.Collapse(); //--- Обновляем канвас без перерисовки чарта this.m_canvas.Update(false); //--- Обновляем рабочую область с перерисовкой графика this.m_workspace.Update(); } //+------------------------------------------------------------------+ //| Сворачивает панель | //+------------------------------------------------------------------+ void CDashboard::Collapse(void) { //--- Запоминаем текущую высоту панели int h=this.m_h; //--- Скрываем все привязанные объекты for(int i=0;i0) this.RestoreWorkspace(); } //--- Если после разворачивания панель выходит за пределы окна графика - корректируем расположение панели if(this.m_y+this.m_canvas.Height()>this.m_chart_h-1) this.Move(this.m_x,this.m_chart_h-1-this.m_canvas.Height()); //--- Показываем все привязанные объекты for(int i=0;i 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 CDashboard::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 CDashboard::ColorToRGB(const color clr,double &r,double &g,double &b) { r=GetR(clr); g=GetG(clr); b=GetB(clr); } //+------------------------------------------------------------------+ //| Устанавливает прозрачность заголовка | //+------------------------------------------------------------------+ void CDashboard::SetHeaderTransparency(const uchar value) { this.m_header_alpha=value; if(this.m_header_alpha_c!=this.m_header_alpha) this.RedrawHeaderArea(clrNONE,NULL,clrNONE,value); this.m_header_alpha_c=value; } //+------------------------------------------------------------------+ //| Устанавливает прозрачность панели | //+------------------------------------------------------------------+ void CDashboard::SetTransparency(const uchar value) { this.m_alpha=value; if(this.m_alpha_c!=this.m_alpha) { this.m_canvas.Erase(::ColorToARGB(this.m_back_color,value)); this.DrawFrame(); this.RedrawHeaderArea(clrNONE,NULL,clrNONE,value); this.m_canvas.Update(false); } this.m_alpha_c=value; } //+------------------------------------------------------------------+ //| Устанавливает параметры шрифта рабочей области по умолчанию | //+------------------------------------------------------------------+ void CDashboard::SetFontParams(const string name,const int size,const uint flags=0,const uint angle=0) { if(!this.m_workspace.FontSet(name,size*-10,flags,angle)) { ::PrintFormat("%s: Failed to set font options. Error %lu",(string)__FUNCTION__,::GetLastError()); return; } this.m_font=name; this.m_font_size=size*-10; } //+------------------------------------------------------------------+ //| Устанавливает параметры шрифта заголовка по умолчанию | //+------------------------------------------------------------------+ void CDashboard::SetHeaderFontParams(const string name,const int size,const uint flags=0,const uint angle=0) { if(!this.m_canvas.FontSet(name,size*-10,flags,angle)) { ::PrintFormat("%s: Failed to set font options. Error %lu",(string)__FUNCTION__,::GetLastError()); return; } this.m_title_font=name; this.m_title_font_size=size*-10; } //+------------------------------------------------------------------+ //| Возвращает установленные параметры шрифта панели | //+------------------------------------------------------------------+ string CDashboard::FontParams(int &size,uint &flags,uint &angle) { size=this.m_workspace.FontSizeGet(); if(size<0) size=::fabs(size)/10; flags=this.m_workspace.FontFlagsGet(); angle=this.m_workspace.FontAngleGet(); return this.m_workspace.FontNameGet(); } //+------------------------------------------------------------------+ //| Возвращает установленные параметры шрифта заголовка | //+------------------------------------------------------------------+ string CDashboard::FontHeaderParams(int &size,uint &flags,uint &angle) { size=this.m_canvas.FontSizeGet(); flags=this.m_canvas.FontFlagsGet(); angle=this.m_canvas.FontAngleGet(); return this.m_canvas.FontNameGet(); } //+------------------------------------------------------------------+ //| Включает/выключает режимы работы с графиком | //+------------------------------------------------------------------+ void CDashboard::SetChartsTool(const bool flag) { //--- Если объект ведомый - уходим if(this.m_slave) return; //--- Если передан флаг true и если прокрутка графика отключена if(flag && !::ChartGetInteger(this.m_chart_id,CHART_MOUSE_SCROLL)) { //--- включаем прокрутку графика, меню правой кнопки мышки и перекрестие ::ChartSetInteger(this.m_chart_id,CHART_MOUSE_SCROLL,true); ::ChartSetInteger(this.m_chart_id,CHART_CONTEXT_MENU,true); ::ChartSetInteger(this.m_chart_id,CHART_CROSSHAIR_TOOL,true); } //--- иначе, если передан флаг false и если прокрутка графика включена else if(!flag && ::ChartGetInteger(this.m_chart_id,CHART_MOUSE_SCROLL)) { //--- отключаем прокрутку графика, меню правой кнопки мышки и перекрестие ::ChartSetInteger(this.m_chart_id,CHART_MOUSE_SCROLL,false); ::ChartSetInteger(this.m_chart_id,CHART_CONTEXT_MENU,false); ::ChartSetInteger(this.m_chart_id,CHART_CROSSHAIR_TOOL,false); } } //+------------------------------------------------------------------+ //| Выводит текстовое сообщение в указанные координаты | //+------------------------------------------------------------------+ void CDashboard::DrawText(const string text,const int x,const int y,const color clr=clrNONE,const int width=WRONG_VALUE,const int height=WRONG_VALUE) { //--- Объявим переменные для записи в них ширины и высоты текста int w=width; int h=height; //--- Если ширина и высота текста, переданные в метод, имеют нулевые значения, //--- то полностью очищается всё паространство рабочей области прозрачным цветом if(width==0 && height==0) this.m_workspace.Erase(0x00FFFFFF); //--- Иначе else { //--- Если переданные ширина и высота имеют значения по умолчанию (-1) - получаем из текста его ширину и высоту if(width==WRONG_VALUE && height==WRONG_VALUE) this.m_workspace.TextSize(text,w,h); //--- иначе, else { //--- если ширина, переданная в метод, имеет значение по умолчанию (-1) - получаем ширину из текста, либо //--- если ширина, переданная в метод, имеет значение больше нуля - используем переданную в метод ширину, либо //--- если ширина, переданная в метод, имеет нулевое значение, используем значение 1 для ширины w=(width ==WRONG_VALUE ? this.m_workspace.TextWidth(text) : width>0 ? width : 1); //--- если высота, переданная в метод, имеет значение по умолчанию (-1) - получаем высоту из текста, либо //--- если высота, переданная в метод, имеет значение больше нуля - используем переданную в метод высоту, либо //--- если высота, переданная в метод, имеет нулевое значение, используем значение 1 для высоты h=(height==WRONG_VALUE ? this.m_workspace.TextHeight(text) : height>0 ? height : 1); } //--- Заполняем пространство по указанным координатам и полученной шириной и высотой прозрачным цветом (стираем прошлую запись) this.m_workspace.FillRectangle(x,y,x+w,y+h,0x00FFFFFF); } //--- Выводим текст на очищенное от прошлого текста место и обновляем рабочую область без перерисовки экрана this.m_workspace.TextOut(x,y,text,::ColorToARGB(clr==clrNONE ? this.m_fore_color : clr)); this.m_workspace.Update(false); } //+------------------------------------------------------------------+ //| Выводит закрашенный прямоугольник в указанные координаты | //+------------------------------------------------------------------+ void CDashboard::DrawRectangleFill(const int x,const int y,const int width,const int height,const color clr,const uchar alpha) { this.m_canvas.FillRectangle(x,y,x+width,y+height,ColorToARGB(clr,alpha)); this.m_canvas.Update(); } //+------------------------------------------------------------------+ //| Создаёт новую таблицу | //+------------------------------------------------------------------+ bool CDashboard::CreateNewTable(const int id=WRONG_VALUE) { uint num=(id>WRONG_VALUE ? id : this.m_list_table.Total()); CTableData *table=new CTableData(num); this.m_list_table.Sort(); if(this.m_list_table.Search(table)!=WRONG_VALUE) { PrintFormat("%s: Error. Table with id %lu already exists in the list",__FUNCTION__,num); delete table; return false; } if(!this.m_list_table.Add(table)) { PrintFormat("%s: Error. Failed to add table with id %lu to the list",__FUNCTION__,num); delete table; return false; } return true; } //+------------------------------------------------------------------+ //| Возвращает объект табличных данных по идентификатору | //+------------------------------------------------------------------+ CTableData *CDashboard::GetTable(const uint id) { if(this.m_list_table.Total()==0) { PrintFormat("%s: Error. The list of tables is empty. First you need to create a table using CreateNewTable",__FUNCTION__); return NULL; } this.m_table_tmp.SetID(id); this.m_list_table.Sort(); int index=this.m_list_table.Search(&this.m_table_tmp); return this.m_list_table.At(index); } //+------------------------------------------------------------------+ //| Возвращает объект табличных данных по наименованию | //+------------------------------------------------------------------+ CTableData *CDashboard::GetTable(const string name) { if(this.m_list_table.Total()==0) { PrintFormat("%s: Error. The list of tables is empty. First you need to create a table using CreateNewTable",__FUNCTION__); return NULL; } this.m_table_tmp.SetName(name); this.m_list_table.Sort(1); int index=this.m_list_table.Search(&this.m_table_tmp); return this.m_list_table.At(index); } //+------------------------------------------------------------------+ //| Возвращает флаг наличия таблицы в списке по идентификатору | //+------------------------------------------------------------------+ bool CDashboard::TableIsExist(const uint id) { if(this.m_list_table.Total()==0) return false; this.m_table_tmp.SetID(id); this.m_list_table.Sort(); int index=this.m_list_table.Search(&this.m_table_tmp); return(index>WRONG_VALUE); } //+------------------------------------------------------------------+ //| Возвращает флаг наличия таблицы в списке по наименованию | //+------------------------------------------------------------------+ bool CDashboard::TableIsExist(const string name) { if(this.m_list_table.Total()==0) return false; this.m_table_tmp.SetName(name); this.m_list_table.Sort(1); int index=this.m_list_table.Search(&this.m_table_tmp); return(index>WRONG_VALUE); } //+------------------------------------------------------------------+ //| Рисует фоновую сетку | //+------------------------------------------------------------------+ void CDashboard::DrawGrid(const uint table_id, const int x,const int y,const uint rows,const uint columns,const uint row_size,const uint col_size, const color line_color=clrNONE,bool alternating_color=true) { //--- Получаем объект таблицы по идентификатору CTableData *table=this.GetTable(table_id); if(table==NULL) { PrintFormat("%s: Error. Failed to get table object with id %lu",__FUNCTION__,table_id); return; } //--- Очищаем все списки объекта табличных данных (удаляем ячейки из строк и все строки) table.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=this.m_header_h+y; //--- Рассчитываем координату Y2 (снизу) в зависимости от количества строк и их высоты int y2=y1+row_h*int(rows>0 ? rows : 1); //--- Устанавливаем координаты таблицы table.SetCoords(x1,y1-this.m_header_h,x2,y2-this.m_header_h); //--- Получаем цвет линий сетки таблицы, либо по умолчанию, либо переданный в метод color clr=(line_color==clrNONE ? C'200,200,200' : line_color); //--- Рисуем рамку таблицы this.m_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); this.m_canvas.FillRectangle(x1+1,row_y+1,x2-1,row_y+row_h-1,::ColorToARGB(new_color,this.m_alpha)); } //--- Рисуем горизонтальную линию сетки таблицы this.m_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(!table.AddRow(row_obj)) delete row_obj; //--- Устанавливаем в созданном объекте-строке его координату Y с учётом смещения от заголовка панели row_obj.SetY(row_y-this.m_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+m_canvas.Width()-2) break; //--- Рисуем вертикальную линию сетки таблицы this.m_canvas.Line(col_x,y1,col_x,y2,::ColorToARGB(clr,this.m_alpha)); //--- Получаем из объекта табличных данных количество созданных строк int total=table.RowsTotal(); //--- В цикле по строкам таблицы for(int j=0;j0) this.m_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); this.m_canvas.FillRectangle(x1+1,row_y+1,x2-1,row_y+row_h-1,::ColorToARGB(new_color,this.m_alpha)); } //--- Рисуем горизонтальную линию сетки таблицы this.m_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(!table.AddRow(row_obj)) delete row_obj; //--- Устанавливаем в созданном объекте-строке его координату Y с учётом смещения от заголовка панели row_obj.SetY(row_y-this.m_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) this.m_canvas.Line(col_x,y1,col_x,y2,::ColorToARGB(clr,this.m_alpha)); //--- Получаем из объекта табличных данных количество созданных строк int total=table.RowsTotal(); //--- В цикле по строкам таблицы for(int j=0;jthis.m_array_wpx.Size()-1) break; //--- копируем пиксель в приёмный массив из X и Y рабочей области this.m_array_wpx[n]=this.m_workspace.PixelGet(x,y); } } //+------------------------------------------------------------------+ //| Восстанавливает рабочую область из массива пикселей | //+------------------------------------------------------------------+ void CDashboard::RestoreWorkspace(void) { //--- Если массив пустой - уходим if(this.m_array_wpx.Size()==0) return; uint n=0; //--- В цикле по высоте рабочей области (координата Y пикселя) for(int y=0;ythis.m_array_wpx.Size()-1) break; //--- копируем пиксель из массива в координаты X и Y рабочей области this.m_workspace.PixelSet(x,y,this.m_array_wpx[n]); } } //+------------------------------------------------------------------+ //| Сохраняет фон панели в массив пикселей | //+------------------------------------------------------------------+ void CDashboard::SaveBackground(void) { //--- Рассчитываем необходимый размер массива (ширина * высота панели) uint size=this.m_canvas.Width()*this.m_canvas.Height(); //--- Если размер массива не равен рассчитанному - изменяем его if(this.m_array_ppx.Size()!=size) { ::ResetLastError(); if(::ArrayResize(this.m_array_ppx,size)!=size) { ::PrintFormat("%s: ArrayResize failed. Error %lu",(string)__FUNCTION__,::GetLastError()); return; } } uint n=0; //--- В цикле по высоте панели (координата Y пикселя) for(int y=0;ythis.m_array_ppx.Size()-1) break; //--- копируем пиксель в приёмный массив из X и Y панели this.m_array_ppx[n]=this.m_canvas.PixelGet(x,y); } } //+------------------------------------------------------------------+ //| Восстанавливает фон панели из массива пикселей | //+------------------------------------------------------------------+ void CDashboard::RestoreBackground(void) { //--- Если массив пустой - уходим if(this.m_array_ppx.Size()==0) return; uint n=0; //--- В цикле по высоте панели (координата Y пикселя) for(int y=0;ythis.m_array_ppx.Size()-1) break; //--- копируем пиксель из массива в координаты X и Y панели this.m_canvas.PixelSet(x,y,this.m_array_ppx[n]); } } //+------------------------------------------------------------------+ //| Скрывает панель | //+------------------------------------------------------------------+ void CDashboard::Hide(const bool redraw=false) { ::ObjectSetInteger(this.m_chart_id,this.m_workspace.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS); ::ObjectSetInteger(this.m_chart_id,this.m_canvas.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS); if(redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| Показывает панель | //+------------------------------------------------------------------+ void CDashboard::Show(const bool redraw=false) { ::ObjectSetInteger(this.m_chart_id,this.m_canvas.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS); if(!this.m_minimized) ::ObjectSetInteger(this.m_chart_id,this.m_workspace.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS); if(redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| Переносит панель на передний план | //+------------------------------------------------------------------+ void CDashboard::BringToTop(void) { if(this.IsHidden()) return; this.Hide(false); this.Show(true); for(int i=0;i