//+------------------------------------------------------------------+ //| Controls.mqh | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| Включаемые библиотеки | //+------------------------------------------------------------------+ #include "Base.mqh" //+------------------------------------------------------------------+ //| Макроподстановки | //+------------------------------------------------------------------+ #define DEF_LABEL_W 50 // Ширина текстовой метки по умолчанию #define DEF_LABEL_H 16 // Высота текстовой метки по умолчанию #define DEF_BUTTON_W 60 // Ширина кнопки по умолчанию #define DEF_BUTTON_H 16 // Высота кнопки по умолчанию #define DEF_TABLE_ROW_H 16 // Высота строки таблицы по умолчанию #define DEF_TABLE_HEADER_H 20 // Высота заголовка таблицы по умолчанию #define DEF_TABLE_COLUMN_MIN_W 12 // Минимальная ширина колонки таблицы #define DEF_PANEL_W 80 // Ширина панели по умолчанию #define DEF_PANEL_H 80 // Высота панели по умолчанию #define DEF_PANEL_MIN_W 60 // Минимальная ширина панели #define DEF_PANEL_MIN_H 60 // Минимальная высота панели #define DEF_SCROLLBAR_TH 13 // Толщина полосы прокрутки по умолчанию #define DEF_THUMB_MIN_SIZE 8 // Минимальная толщина ползунка полосы прокрутки #define DEF_AUTOREPEAT_DELAY 500 // Задержка перед запуском автоповтора #define DEF_AUTOREPEAT_INTERVAL 100 // Частота автоповторов #define DEF_HINT_NAME_TOOLTIP "HintTooltip" // Наименование подсказки "тултип" #define DEF_HINT_NAME_HORZ "HintHORZ" // Наименование подсказки "Двойная горизонтальная стрелка" #define DEF_HINT_NAME_VERT "HintVERT" // Наименование подсказки "Двойная вертикальная стрелка" #define DEF_HINT_NAME_NWSE "HintNWSE" // Наименование подсказки "Двойная стрелка сверху-лево" --- низ-право (NorthWest-SouthEast) #define DEF_HINT_NAME_NESW "HintNESW" // Наименование подсказки "Двойная стрелка снизу-лево" --- верх-право (NorthEast-SouthWest) #define DEF_HINT_NAME_SHIFT_HORZ "HintShiftHORZ" // Наименование подсказки "Стрелка горизонтального смещения" #define DEF_HINT_NAME_SHIFT_VERT "HintShiftVERT" // Наименование подсказки "Стрелка вертикального смещения" //+------------------------------------------------------------------+ //| Перечисления | //+------------------------------------------------------------------+ enum ENUM_ELEMENT_SORT_BY // Сравниваемые свойства { ELEMENT_SORT_BY_ID = BASE_SORT_BY_ID, // Сравнение по идентификатору элемента ELEMENT_SORT_BY_NAME = BASE_SORT_BY_NAME, // Сравнение по наименованию элемента ELEMENT_SORT_BY_X = BASE_SORT_BY_X, // Сравнение по координате X элемента ELEMENT_SORT_BY_Y = BASE_SORT_BY_Y, // Сравнение по координате Y элемента ELEMENT_SORT_BY_WIDTH= BASE_SORT_BY_WIDTH, // Сравнение по ширине элемента ELEMENT_SORT_BY_HEIGHT= BASE_SORT_BY_HEIGHT, // Сравнение по высоте элемента ELEMENT_SORT_BY_ZORDER= BASE_SORT_BY_ZORDER, // Сравнение по Z-order элемента ELEMENT_SORT_BY_TEXT, // Сравнение по тексту элемента ELEMENT_SORT_BY_COLOR_BG, // Сравнение по цвету фона элемента ELEMENT_SORT_BY_ALPHA_BG, // Сравнение по прозрачности фона элемента ELEMENT_SORT_BY_COLOR_FG, // Сравнение по цвету переднего плана элемента ELEMENT_SORT_BY_ALPHA_FG, // Сравнение по прозрачности переднего плана элемента ELEMENT_SORT_BY_STATE, // Сравнение по состоянию элемента ELEMENT_SORT_BY_GROUP, // Сравнение по группе элемента }; enum ENUM_TABLE_SORT_MODE // Режимы сортировки столбцов таблиц { TABLE_SORT_MODE_NONE, // Сортировка отсутствует TABLE_SORT_MODE_ASC, // Сортировка по возрастанию TABLE_SORT_MODE_DESC, // Сортировка по убыванию }; enum ENUM_HINT_TYPE // Типы подсказок { HINT_TYPE_TOOLTIP, // Тултип HINT_TYPE_ARROW_HORZ, // Двойная горизонтальная стрелка HINT_TYPE_ARROW_VERT, // Двойная вертикальная стрелка HINT_TYPE_ARROW_NWSE, // Двойная стрелка сверху-лево --- низ-право (NorthWest-SouthEast) HINT_TYPE_ARROW_NESW, // Двойная стрелка снизу-лево --- верх-право (NorthEast-SouthWest) HINT_TYPE_ARROW_SHIFT_HORZ, // Стрелка горизонтального смещения HINT_TYPE_ARROW_SHIFT_VERT, // Стрелка вертикального смещения }; //+------------------------------------------------------------------+ //| Функции | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Классы | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс связанного списка графических элементов | //+------------------------------------------------------------------+ class CListElm : public CList { protected: ENUM_ELEMENT_TYPE m_element_type; // Тип создаваемого объекта в CreateElement() public: //--- Установка типа элемента void SetElementType(const ENUM_ELEMENT_TYPE type) { this.m_element_type=type; } //--- Виртуальный метод (1) загрузки списка из файла, (2) создания элемента списка virtual bool Load(const int file_handle); virtual CObject *CreateElement(void); }; //+------------------------------------------------------------------+ //| Загрузка списка из файла | //+------------------------------------------------------------------+ bool CListElm::Load(const int file_handle) { //--- Переменные CObject *node; bool result=true; //--- Проверяем хэндл if(file_handle==INVALID_HANDLE) return(false); //--- Загрузка и проверка маркера начала списка - 0xFFFFFFFFFFFFFFFF if(::FileReadLong(file_handle)!=MARKER_START_DATA) return(false); //--- Загрузка и проверка типа списка if(::FileReadInteger(file_handle,INT_VALUE)!=this.Type()) return(false); //--- Чтение размера списка (количество объектов) uint num=::FileReadInteger(file_handle,INT_VALUE); //--- Последовательно заново создаём элементы списка с помощью вызова метода Load() объектов node this.Clear(); for(uint i=0; iobj.Name() ? 1 : this.Name() obj.Alpha() ? 1 : this.Alpha() obj.X() ? 1 : this.X() obj.Y() ? 1 : this.Y() obj.Width() ? 1 : this.Width() obj.Height() ? 1 : this.Height() obj.ID() ? 1 : this.ID() 0) this.m_canvas.FillRectangle(x+5,y,x+7+tw,y+th,clrNULL); this.m_canvas.TextOut(x+6,y-1,text,::ColorToARGB(clr_text, alpha)); if(update) this.m_canvas.Update(false); return true; } //+------------------------------------------------------------------+ //| CImagePainter::Сохранение в файл | //+------------------------------------------------------------------+ bool CImagePainter::Save(const int file_handle) { //--- Сохраняем данные родительского объекта if(!CBaseObj::Save(file_handle)) return false; //--- Сохраняем прозрачность if(::FileWriteInteger(file_handle,this.m_alpha,INT_VALUE)!=INT_VALUE) return false; //--- Сохраняем данные области if(!this.m_bound.Save(file_handle)) return false; //--- Всё успешно return true; } //+------------------------------------------------------------------+ //| CImagePainter::Загрузка из файла | //+------------------------------------------------------------------+ bool CImagePainter::Load(const int file_handle) { //--- Загружаем данные родительского объекта if(!CBaseObj::Load(file_handle)) return false; //--- Загружаем прозрачность this.m_alpha=(uchar)::FileReadInteger(file_handle,INT_VALUE); //--- Загружаем данные области if(!this.m_bound.Load(file_handle)) return false; //--- Всё успешно return true; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Базовый класс графического элемента | //+------------------------------------------------------------------+ class CElementBase : public CCanvasBase { protected: CImagePainter m_painter; // Класс рисования CListElm m_list_hints; // Список подсказок int m_group; // Группа элементов bool m_visible_in_container; // Флаг видимости в контейнере //--- Добавляет указанный объект-подсказку в список bool AddHintToList(CVisualHint *obj); //--- Создаёт и добавляет новый объект-подсказку в список CVisualHint *CreateAndAddNewHint(const ENUM_HINT_TYPE type, const string user_name, const int w, const int h); //--- Добавляет существующий объект-подсказку в список CVisualHint *AddHint(CVisualHint *obj, const int dx, const int dy); //--- (1) Добавляет в список, (2) удаляет из списка объекты-подсказки со стрелками virtual bool AddHintsArrowed(void); bool DeleteHintsArrowed(void); //--- Отображает курсор изменения размеров virtual bool ShowCursorHint(const ENUM_CURSOR_REGION edge,int x,int y); //--- Обработчик перетаскивания граней и углов элемента virtual void ResizeActionDragHandler(const int x, const int y); //--- Обработчики изменения размеров элемента по сторонам и углам virtual bool ResizeZoneLeftHandler(const int x, const int y); virtual bool ResizeZoneRightHandler(const int x, const int y); virtual bool ResizeZoneTopHandler(const int x, const int y); virtual bool ResizeZoneBottomHandler(const int x, const int y); virtual bool ResizeZoneLeftTopHandler(const int x, const int y); virtual bool ResizeZoneRightTopHandler(const int x, const int y); virtual bool ResizeZoneLeftBottomHandler(const int x, const int y); virtual bool ResizeZoneRightBottomHandler(const int x, const int y); //--- Возвращает указатель на подсказку по (1) индексу, (2) идентификатору, (3) наименованию CVisualHint *GetHintAt(const int index); CVisualHint *GetHint(const int id); CVisualHint *GetHint(const string name); //--- Создаёт новую подсказку CVisualHint *CreateNewHint(const ENUM_HINT_TYPE type, const string object_name, const string user_name, const int id, const int x, const int y, const int w, const int h); //--- (1) Отображает указанную подсказку со стрелками, (2) скрывает все подсказки void ShowHintArrowed(const ENUM_HINT_TYPE type,const int x,const int y); void HideHintsAll(const bool chart_redraw); public: //--- Возвращает себя CElementBase *GetObject(void) { return &this; } //--- Возвращает указатель на (1) класс рисования, (2) список подсказок CImagePainter *Painter(void) { return &this.m_painter; } CListElm *GetListHints(void) { return &this.m_list_hints; } //--- Создаёт и добавляет (1) новый, (2) ранее созданный объект-подсказку (только тултип) в список CVisualHint *InsertNewTooltip(const ENUM_HINT_TYPE type, const string user_name, const int w, const int h); CVisualHint *InsertTooltip(CVisualHint *obj, const int dx, const int dy); //--- (1) Устанавливает координаты, (2) изменяет размеры области изображения void SetImageXY(const int x,const int y) { this.m_painter.SetXY(x,y); } void SetImageSize(const int w,const int h) { this.m_painter.SetSize(w,h); } //--- Устанавливает координаты и размеры области изображения void SetImageBound(const int x,const int y,const int w,const int h) { this.SetImageXY(x,y); this.SetImageSize(w,h); } //--- Возвращает координату (1) X, (2) Y, (3) ширину, (4) высоту, (5) правую, (6) нижнюю границу области изображения int ImageX(void) const { return this.m_painter.X(); } int ImageY(void) const { return this.m_painter.Y(); } int ImageWidth(void) const { return this.m_painter.Width(); } int ImageHeight(void) const { return this.m_painter.Height(); } int ImageRight(void) const { return this.m_painter.Right(); } int ImageBottom(void) const { return this.m_painter.Bottom(); } //--- (1) Устанавливает, (2) возвращает группу элементов virtual void SetGroup(const int group) { this.m_group=group; } int Group(void) const { return this.m_group; } //--- Устанавливает флаг возможности изменения размеров virtual void SetResizable(const bool flag); //--- (1) Устанавливает, (2) возвращает флаг видимости в контейнере virtual void SetVisibleInContainer(const bool flag) { this.m_visible_in_container=flag; } bool IsVisibleInContainer(void) const { return this.m_visible_in_container;} //--- Возвращает описание объекта virtual string Description(void); //--- Обработчик изменения размеров (Resize) virtual void OnResizeZoneEvent(const int id, const long lparam, const double dparam, const string sparam); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle); virtual bool Load(const int file_handle); virtual int Type(void) const { return(ELEMENT_TYPE_ELEMENT_BASE);} //--- Конструкторы/деструктор CElementBase(void) { this.m_painter.CanvasAssign(this.GetForeground()); this.m_visible_in_container=true; } CElementBase(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CElementBase(void) { this.m_list_hints.Clear(); } }; //+-----------------------------------------------------------------------+ //| CElementBase::Конструктор параметрический. Строит элемент в указанном | //| окне указанного графика с указанными текстом, координатами и размерами| //+-----------------------------------------------------------------------+ CElementBase::CElementBase(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CCanvasBase(object_name,chart_id,wnd,x,y,w,h),m_group(-1) { //--- Объекту рисования назначаем канвас переднего плана и //--- обнуляем координаты и размеры, что делает его неактивным, //--- устанавливаем флаг видимости элемента в контейнере this.m_painter.CanvasAssign(this.GetForeground()); this.m_painter.SetXY(0,0); this.m_painter.SetSize(0,0); this.m_visible_in_container=true; } //+------------------------------------------------------------------+ //| CElementBase::Сравнение двух объектов | //+------------------------------------------------------------------+ int CElementBase::Compare(const CObject *node,const int mode=0) const { if(node==NULL) return -1; const CElementBase *obj=node; switch(mode) { case ELEMENT_SORT_BY_NAME : return(this.Name() >obj.Name() ? 1 : this.Name() obj.X() ? 1 : this.X() obj.Y() ? 1 : this.Y() obj.Width() ? 1 : this.Width() obj.Height() ? 1 : this.Height() obj.BackColor() ? 1 : this.BackColor() obj.ForeColor() ? 1 : this.ForeColor() obj.AlphaBG() ? 1 : this.AlphaBG() obj.AlphaFG() ? 1 : this.AlphaFG() obj.State() ? 1 : this.State() obj.Group() ? 1 : this.Group() obj.ObjectZOrder() ? 1 : this.ObjectZOrder() obj.ID() ? 1 : this.ID() -1); } //--- Возвращаем списку изначальную сортировку this.m_list_hints.Sort(sort_mode); //--- Элемент с таким идентификатором уже есть в списке - возвращаем false return false; } //+------------------------------------------------------------------+ //| CElementBase::Создаёт новую подсказку | //+------------------------------------------------------------------+ CVisualHint *CElementBase::CreateNewHint(const ENUM_HINT_TYPE type,const string object_name,const string user_name,const int id, const int x,const int y,const int w,const int h) { //--- Создаём новый объект-подсказку CVisualHint *obj=new CVisualHint(object_name,this.m_chart_id,this.m_wnd,x,y,w,h); if(obj==NULL) { ::PrintFormat("%s: Error: Failed to create Hint object",__FUNCTION__); return NULL; } //--- Устанавливаем идентификатор, наименование и тип подсказки obj.SetID(id); obj.SetName(user_name); obj.SetHintType(type); //--- Возвращаем указатель на созданный объект return obj; } //+------------------------------------------------------------------+ //| CElementBase::Создаёт и добавляет новый объект-подсказку в список| //+------------------------------------------------------------------+ CVisualHint *CElementBase::CreateAndAddNewHint(const ENUM_HINT_TYPE type,const string user_name,const int w,const int h) { //--- Создаём имя графического объекта int obj_total=this.m_list_hints.Total(); string obj_name=this.NameFG()+"_HNT"+(string)obj_total; //--- Рассчитываем координаты объекта ниже и правее правого нижнего угла элемента int x=this.Right()+1; int y=this.Bottom()+1; //--- Создаём новый объект-подсказку CVisualHint *obj=this.CreateNewHint(type,obj_name,user_name,obj_total,x,y,w,h); //--- Если новый объект не создан - возвращаем NULL if(obj==NULL) return NULL; //--- Устанавливаем пределы изображения, контейнер и z-order obj.SetImageBound(0,0,this.Width(),this.Height()); obj.SetContainerObj(&this); obj.ObjectSetZOrder(this.ObjectZOrder()+1); //--- Если созданный элемент не добавлен в список - сообщаем об этом, удаляем созданный элемент и возвращаем NULL if(!this.AddHintToList(obj)) { ::PrintFormat("%s: Error. Failed to add Hint object with ID %d to list",__FUNCTION__,obj.ID()); delete obj; return NULL; } //--- Возвращаем указатель на созданный и присоединённый объект return obj; } //+------------------------------------------------------------------+ //| CElementBase::Добавляет существующий объект-подсказку в список | //+------------------------------------------------------------------+ CVisualHint *CElementBase::AddHint(CVisualHint *obj,const int dx,const int dy) { //--- Если передан объект не с типом подсказки - возвращаем NULL if(obj.Type()!=ELEMENT_TYPE_HINT) { ::PrintFormat("%s: Error. Only an object with the Hint type can be used here. The element type \"%s\" was passed",__FUNCTION__,ElementDescription((ENUM_ELEMENT_TYPE)obj.Type())); return NULL; } //--- Запоминаем идентификатор объекта и устанавливаем новый int id=obj.ID(); obj.SetID(this.m_list_hints.Total()); //--- Добавляем объект в список; при неудаче - сообщаем об этом, устанавливаем начальный идентификатор и возвращаем NULL if(!this.AddHintToList(obj)) { ::PrintFormat("%s: Error. Failed to add Hint object to list",__FUNCTION__); obj.SetID(id); return NULL; } //--- Устанавливаем новые координаты, контейнер и z-order объекта int x=this.X()+dx; int y=this.Y()+dy; obj.Move(x,y); obj.SetContainerObj(&this); obj.ObjectSetZOrder(this.ObjectZOrder()+1); //--- Возвращаем указатель на присоединённый объект return obj; } //+------------------------------------------------------------------+ //| CElementBase::Добавляет в список объекты-подсказки со стрелками | //+------------------------------------------------------------------+ bool CElementBase::AddHintsArrowed(void) { //--- Массивы наименований и типов подсказок string array[4]={DEF_HINT_NAME_HORZ,DEF_HINT_NAME_VERT,DEF_HINT_NAME_NWSE,DEF_HINT_NAME_NESW}; ENUM_HINT_TYPE type[4]={HINT_TYPE_ARROW_HORZ,HINT_TYPE_ARROW_VERT,HINT_TYPE_ARROW_NWSE,HINT_TYPE_ARROW_NESW}; //--- В цикле создаём четыре подсказки со стрелками bool res=true; for(int i=0;i<(int)array.Size();i++) res &=(this.CreateAndAddNewHint(type[i],array[i],0,0)!=NULL); //--- Если были ошибки при создании - возвращаем false if(!res) return false; //--- В цикле по массиву наименований объектов-подсказок for(int i=0;i<(int)array.Size();i++) { //--- получаем очередной объект по наименованию, CVisualHint *obj=this.GetHint(array[i]); if(obj==NULL) continue; //--- скрываем объект и рисуем внешний вид (стрелки в соответствии с типом объекта) obj.Hide(false); obj.Draw(false); } //--- Всё успешно return true; } //+------------------------------------------------------------------+ //| CElementBase::Удаляет из списка объекты-подсказки со стрелками | //+------------------------------------------------------------------+ bool CElementBase::DeleteHintsArrowed(void) { //--- В цикле по списку объектов-подсказок bool res=true; for(int i=this.m_list_hints.Total()-1;i>=0;i--) { //--- получаем очередной объект и, если это не тултип - удаляем его CVisualHint *obj=this.m_list_hints.GetNodeAtIndex(i); if(obj!=NULL && obj.HintType()!=HINT_TYPE_TOOLTIP) res &=this.m_list_hints.DeleteCurrent(); } //--- Возвращаем результат удаления подсказок со стрелками return res; } //+------------------------------------------------------------------+ //| CElementBase::Создаёт и добавляет новый объект-подсказку в список| //+------------------------------------------------------------------+ CVisualHint *CElementBase::InsertNewTooltip(const ENUM_HINT_TYPE type,const string user_name,const int w,const int h) { //--- Если тип подсказки не тултип - сообщаем об этом и возвращаем NULL if(type!=HINT_TYPE_TOOLTIP) { ::PrintFormat("%s: Error. Only a tooltip can be added to an element",__FUNCTION__); return NULL; } //--- Создаём и добавляем новый объект-подсказку в список; //--- Возвращаем указатель на созданный и присоединённый объект return this.CreateAndAddNewHint(type,user_name,w,h); } //+------------------------------------------------------------------+ //| CElementBase::Добавляет ранее созданный объект-подсказку в список| //+------------------------------------------------------------------+ CVisualHint *CElementBase::InsertTooltip(CVisualHint *obj,const int dx,const int dy) { //--- Если передан пустой или невалидный указатель на объект - возвращаем NULL if(::CheckPointer(obj)==POINTER_INVALID) { ::PrintFormat("%s: Error. Empty element passed",__FUNCTION__); return NULL; } //--- Если тип подсказки не тиултип - сообщаем об этом и возвращаем NULL if(obj.HintType()!=HINT_TYPE_TOOLTIP) { ::PrintFormat("%s: Error. Only a tooltip can be added to an element",__FUNCTION__); return NULL; } //--- Добавляем указанный объект-подсказку в список; //--- Возвращаем указатель на созданный и присоединённый объект return this.AddHint(obj,dx,dy); } //+------------------------------------------------------------------+ //| CElementBase::Отображает указанную подсказку | //| в указанных координатах | //+------------------------------------------------------------------+ void CElementBase::ShowHintArrowed(const ENUM_HINT_TYPE type,const int x,const int y) { CVisualHint *hint=NULL; // Указатель на искомый объект //--- В цикле по списку объектов подсказок for(int i=0;iobj.Name() ? 1 : this.Name() obj.Text() ? 1 : this.Text() obj.X() ? 1 : this.X() obj.Y() ? 1 : this.Y() obj.Width() ? 1 : this.Width() obj.Height() ? 1 : this.Height() obj.BackColor() ? 1 : this.BackColor() obj.ForeColor() ? 1 : this.ForeColor() obj.AlphaBG() ? 1 : this.AlphaBG() obj.AlphaFG() ? 1 : this.AlphaFG() obj.State() ? 1 : this.State() obj.ObjectZOrder() ? 1 : this.ObjectZOrder() obj.ID() ? 1 : this.ID() 0 && h>0) this.m_foreground.FillRectangle(this.AdjX(this.m_text_x),this.AdjY(this.m_text_y),this.AdjX(this.m_text_x+w),this.AdjY(this.m_text_y+h),clrNULL); //--- Иначе - очищаем полностью весь передний план else this.m_foreground.Erase(clrNULL); } //+------------------------------------------------------------------+ //| CLabel::Выводит текст | //+------------------------------------------------------------------+ void CLabel::DrawText(const int dx,const int dy,const string text,const bool chart_redraw) { //--- Очищаем прошлый текст и устанавливаем новый this.ClearText(); this.SetText(text); //--- Выводим установленный текст this.m_foreground.TextOut(this.AdjX(dx),this.AdjY(dy),this.Text(),::ColorToARGB(this.ForeColor(),this.AlphaFG())); //--- Если текст выходит за правую границу объекта if(this.Width()-dx0 && h>0) { //--- Стираем текст у правой границы объекта по размеру текста "троеточие" и заменяем троеточием окончание текста метки this.m_foreground.FillRectangle(this.AdjX(this.Width()-w),this.AdjY(this.m_text_y),this.AdjX(this.Width()),this.AdjY(this.m_text_y+h),clrNULL); this.m_foreground.TextOut(this.AdjX(this.Width()-w),this.AdjY(dy),"...",::ColorToARGB(this.ForeColor(),this.AlphaFG())); } } //--- Обновляем канвас переднего плана и запоминаем новые координаты текста this.m_foreground.Update(chart_redraw); this.m_text_x=dx; this.m_text_y=dy; //--- Запоминаем нарисованный текст как прошлый this.SetTextPrev(text); } //+------------------------------------------------------------------+ //| CLabel::Рисует внешний вид | //+------------------------------------------------------------------+ void CLabel::Draw(const bool chart_redraw) { this.DrawText(this.m_text_x,this.m_text_y,this.Text(),chart_redraw); } //+------------------------------------------------------------------+ //| CLabel::Сохранение в файл | //+------------------------------------------------------------------+ bool CLabel::Save(const int file_handle) { //--- Сохраняем данные родительского объекта if(!CElementBase::Save(file_handle)) return false; //--- Сохраняем текст if(::FileWriteArray(file_handle,this.m_text)!=sizeof(this.m_text)) return false; //--- Сохраняем предыдущий текст if(::FileWriteArray(file_handle,this.m_text_prev)!=sizeof(this.m_text_prev)) return false; //--- Сохраняем координату X текста if(::FileWriteInteger(file_handle,this.m_text_x,INT_VALUE)!=INT_VALUE) return false; //--- Сохраняем координату Y текста if(::FileWriteInteger(file_handle,this.m_text_y,INT_VALUE)!=INT_VALUE) return false; //--- Всё успешно return true; } //+------------------------------------------------------------------+ //| CLabel::Загрузка из файла | //+------------------------------------------------------------------+ bool CLabel::Load(const int file_handle) { //--- Загружаем данные родительского объекта if(!CElementBase::Load(file_handle)) return false; //--- Загружаем текст if(::FileReadArray(file_handle,this.m_text)!=sizeof(this.m_text)) return false; //--- Загружаем предыдущий текст if(::FileReadArray(file_handle,this.m_text_prev)!=sizeof(this.m_text_prev)) return false; //--- Загружаем координату X текста this.m_text_x=::FileReadInteger(file_handle,INT_VALUE); //--- Загружаем координату Y текста this.m_text_y=::FileReadInteger(file_handle,INT_VALUE); //--- Всё успешно return true; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс простой кнопки | //+------------------------------------------------------------------+ class CButton : public CLabel { public: //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle) { return CLabel::Save(file_handle); } virtual bool Load(const int file_handle) { return CLabel::Load(file_handle); } virtual int Type(void) const { return(ELEMENT_TYPE_BUTTON); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(const string text); virtual void InitColors(void){} //--- Обработчик события таймера virtual void TimerEventHandler(void); //--- Конструкторы/деструктор CButton(void); CButton(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CButton (void) {} }; //+------------------------------------------------------------------+ //| CButton::Конструктор по умолчанию. Строит кнопку в главном окне | //| текущего графика в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CButton::CButton(void) : CLabel("Button","Button",::ChartID(),0,0,0,DEF_BUTTON_W,DEF_BUTTON_H) { //--- Инициализация this.Init(""); } //+---------------------------------------------------------------------+ //| CButton::Конструктор параметрический. Строит кнопку в указанном окне| //| указанного графика с указанными текстом, координатами и размерами | //+---------------------------------------------------------------------+ CButton::CButton(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CLabel(object_name,text,chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButton::Инициализация | //+------------------------------------------------------------------+ void CButton::Init(const string text) { //--- Устанавливаем состояние по умолчанию this.SetState(ELEMENT_STATE_DEF); //--- Фон и передний план - непрозрачные this.SetAlpha(255); //--- Смещение текста от левого края кнопки по умолчанию this.m_text_x=2; //--- Автоповтор нажатий отключен this.m_autorepeat_flag=false; } //+------------------------------------------------------------------+ //| CButton::Сравнение двух объектов | //+------------------------------------------------------------------+ int CButton::Compare(const CObject *node,const int mode=0) const { return CLabel::Compare(node,mode); } //+------------------------------------------------------------------+ //| CButton::Рисует внешний вид | //+------------------------------------------------------------------+ void CButton::Draw(const bool chart_redraw) { //--- Заливаем кнопку цветом фона, рисуем рамку и обновляем канвас фона this.Fill(this.BackColor(),false); this.m_background.Rectangle(this.AdjX(0),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG())); this.m_background.Update(false); //--- Выводим текст кнопки CLabel::Draw(false); //--- Если указано - обновляем график if(chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| Обработчик события таймера | //+------------------------------------------------------------------+ void CButton::TimerEventHandler(void) { if(this.m_autorepeat_flag) this.m_autorepeat.Process(); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс двухпозиционной кнопки | //+------------------------------------------------------------------+ class CButtonTriggered : public CButton { public: //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle) { return CButton::Save(file_handle); } virtual bool Load(const int file_handle) { return CButton::Load(file_handle); } virtual int Type(void) const { return(ELEMENT_TYPE_BUTTON_TRIGGERED); } //--- Обработчик событий нажатий кнопок мышки (Press) virtual void OnPressEvent(const int id, const long lparam, const double dparam, const string sparam); //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(const string text); virtual void InitColors(void); //--- Конструкторы/деструктор CButtonTriggered(void); CButtonTriggered(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CButtonTriggered (void) {} }; //+------------------------------------------------------------------+ //| CButtonTriggered::Конструктор по умолчанию. | //| Строит кнопку в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CButtonTriggered::CButtonTriggered(void) : CButton("Button","Button",::ChartID(),0,0,0,DEF_BUTTON_W,DEF_BUTTON_H) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButtonTriggered::Конструктор параметрический. | //| Строит кнопку в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CButtonTriggered::CButtonTriggered(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CButton(object_name,text,chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButtonTriggered::Инициализация | //+------------------------------------------------------------------+ void CButtonTriggered::Init(const string text) { //--- Инициализируем цвета по умолчанию this.InitColors(); } //+------------------------------------------------------------------+ //| CButtonTriggered::Инициализация цветов объекта по умолчанию | //+------------------------------------------------------------------+ void CButtonTriggered::InitColors(void) { //--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона this.InitBackColors(clrWhiteSmoke); this.InitBackColorsAct(clrLightBlue); this.BackColorToDefault(); //--- Инициализируем цвета переднего плана для обычного и активированного состояний и делаем его текущим цветом текста this.InitForeColors(clrBlack); this.InitForeColorsAct(clrBlack); this.ForeColorToDefault(); //--- Инициализируем цвета рамки для обычного и активированного состояний и делаем его текущим цветом рамки this.InitBorderColors(clrDarkGray); this.InitBorderColorsAct(clrGreen); this.BorderColorToDefault(); //--- Инициализируем цвет рамки и цвет переднего плана для заблокированного элемента this.InitBorderColorBlocked(clrLightGray); this.InitForeColorBlocked(clrSilver); } //+------------------------------------------------------------------+ //| CButtonTriggered::Сравнение двух объектов | //+------------------------------------------------------------------+ int CButtonTriggered::Compare(const CObject *node,const int mode=0) const { return CButton::Compare(node,mode); } //+------------------------------------------------------------------+ //| CButtonTriggered::Рисует внешний вид | //+------------------------------------------------------------------+ void CButtonTriggered::Draw(const bool chart_redraw) { //--- Заливаем кнопку цветом фона, рисуем рамку и обновляем канвас фона this.Fill(this.BackColor(),false); this.m_background.Rectangle(this.AdjX(0),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG())); this.m_background.Update(false); //--- Выводим текст кнопки CLabel::Draw(false); //--- Если указано - обновляем график if(chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| CButtonTriggered::Обработчик событий нажатий кнопок мышки (Press)| //+------------------------------------------------------------------+ void CButtonTriggered::OnPressEvent(const int id,const long lparam,const double dparam,const string sparam) { //--- Устанавливаем состояние кнопки, обратное уже установленному ENUM_ELEMENT_STATE state=(this.State()==ELEMENT_STATE_DEF ? ELEMENT_STATE_ACT : ELEMENT_STATE_DEF); this.SetState(state); //--- Вызываем обработчик родительского объекта с указанием идентификатора в lparam и состояния в dparam CCanvasBase::OnPressEvent(id,this.m_id,this.m_state,sparam); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс кнопки со стрелкой вверх | //+------------------------------------------------------------------+ class CButtonArrowUp : public CButton { public: //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle) { return CButton::Save(file_handle); } virtual bool Load(const int file_handle) { return CButton::Load(file_handle); } virtual int Type(void) const { return(ELEMENT_TYPE_BUTTON_ARROW_UP);} //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(const string text); virtual void InitColors(void){} //--- Конструкторы/деструктор CButtonArrowUp(void); CButtonArrowUp(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CButtonArrowUp (void) {} }; //+------------------------------------------------------------------+ //| CButtonArrowUp::Конструктор по умолчанию. | //| Строит кнопку в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CButtonArrowUp::CButtonArrowUp(void) : CButton("Arrow Up Button","",::ChartID(),0,0,0,DEF_BUTTON_W,DEF_BUTTON_H) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButtonArrowUp::Конструктор параметрический. | //| Строит кнопку в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CButtonArrowUp::CButtonArrowUp(const string object_name, const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CButton(object_name,text,chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButtonArrowUp::Инициализация | //+------------------------------------------------------------------+ void CButtonArrowUp::Init(const string text) { //--- Инициализируем цвета по умолчанию this.InitColors(); //--- Устанавливаем смещение и размеры области изображенеия this.SetImageBound(1,1,this.Height()-2,this.Height()-2); //--- Инициализируем счётчики автоповтора this.m_autorepeat_flag=true; //--- Инициализируем свойства объекта управления автоповтором событий this.m_autorepeat.SetChartID(this.m_chart_id); this.m_autorepeat.SetID(0); this.m_autorepeat.SetName("ButtUpAutorepeatControl"); this.m_autorepeat.SetDelay(DEF_AUTOREPEAT_DELAY); this.m_autorepeat.SetInterval(DEF_AUTOREPEAT_INTERVAL); this.m_autorepeat.SetEvent(CHARTEVENT_OBJECT_CLICK,0,0,this.NameFG()); } //+------------------------------------------------------------------+ //| CButtonArrowUp::Сравнение двух объектов | //+------------------------------------------------------------------+ int CButtonArrowUp::Compare(const CObject *node,const int mode=0) const { return CButton::Compare(node,mode); } //+------------------------------------------------------------------+ //| CButtonArrowUp::Рисует внешний вид | //+------------------------------------------------------------------+ void CButtonArrowUp::Draw(const bool chart_redraw) { //--- Заливаем кнопку цветом фона, рисуем рамку и обновляем канвас фона this.Fill(this.BackColor(),false); this.m_background.Rectangle(this.AdjX(0),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG())); this.m_background.Update(false); //--- Выводим текст кнопки CLabel::Draw(false); //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Задаём цвет стрелки для обычного и заблокированного состояний кнопки и рисуем стрелку вверх color clr=(!this.IsBlocked() ? this.GetForeColorControl().NewColor(this.ForeColor(),90,90,90) : this.ForeColor()); this.m_painter.ArrowUp(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),clr,this.AlphaFG(),true); //--- Если указано - обновляем график if(chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс кнопки со стрелкой вниз | //+------------------------------------------------------------------+ class CButtonArrowDown : public CButton { public: //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle) { return CButton::Save(file_handle); } virtual bool Load(const int file_handle) { return CButton::Load(file_handle); } virtual int Type(void) const { return(ELEMENT_TYPE_BUTTON_ARROW_DOWN); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(const string text); virtual void InitColors(void){} //--- Конструкторы/деструктор CButtonArrowDown(void); CButtonArrowDown(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CButtonArrowDown (void) {} }; //+------------------------------------------------------------------+ //| CButtonArrowDown::Конструктор по умолчанию. | //| Строит кнопку в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CButtonArrowDown::CButtonArrowDown(void) : CButton("Arrow Up Button","",::ChartID(),0,0,0,DEF_BUTTON_W,DEF_BUTTON_H) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButtonArrowDown::Конструктор параметрический. | //| Строит кнопку в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CButtonArrowDown::CButtonArrowDown(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CButton(object_name,text,chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButtonArrowDown::Инициализация | //+------------------------------------------------------------------+ void CButtonArrowDown::Init(const string text) { //--- Инициализируем цвета по умолчанию this.InitColors(); //--- Устанавливаем смещение и размеры области изображенеия this.SetImageBound(1,1,this.Height()-2,this.Height()-2); //--- Инициализируем счётчики автоповтора this.m_autorepeat_flag=true; //--- Инициализируем свойства объекта управления автоповтором событий this.m_autorepeat.SetChartID(this.m_chart_id); this.m_autorepeat.SetID(0); this.m_autorepeat.SetName("ButtDownAutorepeatControl"); this.m_autorepeat.SetDelay(DEF_AUTOREPEAT_DELAY); this.m_autorepeat.SetInterval(DEF_AUTOREPEAT_INTERVAL); this.m_autorepeat.SetEvent(CHARTEVENT_OBJECT_CLICK,0,0,this.NameFG()); } //+------------------------------------------------------------------+ //| CButtonArrowDown::Сравнение двух объектов | //+------------------------------------------------------------------+ int CButtonArrowDown::Compare(const CObject *node,const int mode=0) const { return CButton::Compare(node,mode); } //+------------------------------------------------------------------+ //| CButtonArrowDown::Рисует внешний вид | //+------------------------------------------------------------------+ void CButtonArrowDown::Draw(const bool chart_redraw) { //--- Заливаем кнопку цветом фона, рисуем рамку и обновляем канвас фона this.Fill(this.BackColor(),false); this.m_background.Rectangle(this.AdjX(0),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG())); this.m_background.Update(false); //--- Выводим текст кнопки CLabel::Draw(false); //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Задаём цвет стрелки для обычного и заблокированного состояний кнопки и рисуем стрелку вниз color clr=(!this.IsBlocked() ? this.GetForeColorControl().NewColor(this.ForeColor(),90,90,90) : this.ForeColor()); this.m_painter.ArrowDown(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),clr,this.AlphaFG(),true); //--- Если указано - обновляем график if(chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс кнопки со стрелкой влево | //+------------------------------------------------------------------+ class CButtonArrowLeft : public CButton { public: //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle) { return CButton::Save(file_handle); } virtual bool Load(const int file_handle) { return CButton::Load(file_handle); } virtual int Type(void) const { return(ELEMENT_TYPE_BUTTON_ARROW_DOWN); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(const string text); virtual void InitColors(void){} //--- Конструкторы/деструктор CButtonArrowLeft(void); CButtonArrowLeft(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CButtonArrowLeft (void) {} }; //+------------------------------------------------------------------+ //| CButtonArrowLeft::Конструктор по умолчанию. | //| Строит кнопку в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CButtonArrowLeft::CButtonArrowLeft(void) : CButton("Arrow Up Button","",::ChartID(),0,0,0,DEF_BUTTON_W,DEF_BUTTON_H) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButtonArrowLeft::Конструктор параметрический. | //| Строит кнопку в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CButtonArrowLeft::CButtonArrowLeft(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CButton(object_name,text,chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButtonArrowLeft::Инициализация | //+------------------------------------------------------------------+ void CButtonArrowLeft::Init(const string text) { //--- Инициализируем цвета по умолчанию this.InitColors(); //--- Устанавливаем смещение и размеры области изображенеия this.SetImageBound(1,1,this.Height()-2,this.Height()-2); //--- Инициализируем счётчики автоповтора this.m_autorepeat_flag=true; //--- Инициализируем свойства объекта управления автоповтором событий this.m_autorepeat.SetChartID(this.m_chart_id); this.m_autorepeat.SetID(0); this.m_autorepeat.SetName("ButtLeftAutorepeatControl"); this.m_autorepeat.SetDelay(DEF_AUTOREPEAT_DELAY); this.m_autorepeat.SetInterval(DEF_AUTOREPEAT_INTERVAL); this.m_autorepeat.SetEvent(CHARTEVENT_OBJECT_CLICK,0,0,this.NameFG()); } //+------------------------------------------------------------------+ //| CButtonArrowLeft::Сравнение двух объектов | //+------------------------------------------------------------------+ int CButtonArrowLeft::Compare(const CObject *node,const int mode=0) const { return CButton::Compare(node,mode); } //+------------------------------------------------------------------+ //| CButtonArrowLeft::Рисует внешний вид | //+------------------------------------------------------------------+ void CButtonArrowLeft::Draw(const bool chart_redraw) { //--- Заливаем кнопку цветом фона, рисуем рамку и обновляем канвас фона this.Fill(this.BackColor(),false); this.m_background.Rectangle(this.AdjX(0),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG())); this.m_background.Update(false); //--- Выводим текст кнопки CLabel::Draw(false); //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Задаём цвет стрелки для обычного и заблокированного состояний кнопки и рисуем стрелку влево color clr=(!this.IsBlocked() ? this.GetForeColorControl().NewColor(this.ForeColor(),90,90,90) : this.ForeColor()); this.m_painter.ArrowLeft(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),clr,this.AlphaFG(),true); //--- Если указано - обновляем график if(chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс кнопки со стрелкой вправо | //+------------------------------------------------------------------+ class CButtonArrowRight : public CButton { public: //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle) { return CButton::Save(file_handle); } virtual bool Load(const int file_handle) { return CButton::Load(file_handle); } virtual int Type(void) const { return(ELEMENT_TYPE_BUTTON_ARROW_DOWN); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(const string text); virtual void InitColors(void){} //--- Конструкторы/деструктор CButtonArrowRight(void); CButtonArrowRight(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CButtonArrowRight (void) {} }; //+------------------------------------------------------------------+ //| CButtonArrowRight::Конструктор по умолчанию. | //| Строит кнопку в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CButtonArrowRight::CButtonArrowRight(void) : CButton("Arrow Up Button","",::ChartID(),0,0,0,DEF_BUTTON_W,DEF_BUTTON_H) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButtonArrowRight::Конструктор параметрический. | //| Строит кнопку в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CButtonArrowRight::CButtonArrowRight(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CButton(object_name,text,chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CButtonArrowRight::Инициализация | //+------------------------------------------------------------------+ void CButtonArrowRight::Init(const string text) { //--- Инициализируем цвета по умолчанию this.InitColors(); //--- Устанавливаем смещение и размеры области изображенеия this.SetImageBound(1,1,this.Height()-2,this.Height()-2); //--- Инициализируем счётчики автоповтора this.m_autorepeat_flag=true; //--- Инициализируем свойства объекта управления автоповтором событий this.m_autorepeat.SetChartID(this.m_chart_id); this.m_autorepeat.SetID(0); this.m_autorepeat.SetName("ButtRightAutorepeatControl"); this.m_autorepeat.SetDelay(DEF_AUTOREPEAT_DELAY); this.m_autorepeat.SetInterval(DEF_AUTOREPEAT_INTERVAL); this.m_autorepeat.SetEvent(CHARTEVENT_OBJECT_CLICK,0,0,this.NameFG()); } //+------------------------------------------------------------------+ //| CButtonArrowRight::Сравнение двух объектов | //+------------------------------------------------------------------+ int CButtonArrowRight::Compare(const CObject *node,const int mode=0) const { return CButton::Compare(node,mode); } //+------------------------------------------------------------------+ //| CButtonArrowRight::Рисует внешний вид | //+------------------------------------------------------------------+ void CButtonArrowRight::Draw(const bool chart_redraw) { //--- Заливаем кнопку цветом фона, рисуем рамку и обновляем канвас фона this.Fill(this.BackColor(),false); this.m_background.Rectangle(this.AdjX(0),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG())); this.m_background.Update(false); //--- Выводим текст кнопки CLabel::Draw(false); //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Задаём цвет стрелки для обычного и заблокированного состояний кнопки и рисуем стрелку вправо color clr=(!this.IsBlocked() ? this.GetForeColorControl().NewColor(this.ForeColor(),90,90,90) : this.ForeColor()); this.m_painter.ArrowRight(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),clr,this.AlphaFG(),true); //--- Если указано - обновляем график if(chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс подсказки | //+------------------------------------------------------------------+ class CVisualHint : public CButton { protected: ENUM_HINT_TYPE m_hint_type; // Тип подсказки //--- Рисует (1) тултип, (2) горизонтальную, (3) вертикальную стрелку, //--- стрелки (4) сверху-лево --- низ-право, (5) снизу-лево --- верх-право, //--- стрелки смещения по (6) горизонтали, (7) вертикали void DrawTooltip(void); void DrawArrHorz(void); void DrawArrVert(void); void DrawArrNWSE(void); void DrawArrNESW(void); void DrawArrShiftHorz(void); void DrawArrShiftVert(void); //--- Инициализация цветов для типа подсказки (1) Tooltip, (2) стрелки void InitColorsTooltip(void); void InitColorsArrowed(void); public: //--- (1) Устанавливает, (2) возвращает тип подсказки void SetHintType(const ENUM_HINT_TYPE type); ENUM_HINT_TYPE HintType(void) const { return this.m_hint_type; } //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle) { return CButton::Save(file_handle); } virtual bool Load(const int file_handle) { return CButton::Load(file_handle); } virtual int Type(void) const { return(ELEMENT_TYPE_HINT); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(const string text); virtual void InitColors(void); //--- Конструкторы/деструктор CVisualHint(void); CVisualHint(const string object_name, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CVisualHint (void) {} }; //+------------------------------------------------------------------+ //| CVisualHint::Конструктор по умолчанию. | //| Строит элемент в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CVisualHint::CVisualHint(void) : CButton("HintObject","",::ChartID(),0,0,0,DEF_BUTTON_W,DEF_BUTTON_H) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CVisualHint::Конструктор параметрический. | //| Строит элемент в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CVisualHint::CVisualHint(const string object_name,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CButton(object_name,"",chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CVisualHint::Инициализация | //+------------------------------------------------------------------+ void CVisualHint::Init(const string text) { //--- Инициализируем цвета по умолчанию this.InitColors(); //--- Устанавливаем смещение и размеры области изображенеия this.SetImageBound(0,0,this.Width(),this.Height()); //--- Объект не обрезается по границам контейнера this.m_trim_flag=false; //--- Инициализируем счётчики автоповтора this.m_autorepeat_flag=true; //--- Инициализируем свойства объекта управления автоповтором событий this.m_autorepeat.SetChartID(this.m_chart_id); this.m_autorepeat.SetID(0); this.m_autorepeat.SetName("VisualHintAutorepeatControl"); this.m_autorepeat.SetDelay(DEF_AUTOREPEAT_DELAY); this.m_autorepeat.SetInterval(DEF_AUTOREPEAT_INTERVAL); this.m_autorepeat.SetEvent(CHARTEVENT_OBJECT_CLICK,0,0,this.NameFG()); } //+------------------------------------------------------------------+ //| CVisualHint::Инициализация цветов для типа подсказки Tooltip | //+------------------------------------------------------------------+ void CVisualHint::InitColorsTooltip(void) { //--- Фон и передний план непрозрачные this.SetAlpha(255); //--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона this.InitBackColors(clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke); this.InitBackColorsAct(clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke); this.BackColorToDefault(); //--- Инициализируем цвета переднего плана для обычного и активированного состояний и делаем его текущим цветом текста this.InitForeColors(clrBlack,clrBlack,clrBlack,clrSilver); this.InitForeColorsAct(clrBlack,clrBlack,clrBlack,clrSilver); this.ForeColorToDefault(); //--- Инициализируем цвета рамки для обычного и активированного состояний и делаем его текущим цветом рамки this.InitBorderColors(clrLightGray,clrLightGray,clrLightGray,clrLightGray); this.InitBorderColorsAct(clrLightGray,clrLightGray,clrLightGray,clrLightGray); this.BorderColorToDefault(); //--- Инициализируем цвет рамки и цвет переднего плана для заблокированного элемента this.InitBorderColorBlocked(clrNULL); this.InitForeColorBlocked(clrNULL); } //+------------------------------------------------------------------+ //| CVisualHint::Инициализация цветов для типа подсказки Arrowed | //+------------------------------------------------------------------+ void CVisualHint::InitColorsArrowed(void) { //--- Фон прозрачный, передний план - непрозрачный this.SetAlphaBG(0); this.SetAlphaFG(255); //--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона this.InitBackColors(clrNULL,clrNULL,clrNULL,clrNULL); this.InitBackColorsAct(clrNULL,clrNULL,clrNULL,clrNULL); this.BackColorToDefault(); //--- Инициализируем цвета переднего плана для обычного и активированного состояний и делаем его текущим цветом текста this.InitForeColors(clrBlack,clrBlack,clrBlack,clrSilver); this.InitForeColorsAct(clrBlack,clrBlack,clrBlack,clrSilver); this.ForeColorToDefault(); //--- Инициализируем цвета рамки для обычного и активированного состояний и делаем его текущим цветом рамки this.InitBorderColors(clrNULL,clrNULL,clrNULL,clrNULL); this.InitBorderColorsAct(clrNULL,clrNULL,clrNULL,clrNULL); this.BorderColorToDefault(); //--- Инициализируем цвет рамки и цвет переднего плана для заблокированного элемента this.InitBorderColorBlocked(clrNULL); this.InitForeColorBlocked(clrNULL); } //+------------------------------------------------------------------+ //| CVisualHint::Инициализация цветов объекта по умолчанию | //+------------------------------------------------------------------+ void CVisualHint::InitColors(void) { if(this.m_hint_type==HINT_TYPE_TOOLTIP) this.InitColorsTooltip(); else this.InitColorsArrowed(); } //+------------------------------------------------------------------+ //| CVisualHint::Сравнение двух объектов | //+------------------------------------------------------------------+ int CVisualHint::Compare(const CObject *node,const int mode=0) const { return CButton::Compare(node,mode); } //+------------------------------------------------------------------+ //| CVisualHint::Устанавливает тип подсказки | //+------------------------------------------------------------------+ void CVisualHint::SetHintType(const ENUM_HINT_TYPE type) { //--- Если переданный тип соответствует установленному - уходим if(this.m_hint_type==type) return; //--- Устанавливаем новый тип подсказки this.m_hint_type=type; //--- В зависимости от типа подсказки устанавливаем размеры объекта switch(this.m_hint_type) { case HINT_TYPE_ARROW_HORZ : this.Resize(17,7); break; case HINT_TYPE_ARROW_VERT : this.Resize(7,17); break; case HINT_TYPE_ARROW_NESW : case HINT_TYPE_ARROW_NWSE : this.Resize(13,13); break; case HINT_TYPE_ARROW_SHIFT_HORZ : case HINT_TYPE_ARROW_SHIFT_VERT : this.Resize(18,18); break; default : break; } //--- Устанавливаем смещение и размеры области изображенеия, //--- инициализируем цвета по типу подсказки this.SetImageBound(0,0,this.Width(),this.Height()); this.InitColors(); } //+------------------------------------------------------------------+ //| CVisualHint::Рисует внешний вид | //+------------------------------------------------------------------+ void CVisualHint::Draw(const bool chart_redraw) { //--- В зависимости от типа подсказки вызываем соответствующий метод рисования switch(this.m_hint_type) { case HINT_TYPE_ARROW_HORZ : this.DrawArrHorz(); break; case HINT_TYPE_ARROW_VERT : this.DrawArrVert(); break; case HINT_TYPE_ARROW_NESW : this.DrawArrNESW(); break; case HINT_TYPE_ARROW_NWSE : this.DrawArrNWSE(); break; case HINT_TYPE_ARROW_SHIFT_HORZ : this.DrawArrShiftHorz(); break; case HINT_TYPE_ARROW_SHIFT_VERT : this.DrawArrShiftVert(); break; default : this.DrawTooltip(); break; } //--- Если указано - обновляем график if(chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| CVisualHint::Рисует тултип | //+------------------------------------------------------------------+ void CVisualHint::DrawTooltip(void) { //--- Заливаем объект цветом фона, рисуем рамку и обновляем канвас фона this.Fill(this.BackColor(),false); this.m_background.Rectangle(this.AdjX(0),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG())); this.m_background.Update(false); } //+------------------------------------------------------------------+ //| CVisualHint::Рисует горизонтальную стрелку | //+------------------------------------------------------------------+ void CVisualHint::DrawArrHorz(void) { //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Рисуем двойную горизонтальную стрелку this.m_painter.ArrowHorz(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),this.ForeColor(),this.AlphaFG(),true); } //+------------------------------------------------------------------+ //| CVisualHint::Рисует вертикальную стрелку | //+------------------------------------------------------------------+ void CVisualHint::DrawArrVert(void) { //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Рисуем двойную вертикальную стрелку this.m_painter.ArrowVert(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),this.ForeColor(),this.AlphaFG(),true); } //+------------------------------------------------------------------+ //| CVisualHint::Рисует стрелки сверху-лево --- низ-право | //+------------------------------------------------------------------+ void CVisualHint::DrawArrNWSE(void) { //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Рисуем двойную диагональную стрелку сверху-лево --- вниз-право this.m_painter.ArrowNWSE(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),this.ForeColor(),this.AlphaFG(),true); } //+------------------------------------------------------------------+ //| CVisualHint::Рисует стрелки снизу-лево --- верх-право | //+------------------------------------------------------------------+ void CVisualHint::DrawArrNESW(void) { //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Рисуем двойную диагональную стрелку снизу-лево --- верх-право this.m_painter.ArrowNESW(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),this.ForeColor(),this.AlphaFG(),true); } //+------------------------------------------------------------------+ //| CVisualHint::Рисует стрелки смещения по горизонтали | //+------------------------------------------------------------------+ void CVisualHint::DrawArrShiftHorz(void) { //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Рисуем стрелки смещения по горизонтали this.m_painter.ArrowShiftHorz(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),this.ForeColor(),this.AlphaFG(),true); } //+------------------------------------------------------------------+ //| CVisualHint::Рисует стрелки смещения по вертикали | //+------------------------------------------------------------------+ void CVisualHint::DrawArrShiftVert(void) { //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Рисуем стрелки смещения по горизонтали this.m_painter.ArrowShiftVert(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),this.ForeColor(),this.AlphaFG(),true); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс элемента управления Checkbox | //+------------------------------------------------------------------+ class CCheckBox : public CButtonTriggered { public: //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle) { return CButton::Save(file_handle); } virtual bool Load(const int file_handle) { return CButton::Load(file_handle); } virtual int Type(void) const { return(ELEMENT_TYPE_CHECKBOX); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(const string text); virtual void InitColors(void); //--- Конструкторы/деструктор CCheckBox(void); CCheckBox(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CCheckBox (void) {} }; //+------------------------------------------------------------------+ //| CCheckBox::Конструктор по умолчанию. | //| Строит элемент в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CCheckBox::CCheckBox(void) : CButtonTriggered("CheckBox","CheckBox",::ChartID(),0,0,0,DEF_BUTTON_W,DEF_BUTTON_H) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CCheckBox::Конструктор параметрический. | //| Строит элемент в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CCheckBox::CCheckBox(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CButtonTriggered(object_name,text,chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CCheckBox::Инициализация | //+------------------------------------------------------------------+ void CCheckBox::Init(const string text) { //--- Устанавливаем цвета по умолчанию, прозрачность для фона и переднего плана, //--- и координаты и границы области рисунка значка кнопки this.InitColors(); this.SetAlphaBG(0); this.SetAlphaFG(255); this.SetImageBound(1,1,this.Height()-2,this.Height()-2); } //+------------------------------------------------------------------+ //| CCheckBox::Инициализация цветов объекта по умолчанию | //+------------------------------------------------------------------+ void CCheckBox::InitColors(void) { //--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона this.InitBackColors(clrNULL); this.InitBackColorsAct(clrNULL); this.BackColorToDefault(); //--- Инициализируем цвета переднего плана для обычного и активированного состояний и делаем его текущим цветом текста this.InitForeColors(clrBlack); this.InitForeColorsAct(clrBlack); this.InitForeColorFocused(clrNavy); this.InitForeColorActFocused(clrNavy); this.ForeColorToDefault(); //--- Инициализируем цвета рамки для обычного и активированного состояний и делаем его текущим цветом рамки this.InitBorderColors(clrNULL); this.InitBorderColorsAct(clrNULL); this.BorderColorToDefault(); //--- Инициализируем цвет рамки и цвет переднего плана для заблокированного элемента this.InitBorderColorBlocked(clrNULL); this.InitForeColorBlocked(clrSilver); } //+------------------------------------------------------------------+ //| CCheckBox::Сравнение двух объектов | //+------------------------------------------------------------------+ int CCheckBox::Compare(const CObject *node,const int mode=0) const { return CButtonTriggered::Compare(node,mode); } //+------------------------------------------------------------------+ //| CCheckBox::Рисует внешний вид | //+------------------------------------------------------------------+ void CCheckBox::Draw(const bool chart_redraw) { //--- Заливаем кнопку цветом фона, рисуем рамку и обновляем канвас фона this.Fill(this.BackColor(),false); this.m_background.Rectangle(this.AdjX(0),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG())); this.m_background.Update(false); //--- Выводим текст кнопки CLabel::Draw(false); //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Рисуем отмеченный значок для активного состояния кнопки, if(this.m_state) this.m_painter.CheckedBox(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),this.ForeColor(),this.AlphaFG(),true); //--- и неотмеченный - для неактивного else this.m_painter.UncheckedBox(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),this.ForeColor(),this.AlphaFG(),true); //--- Если указано - обновляем график if(chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс элемента управления Radio Button | //+------------------------------------------------------------------+ class CRadioButton : public CCheckBox { public: //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle) { return CButton::Save(file_handle); } virtual bool Load(const int file_handle) { return CButton::Load(file_handle); } virtual int Type(void) const { return(ELEMENT_TYPE_RADIOBUTTON); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(const string text); virtual void InitColors(void){} //--- Обработчик событий нажатий кнопок мышки (Press) virtual void OnPressEvent(const int id, const long lparam, const double dparam, const string sparam); //--- Конструкторы/деструктор CRadioButton(void); CRadioButton(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CRadioButton (void) {} }; //+------------------------------------------------------------------+ //| CRadioButton::Конструктор по умолчанию. | //| Строит элемент в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CRadioButton::CRadioButton(void) : CCheckBox("RadioButton","",::ChartID(),0,0,0,DEF_BUTTON_H,DEF_BUTTON_H) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CRadioButton::Конструктор параметрический. | //| Строит элемент в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CRadioButton::CRadioButton(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CCheckBox(object_name,text,chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CRadioButton::Инициализация | //+------------------------------------------------------------------+ void CRadioButton::Init(const string text) { return; } //+------------------------------------------------------------------+ //| CRadioButton::Сравнение двух объектов | //+------------------------------------------------------------------+ int CRadioButton::Compare(const CObject *node,const int mode=0) const { return CCheckBox::Compare(node,mode); } //+------------------------------------------------------------------+ //| CRadioButton::Рисует внешний вид | //+------------------------------------------------------------------+ void CRadioButton::Draw(const bool chart_redraw) { //--- Заливаем кнопку цветом фона, рисуем рамку и обновляем канвас фона this.Fill(this.BackColor(),false); this.m_background.Rectangle(this.AdjX(0),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG())); this.m_background.Update(false); //--- Выводим текст кнопки CLabel::Draw(false); //--- Очищаем область рисунка this.m_painter.Clear(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),false); //--- Рисуем отмеченный значок для активного состояния кнопки, if(this.m_state) this.m_painter.CheckedRadioButton(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),this.ForeColor(),this.AlphaFG(),true); //--- и неотмеченный - для неактивного else this.m_painter.UncheckedRadioButton(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),this.m_painter.Width(),this.m_painter.Height(),this.ForeColor(),this.AlphaFG(),true); //--- Если указано - обновляем график if(chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| CRadioButton::Обработчик событий нажатий кнопок мышки (Press) | //+------------------------------------------------------------------+ void CRadioButton::OnPressEvent(const int id,const long lparam,const double dparam,const string sparam) { //--- Если кнопка уже отмечена - уходим if(this.m_state) return; //--- Устанавливаем состояние кнопки, обратное уже установленному ENUM_ELEMENT_STATE state=(this.State()==ELEMENT_STATE_DEF ? ELEMENT_STATE_ACT : ELEMENT_STATE_DEF); this.SetState(state); //--- Вызываем обработчик родительского объекта с указанием идентификатора в lparam и состояния в dparam CCanvasBase::OnPressEvent(id,this.m_id,this.m_state,sparam); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс панели | //+------------------------------------------------------------------+ class CPanel : public CLabel { private: CElementBase m_temp_elm; // Временный объект для поиска элементов CBound m_temp_bound; // Временный объект для поиска областей protected: CListElm m_list_elm; // Список прикреплённых элементов CListElm m_list_bounds; // Список областей //--- Добавляет новый элемент в список bool AddNewElement(CElementBase *element); public: //--- Возвращает указатель на список (1) прикреплённых элементов, (2) областей CListElm *GetListAttachedElements(void) { return &this.m_list_elm; } CListElm *GetListBounds(void) { return &this.m_list_bounds; } //--- Возвращает прикреплённый элемент по (1) индексу в списке, (2) идентификатору, (3) назначенному имени объекта CElementBase *GetAttachedElementAt(const uint index) { return this.m_list_elm.GetNodeAtIndex(index); } CElementBase *GetAttachedElementByID(const int id); CElementBase *GetAttachedElementByName(const string name); //--- Возвращает количество присоединённых элементов int AttachedElementsTotal(void) const { return this.m_list_elm.Total(); } //--- Возвращает область по (1) индексу в списке, (2) идентификатору, (3) назначенному имени области CBound *GetBoundAt(const uint index) { return this.m_list_bounds.GetNodeAtIndex(index); } CBound *GetBoundByID(const int id); CBound *GetBoundByName(const string name); //--- Создаёт и добавляет (1) новый, (2) ранее созданный элемент в список virtual CElementBase *InsertNewElement(const ENUM_ELEMENT_TYPE type,const string text,const string user_name,const int dx,const int dy,const int w,const int h); virtual CElementBase *InsertElement(CElementBase *element,const int dx,const int dy); //--- Удаляет указанный элемент bool DeleteElement(const int index) { return this.m_list_elm.Delete(index); } //--- (1) Создаёт и добавляет в список новую область, (2) удаляет указанную область CBound *InsertNewBound(const string name,const int dx,const int dy,const int w,const int h); bool DeleteBound(const int index) { return this.m_list_bounds.Delete(index); } //--- (1) Назначает объект на указанную область, (2) отменяет назначение объекта с указанной области bool AssignObjectToBound(const int bound, CBaseObj *object); bool UnassignObjectFromBound(const int bound); //--- Изменяет размеры объекта virtual bool ResizeW(const int w); virtual bool ResizeH(const int h); virtual bool Resize(const int w,const int h); //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0) const; virtual bool Save(const int file_handle); virtual bool Load(const int file_handle); virtual int Type(void) const { return(ELEMENT_TYPE_PANEL); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(void); virtual void InitColors(void); //--- Устанавливает объекту новые координаты XY virtual bool Move(const int x,const int y); //--- Смещает объект по осям XY на указанное смещение virtual bool Shift(const int dx,const int dy); //--- Устанавливает одновременно координаты и размеры элемента virtual bool MoveXYWidthResize(const int x,const int y,const int w,const int h); //--- (1) Скрывает (2) отображает объект на всех периодах графика, //--- (3) помещает объект на передний план, (4) блокирует, (5) разблокирует элемент, virtual void Hide(const bool chart_redraw); virtual void Show(const bool chart_redraw); virtual void BringToTop(const bool chart_redraw); virtual void Block(const bool chart_redraw); virtual void Unblock(const bool chart_redraw); //--- Выводит в журнал описание объекта virtual void Print(void); //--- Распечатывает список (1) присоединённых объектов, (2) областей void PrintAttached(const uint tab=3); void PrintBounds(void); //--- Обработчик событий virtual void OnChartEvent(const int id,const long& lparam,const double& dparam,const string& sparam); //--- Обработчик события таймера virtual void TimerEventHandler(void); //--- Конструкторы/деструктор CPanel(void); CPanel(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CPanel (void) { this.m_list_elm.Clear(); this.m_list_bounds.Clear(); } }; //+------------------------------------------------------------------+ //| CPanel::Конструктор по умолчанию. | //| Строит элемент в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CPanel::CPanel(void) : CLabel("Panel","",::ChartID(),0,0,0,DEF_PANEL_W,DEF_PANEL_H) { //--- Инициализация this.Init(); } //+------------------------------------------------------------------+ //| CPanel::Конструктор параметрический. | //| Строит элемент в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CPanel::CPanel(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CLabel(object_name,text,chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(); } //+------------------------------------------------------------------+ //| CPanel::Инициализация | //+------------------------------------------------------------------+ void CPanel::Init(void) { //--- Инициализация цветов по умолчанию this.InitColors(); //--- Фон - прозрачный, передний план - нет this.SetAlphaBG(0); this.SetAlphaFG(255); //--- Устанавливаем смещение и размеры области изображенеия this.SetImageBound(0,0,this.Width(),this.Height()); //--- Ширина рамки this.SetBorderWidth(2); } //+------------------------------------------------------------------+ //| CPanel::Инициализация цветов объекта по умолчанию | //+------------------------------------------------------------------+ void CPanel::InitColors(void) { //--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона this.InitBackColors(clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke); this.InitBackColorsAct(clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke); this.BackColorToDefault(); //--- Инициализируем цвета переднего плана для обычного и активированного состояний и делаем его текущим цветом текста this.InitForeColors(clrBlack,clrBlack,clrBlack,clrSilver); this.InitForeColorsAct(clrBlack,clrBlack,clrBlack,clrSilver); this.ForeColorToDefault(); //--- Инициализируем цвета рамки для обычного и активированного состояний и делаем его текущим цветом рамки this.InitBorderColors(clrNULL,clrNULL,clrNULL,clrNULL); this.InitBorderColorsAct(clrNULL,clrNULL,clrNULL,clrNULL); this.BorderColorToDefault(); //--- Инициализируем цвет рамки и цвет переднего плана для заблокированного элемента this.InitBorderColorBlocked(clrNULL); this.InitForeColorBlocked(clrSilver); } //+------------------------------------------------------------------+ //| CPanel::Сравнение двух объектов | //+------------------------------------------------------------------+ int CPanel::Compare(const CObject *node,const int mode=0) const { return CLabel::Compare(node,mode); } //+------------------------------------------------------------------+ //| CPanel::Изменяет ширину объекта | //+------------------------------------------------------------------+ bool CPanel::ResizeW(const int w) { if(!this.ObjectResizeW(w)) return false; this.BoundResizeW(w); this.SetImageSize(w,this.Height()); if(!this.ObjectTrim()) { this.Update(false); this.Draw(false); } //--- Получаем указатель на базовый элемент и, если он есть, и его тип - контейнер, //--- проверяем отношение размеров текущего элемента относительно размеров контейнера //--- для отображения полос прокрутки в контейнере при необходимости CContainer *container=NULL; CCanvasBase *base=this.GetContainer(); if(base!=NULL && base.Type()==ELEMENT_TYPE_CONTAINER) { container=base; container.CheckElementSizes(&this); } //--- В цикле по присоединённым элементам обрезаем каждый элемент по границам контейнера int total=this.m_list_elm.Total(); for(int i=0;i-1); } //--- Возвращаем списку изначальную сортировку this.m_list_elm.Sort(sort_mode); //--- Элемент с таким идентификатором уже есть в списке - возвращаем false return false; } //+------------------------------------------------------------------+ //| CPanel::Создаёт и добавляет новый элемент в список | //+------------------------------------------------------------------+ CElementBase *CPanel::InsertNewElement(const ENUM_ELEMENT_TYPE type,const string text,const string user_name,const int dx,const int dy,const int w,const int h) { //--- Создаём имя графического объекта int elm_total=this.m_list_elm.Total(); string obj_name=this.NameFG()+"_"+ElementShortName(type)+(string)elm_total; //--- Рассчитываем координаты int x=this.X()+dx; int y=this.Y()+dy; //--- В зависимости от типа объекта, создаём новый объект CElementBase *element=NULL; switch(type) { case ELEMENT_TYPE_LABEL : element = new CLabel(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Текстовая метка case ELEMENT_TYPE_BUTTON : element = new CButton(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Простая кнопка case ELEMENT_TYPE_BUTTON_TRIGGERED : element = new CButtonTriggered(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Двухпозиционная кнопка case ELEMENT_TYPE_BUTTON_ARROW_UP : element = new CButtonArrowUp(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Кнопка со стрелкой вверх case ELEMENT_TYPE_BUTTON_ARROW_DOWN : element = new CButtonArrowDown(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Кнопка со стрелкой вниз case ELEMENT_TYPE_BUTTON_ARROW_LEFT : element = new CButtonArrowLeft(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Кнопка со стрелкой влево case ELEMENT_TYPE_BUTTON_ARROW_RIGHT : element = new CButtonArrowRight(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Кнопка со стрелкой вправо case ELEMENT_TYPE_CHECKBOX : element = new CCheckBox(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Элемент управления CheckBox case ELEMENT_TYPE_RADIOBUTTON : element = new CRadioButton(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Элемент управления RadioButton case ELEMENT_TYPE_SCROLLBAR_THUMB_H : element = new CScrollBarThumbH(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Полоса прокрутки горизонтального ScrollBar case ELEMENT_TYPE_SCROLLBAR_THUMB_V : element = new CScrollBarThumbV(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Полоса прокрутки вертикального ScrollBar case ELEMENT_TYPE_SCROLLBAR_H : element = new CScrollBarH(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Элемент управления горизонтальный ScrollBar case ELEMENT_TYPE_SCROLLBAR_V : element = new CScrollBarV(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Элемент управления вертикальный ScrollBar case ELEMENT_TYPE_TABLE_ROW_VIEW : element = new CTableRowView(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Объект визуального представления строки таблицы case ELEMENT_TYPE_TABLE_COLUMN_CAPTION_VIEW : element = new CColumnCaptionView(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Объект визуального представления заголовка столбца таблицы case ELEMENT_TYPE_TABLE_HEADER_VIEW : element = new CTableHeaderView(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Объект визуального представления заголовка таблицы case ELEMENT_TYPE_TABLE_VIEW : element = new CTableView(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Объект визуального представления таблицы case ELEMENT_TYPE_PANEL : element = new CPanel(obj_name,"",this.m_chart_id,this.m_wnd,x,y,w,h); break; // Элемент управления Panel case ELEMENT_TYPE_GROUPBOX : element = new CGroupBox(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Элемент управления GroupBox case ELEMENT_TYPE_CONTAINER : element = new CContainer(obj_name,text,this.m_chart_id,this.m_wnd,x,y,w,h); break; // Элемент управления Container default : element = NULL; } //--- Если новый элемент не создан - сообщаем об этом и возвращаем NULL if(element==NULL) { ::PrintFormat("%s: Error. Failed to create graphic element %s",__FUNCTION__,ElementDescription(type)); return NULL; } //--- Устанавливаем идентификатор, имя, контейнер и z-order элемента element.SetID(elm_total); element.SetName(user_name); element.SetContainerObj(&this); element.ObjectSetZOrder(this.ObjectZOrder()+1); //--- Если созданный элемент не добавлен в список - сообщаем об этом, удаляем созданный элемент и возвращаем NULL if(!this.AddNewElement(element)) { ::PrintFormat("%s: Error. Failed to add %s element with ID %d to list",__FUNCTION__,ElementDescription(type),element.ID()); delete element; return NULL; } //--- Получаем родительский элемент, к которому привязаны дочерние CElementBase *elm=this.GetContainer(); //--- Если родительский элемент имеет тип "Контейнер", значит, у него есть полосы прокрутки if(elm!=NULL && elm.Type()==ELEMENT_TYPE_CONTAINER) { //--- Преобразуем CElementBase в CContainer CContainer *container_obj=elm; //--- Если горизонтальная полоса прокрутки видима, if(container_obj.ScrollBarHorzIsVisible()) { //--- получаем указатель на горизонтальный скроллбар и переносим его на передний план CScrollBarH *sbh=container_obj.GetScrollBarH(); if(sbh!=NULL) sbh.BringToTop(false); } //--- Если вертикальная полоса прокрутки видима, if(container_obj.ScrollBarVertIsVisible()) { //--- получаем указатель на вертикальный скроллбар и переносим его на передний план CScrollBarV *sbv=container_obj.GetScrollBarV(); if(sbv!=NULL) sbv.BringToTop(false); } } //--- Возвращаем указатель на созданный и присоединённый элемент return element; } //+------------------------------------------------------------------+ //| CPanel::Добавляет указанный элемент в список | //+------------------------------------------------------------------+ CElementBase *CPanel::InsertElement(CElementBase *element,const int dx,const int dy) { //--- Если передан пустой или невалидный указатель на элемент - возвращаем NULL if(::CheckPointer(element)==POINTER_INVALID) { ::PrintFormat("%s: Error. Empty element passed",__FUNCTION__); return NULL; } //--- Если передан базовый элемент - возвращаем NULL if(element.Type()==ELEMENT_TYPE_BASE) { ::PrintFormat("%s: Error. The base element cannot be used",__FUNCTION__); return NULL; } //--- Запоминаем идентификатор элемента и устанавливаем новый int id=element.ID(); element.SetID(this.m_list_elm.Total()); //--- Добавляем элемент в список; при неудаче - сообщаем об этом, устанавливаем начальный идентификатор и возвращаем NULL if(!this.AddNewElement(element)) { ::PrintFormat("%s: Error. Failed to add element %s to list",__FUNCTION__,ElementDescription((ENUM_ELEMENT_TYPE)element.Type())); element.SetID(id); return NULL; } //--- Устанавливаем новые координаты, контейнер и z-order элемента int x=this.X()+dx; int y=this.Y()+dy; element.Move(x,y); element.SetContainerObj(&this); element.ObjectSetZOrder(this.ObjectZOrder()+1); //--- Возвращаем указатель на присоединённый элемент return element; } //+------------------------------------------------------------------+ //| CPanel::Возвращает элемент по идентификатору | //+------------------------------------------------------------------+ CElementBase *CPanel::GetAttachedElementByID(const int id) { for(int i=0;ibase_right) x=base_right-this.Width(); //--- Сдвигаем ползунок на рассчитанную координату X if(!this.MoveX(x)) return; //--- Рассчитываем позицию ползунка int thumb_pos=this.X()-base_left; //--- Отправляем пользовательское событие на график с позицией ползунка в lparam и именем объекта в sparam ::EventChartCustom(this.m_chart_id, (ushort)CHARTEVENT_MOUSE_MOVE, thumb_pos, dparam, this.NameFG()); //--- Перерисовываем график if(this.m_chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| CScrollBarThumbH::Обработчик прокрутки колёсика | //+------------------------------------------------------------------+ void CScrollBarThumbH::OnWheelEvent(const int id,const long lparam,const double dparam,const string sparam) { //--- Получаем указатель на базовый объект (элемент управления "горизонтальная полоса прогрутки") CCanvasBase *base_obj=this.GetContainer(); //--- Получаем имя главного объекта в иерархии по значению в sparam string array_names[]; string name_main=(GetElementNames(sparam,"_",array_names)>0 ? array_names[0] : ""); //--- Если главный объект в иерархии не наш - уходим if(::StringFind(this.NameFG(),name_main)!=0) return; //--- Если для ползунка не установлен флаг перемещаемости, либо указатель на базовый объект не получен - уходим if(!this.IsMovable() || base_obj==NULL) return; //--- Получаем ширину базового объекта и рассчитываем границы пространства для ползунка int base_w=base_obj.Width(); int base_left=base_obj.X()+base_obj.Height(); int base_right=base_obj.Right()-base_obj.Height()+1; //--- Задаём направление смещения в зависимости от направления вращения колёсика мышки int dx=(dparam<0 ? 2 : dparam>0 ? -2 : 0); if(dx==0) dx=(int)lparam; //--- Если при смещении ползунок выйдет за левый край своей области - устанавливаем его на левый край if(dx<0 && this.X()+dx<=base_left) this.MoveX(base_left); //--- иначе, если при смещении ползунок выйдет за правый край своей области - позиционируем его по правому краю else if(dx>0 && this.Right()+dx>=base_right) this.MoveX(base_right-this.Width()); //--- Иначе, если ползунок в пределах своей области - смещаем его на величину смещения else { this.ShiftX(dx); } //--- Рассчитываем позицию ползунка int thumb_pos=this.X()-base_left; //--- Получаем координаты курсора int x=CCommonManager::GetInstance().CursorX(); int y=CCommonManager::GetInstance().CursorY(); //--- Если курсор попадает на ползунок - меняем цвет на "В фокусе", if(this.Contains(x,y)) this.OnFocusEvent(id,lparam,dparam,sparam); //--- иначе - возвращаем цвет на "По умолчанию" else this.OnReleaseEvent(id,lparam,dparam,sparam); //--- Отправляем пользовательское событие на график с позицией ползунка в lparam и именем объекта в sparam ::EventChartCustom(this.m_chart_id, (ushort)CHARTEVENT_MOUSE_WHEEL, thumb_pos, dparam, this.NameFG()); //--- Перерисовываем график if(this.m_chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| CScrollBarThumbH::Сохранение в файл | //+------------------------------------------------------------------+ bool CScrollBarThumbH::Save(const int file_handle) { //--- Сохраняем данные родительского объекта if(!CButton::Save(file_handle)) return false; //--- Сохраняем флаг обновления графика if(::FileWriteInteger(file_handle,this.m_chart_redraw,INT_VALUE)!=INT_VALUE) return false; //--- Всё успешно return true; } //+------------------------------------------------------------------+ //| CScrollBarThumbH::Загрузка из файла | //+------------------------------------------------------------------+ bool CScrollBarThumbH::Load(const int file_handle) { //--- Загружаем данные родительского объекта if(!CButton::Load(file_handle)) return false; //--- Загружаем флаг обновления графика this.m_chart_redraw=::FileReadInteger(file_handle,INT_VALUE); //--- Всё успешно return true; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс ползунка вертикальной полосы прокрутки | //+------------------------------------------------------------------+ class CScrollBarThumbV : public CButton { protected: bool m_chart_redraw; // Флаг обновления графика public: //--- (1) Устанавливает, (2) возвращает флаг обновления графика void SetChartRedrawFlag(const bool flag) { this.m_chart_redraw=flag; } bool ChartRedrawFlag(void) const { return this.m_chart_redraw; } //--- Виртуальные методы (1) сохранения в файл, (2) загрузки из файла, (3) тип объекта virtual bool Save(const int file_handle); virtual bool Load(const int file_handle); virtual int Type(void) const { return(ELEMENT_TYPE_SCROLLBAR_THUMB_V); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(const string text); //--- Обработчики событий (1) перемещения курсора, (2) прокрутки колёсика virtual void OnMoveEvent(const int id, const long lparam, const double dparam, const string sparam); virtual void OnWheelEvent(const int id, const long lparam, const double dparam, const string sparam); //--- Конструкторы/деструктор CScrollBarThumbV(void); CScrollBarThumbV(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CScrollBarThumbV (void) {} }; //+------------------------------------------------------------------+ //| CScrollBarThumbV::Конструктор по умолчанию. | //| Строит элемент в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CScrollBarThumbV::CScrollBarThumbV(void) : CButton("SBThumb","",::ChartID(),0,0,0,DEF_SCROLLBAR_TH,DEF_PANEL_W) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CScrollBarThumbV::Конструктор параметрический. | //| Строит элемент в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CScrollBarThumbV::CScrollBarThumbV(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CButton(object_name,text,chart_id,wnd,x,y,w,h) { //--- Инициализация this.Init(""); } //+------------------------------------------------------------------+ //| CScrollBarThumbV::Инициализация | //+------------------------------------------------------------------+ void CScrollBarThumbV::Init(const string text) { //--- Инициализация родительского класса CButton::Init(""); //--- Устанавливаем флаги перемещаемости и обновления графика this.SetMovable(true); this.SetChartRedrawFlag(false); //--- Элемент не обрезается по границам контейнера this.m_trim_flag=false; } //+------------------------------------------------------------------+ //| CScrollBarThumbV::Обработчик перемещения курсора | //+------------------------------------------------------------------+ void CScrollBarThumbV::OnMoveEvent(const int id,const long lparam,const double dparam,const string sparam) { //--- Обработчик перемещения курсора базового объекта CCanvasBase::OnMoveEvent(id,lparam,dparam,sparam); //--- Получаем указатель на базовый объект (элемент управления "вертикальная полоса прогрутки") CCanvasBase *base_obj=this.GetContainer(); //--- Если для ползунка не установлен флаг перемещаемости, либо указатель на базовый объект не получен - уходим if(!this.IsMovable() || base_obj==NULL) return; //--- Получаем высоту базового объекта и рассчитываем границы пространства для ползунка int base_h=base_obj.Height(); int base_top=base_obj.Y()+base_obj.Width(); int base_bottom=base_obj.Bottom()-base_obj.Width()+1; //--- Из координат курсора и размеров ползунка рассчитываем ограничения для перемещения int y=(int)dparam-this.m_cursor_delta_y; if(ybase_bottom) y=base_bottom-this.Height(); //--- Сдвигаем ползунок на рассчитанную координату Y if(!this.MoveY(y)) return; //--- Рассчитываем позицию ползунка int thumb_pos=this.Y()-base_top; //--- Отправляем пользовательское событие на график с позицией ползунка в lparam и именем объекта в sparam ::EventChartCustom(this.m_chart_id, (ushort)CHARTEVENT_MOUSE_MOVE, thumb_pos, dparam, this.NameFG()); //--- Перерисовываем график if(this.m_chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| CScrollBarThumbV::Обработчик прокрутки колёсика | //+------------------------------------------------------------------+ void CScrollBarThumbV::OnWheelEvent(const int id,const long lparam,const double dparam,const string sparam) { //--- Получаем указатель на базовый объект (элемент управления "вертикальная полоса прогрутки") CCanvasBase *base_obj=this.GetContainer(); //--- Получаем имя главного объекта в иерархии по значению в sparam string array_names[]; string name_main=(GetElementNames(sparam,"_",array_names)>0 ? array_names[0] : ""); //--- Если главный объект в иерархии не наш - уходим if(::StringFind(this.NameFG(),name_main)!=0) return; //--- Если для ползунка не установлен флаг перемещаемости, либо указатель на базовый объект не получен - уходим if(!this.IsMovable() || base_obj==NULL) return; //--- Получаем высоту базового объекта и рассчитываем границы пространства для ползунка int base_h=base_obj.Height(); int base_top=base_obj.Y()+base_obj.Width(); int base_bottom=base_obj.Bottom()-base_obj.Width()+1; //--- Задаём направление смещения в зависимости от направления вращения колёсика мышки int dy=(dparam<0 ? 2 : dparam>0 ? -2 : 0); if(dy==0) dy=(int)lparam; //--- Если при смещении ползунок выйдет за верхний край своей области - устанавливаем его на верхний край if(dy<0 && this.Y()+dy<=base_top) this.MoveY(base_top); //--- иначе, если при смещении ползунок выйдет за нижний край своей области - позиционируем его по нижнему краю else if(dy>0 && this.Bottom()+dy>=base_bottom) this.MoveY(base_bottom-this.Height()); //--- Иначе, если ползунок в пределах своей области - смещаем его на величину смещения else { this.ShiftY(dy); } //--- Рассчитываем позицию ползунка int thumb_pos=this.Y()-base_top; //--- Получаем координаты курсора int x=CCommonManager::GetInstance().CursorX(); int y=CCommonManager::GetInstance().CursorY(); //--- Если курсор попадает на ползунок - меняем цвет на "В фокусе", if(this.Contains(x,y)) this.OnFocusEvent(id,lparam,dparam,sparam); //--- иначе - возвращаем цвет на "По умолчанию" else this.OnReleaseEvent(id,lparam,dparam,sparam); //--- Отправляем пользовательское событие на график с позицией ползунка в lparam и именем объекта в sparam ::EventChartCustom(this.m_chart_id, (ushort)CHARTEVENT_MOUSE_WHEEL, thumb_pos, dparam, this.NameFG()); //--- Перерисовываем график if(this.m_chart_redraw) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| CScrollBarThumbV::Сохранение в файл | //+------------------------------------------------------------------+ bool CScrollBarThumbV::Save(const int file_handle) { //--- Сохраняем данные родительского объекта if(!CButton::Save(file_handle)) return false; //--- Сохраняем флаг обновления графика if(::FileWriteInteger(file_handle,this.m_chart_redraw,INT_VALUE)!=INT_VALUE) return false; //--- Всё успешно return true; } //+------------------------------------------------------------------+ //| CScrollBarThumbV::Загрузка из файла | //+------------------------------------------------------------------+ bool CScrollBarThumbV::Load(const int file_handle) { //--- Загружаем данные родительского объекта if(!CButton::Load(file_handle)) return false; //--- Загружаем флаг обновления графика this.m_chart_redraw=::FileReadInteger(file_handle,INT_VALUE); //--- Всё успешно return true; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс горизонтальной полосы прокрутки | //+------------------------------------------------------------------+ class CScrollBarH : public CPanel { protected: CButtonArrowLeft *m_butt_left; // Кнопка со стрелкой влево CButtonArrowRight*m_butt_right; // Кнопка со стрелкой вправо CScrollBarThumbH *m_thumb; // Ползунок скроллбара public: //--- Возвращает указатель на (1) левую, (2) правую кнопку, (3) ползунок CButtonArrowLeft *GetButtonLeft(void) { return this.m_butt_left; } CButtonArrowRight*GetButtonRight(void) { return this.m_butt_right; } CScrollBarThumbH *GetThumb(void) { return this.m_thumb; } //--- (1) Устанавливает, (2) возвращает флаг обновления графика void SetChartRedrawFlag(const bool flag) { if(this.m_thumb!=NULL) this.m_thumb.SetChartRedrawFlag(flag); } bool ChartRedrawFlag(void) const { return(this.m_thumb!=NULL ? this.m_thumb.ChartRedrawFlag() : false); } //--- Возвращает (1) длину (2) начало трека, (3) позицию ползунка int TrackLength(void) const; int TrackBegin(void) const; int ThumbPosition(void) const; //--- Устанавливает позицию ползунка bool SetThumbPosition(const int pos) const { return(this.m_thumb!=NULL ? this.m_thumb.MoveX(pos) : false); } //--- Изменяет размер ползунка bool SetThumbSize(const uint size) const { return(this.m_thumb!=NULL ? this.m_thumb.ResizeW(size) : false); } //--- Изменяет ширину объекта virtual bool ResizeW(const int size); //--- Устанавливает флаг видимости в контейнере virtual void SetVisibleInContainer(const bool flag); //--- Устанавливает флаг обрезки по границам контейнера virtual void SetTrimmered(const bool flag); //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Тип объекта virtual int Type(void) const { return(ELEMENT_TYPE_SCROLLBAR_H); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(void); virtual void InitColors(void); //--- Обработчик прокрутки колёсика (Wheel) virtual void OnWheelEvent(const int id, const long lparam, const double dparam, const string sparam); //--- Конструкторы/деструктор CScrollBarH(void); CScrollBarH(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CScrollBarH(void) {} }; //+------------------------------------------------------------------+ //| CScrollBarH::Конструктор по умолчанию. | //| Строит элемент в главном окне текущего графика | //| в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CScrollBarH::CScrollBarH(void) : CPanel("ScrollBarH","",::ChartID(),0,0,0,DEF_PANEL_W,DEF_PANEL_H),m_butt_left(NULL),m_butt_right(NULL),m_thumb(NULL) { //--- Инициализация this.Init(); } //+------------------------------------------------------------------+ //| CScrollBarH::Конструктор параметрический. | //| Строит элемент в указанном окне указанного графика | //| с указанными текстом, координатами и размерами | //+------------------------------------------------------------------+ CScrollBarH::CScrollBarH(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CPanel(object_name,text,chart_id,wnd,x,y,w,h),m_butt_left(NULL),m_butt_right(NULL),m_thumb(NULL) { //--- Инициализация this.Init(); } //+------------------------------------------------------------------+ //| CScrollBarH::Инициализация | //+------------------------------------------------------------------+ void CScrollBarH::Init(void) { //--- Инициализация родительского класса CPanel::Init(); //--- Фон - непрозрачный this.SetAlphaBG(255); //--- Ширина рамки и текст this.SetBorderWidth(0); this.SetText(""); //--- Создаём кнопки прокрутки int w=this.Height(); int h=this.Height(); this.m_butt_left = this.InsertNewElement(ELEMENT_TYPE_BUTTON_ARROW_LEFT, "","ButtL",0,0,w,h); this.m_butt_right= this.InsertNewElement(ELEMENT_TYPE_BUTTON_ARROW_RIGHT,"","ButtR",this.Width()-w,0,w,h); if(this.m_butt_left==NULL || this.m_butt_right==NULL) { ::PrintFormat("%s: Init failed",__FUNCTION__); return; } //--- Настраиваем цвета и вид кнопки со стрелкой влево this.m_butt_left.SetImageBound(1,1,w-2,h-4); this.m_butt_left.InitBackColors(this.m_butt_left.BackColorFocused()); this.m_butt_left.ColorsToDefault(); this.m_butt_left.InitBorderColors(this.BorderColor(),this.m_butt_left.BackColorFocused(),this.m_butt_left.BackColorPressed(),this.m_butt_left.BackColorBlocked()); this.m_butt_left.ColorsToDefault(); //--- Настраиваем цвета и вид кнопки со стрелкой вправо this.m_butt_right.SetImageBound(1,1,w-2,h-4); this.m_butt_right.InitBackColors(this.m_butt_right.BackColorFocused()); this.m_butt_right.ColorsToDefault(); this.m_butt_right.InitBorderColors(this.BorderColor(),this.m_butt_right.BackColorFocused(),this.m_butt_right.BackColorPressed(),this.m_butt_right.BackColorBlocked()); this.m_butt_right.ColorsToDefault(); //--- Создаём ползунок int tsz=this.Width()-w*2; this.m_thumb=this.InsertNewElement(ELEMENT_TYPE_SCROLLBAR_THUMB_H,"","ThumbH",w,1,tsz-w*4,h-2); if(this.m_thumb==NULL) { ::PrintFormat("%s: Init failed",__FUNCTION__); return; } //--- Настраиваем цвета ползунка и устанавливаем ему флаг перемещаемости this.m_thumb.InitBackColors(this.m_thumb.BackColorFocused()); this.m_thumb.ColorsToDefault(); this.m_thumb.InitBorderColors(this.m_thumb.BackColor(),this.m_thumb.BackColorFocused(),this.m_thumb.BackColorPressed(),this.m_thumb.BackColorBlocked()); this.m_thumb.ColorsToDefault(); this.m_thumb.SetMovable(true); //--- Запрещаем самостоятельную перерисовку графика this.m_thumb.SetChartRedrawFlag(false); //--- Изначально в контейнере не отображается и не обрезается по его границам this.SetVisibleInContainer(false); this.SetTrimmered(false); } //+------------------------------------------------------------------+ //| CScrollBarH::Инициализация цветов объекта по умолчанию | //+------------------------------------------------------------------+ void CScrollBarH::InitColors(void) { //--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона this.InitBackColors(clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke); this.InitBackColorsAct(clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke); this.BackColorToDefault(); //--- Инициализируем цвета переднего плана для обычного и активированного состояний и делаем его текущим цветом текста this.InitForeColors(clrBlack,clrBlack,clrBlack,clrSilver); this.InitForeColorsAct(clrBlack,clrBlack,clrBlack,clrSilver); this.ForeColorToDefault(); //--- Инициализируем цвета рамки для обычного и активированного состояний и делаем его текущим цветом рамки this.InitBorderColors(clrLightGray,clrLightGray,clrLightGray,clrSilver); this.InitBorderColorsAct(clrLightGray,clrLightGray,clrLightGray,clrSilver); this.BorderColorToDefault(); //--- Инициализируем цвет рамки и цвет переднего плана для заблокированного элемента this.InitBorderColorBlocked(clrSilver); this.InitForeColorBlocked(clrSilver); } //+------------------------------------------------------------------+ //| CScrollBarH::Устанавливает флаг видимости в контейнере | //+------------------------------------------------------------------+ void CScrollBarH::SetVisibleInContainer(const bool flag) { this.m_visible_in_container=flag; if(this.m_butt_left!=NULL) this.m_butt_left.SetVisibleInContainer(flag); if(this.m_butt_right!=NULL) this.m_butt_right.SetVisibleInContainer(flag); if(this.m_thumb!=NULL) this.m_thumb.SetVisibleInContainer(flag); } //+------------------------------------------------------------------+ //| CScrollBarH::Устанавливает флаг обрезки по границам контейнера | //+------------------------------------------------------------------+ void CScrollBarH::SetTrimmered(const bool flag) { this.m_trim_flag=flag; if(this.m_butt_left!=NULL) this.m_butt_left.SetTrimmered(flag); if(this.m_butt_right!=NULL) this.m_butt_right.SetTrimmered(flag); if(this.m_thumb!=NULL) this.m_thumb.SetTrimmered(flag); } //+------------------------------------------------------------------+ //| CScrollBarH::Рисует внешний вид | //+------------------------------------------------------------------+ void CScrollBarH::Draw(const bool chart_redraw) { //--- Заливаем кнопку цветом фона, рисуем рамку и обновляем канвас фона this.Fill(this.BackColor(),false); this.m_background.Rectangle(this.AdjX(0),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG())); this.m_background.Update(false); //--- Обновляем канвас фона без перерисовки графика this.m_background.Update(false); //--- Рисуем элементы списка без перерисовки графика for(int i=0;i(CPanel::InsertNewElement(ELEMENT_TYPE_SCROLLBAR_H,"","ScrollBarH",0,this.Height()-DEF_SCROLLBAR_TH-1,this.Width()-1,DEF_SCROLLBAR_TH)); if(m_scrollbar_h!=NULL) { //--- Скрываем элемент и устанавливаем запрет самостоятельной перерисовки графика this.m_scrollbar_h.Hide(false); this.m_scrollbar_h.SetChartRedrawFlag(false); } //--- Создаём вертикальный скроллбар this.m_scrollbar_v=dynamic_cast(CPanel::InsertNewElement(ELEMENT_TYPE_SCROLLBAR_V,"","ScrollBarV",this.Width()-DEF_SCROLLBAR_TH-1,0,DEF_SCROLLBAR_TH,this.Height()-1)); if(m_scrollbar_v!=NULL) { //--- Скрываем элемент и устанавливаем запрет самостоятельной перерисовки графика this.m_scrollbar_v.Hide(false); this.m_scrollbar_v.SetChartRedrawFlag(false); } //--- Разрешаем прокрутку содержимого this.m_scroll_flag=true; } //+------------------------------------------------------------------+ //| CContainer::Отображает объект на всех периодах графика | //+------------------------------------------------------------------+ void CContainer::Show(const bool chart_redraw) { //--- Если объект уже видимый, или не должен отображаться в контейнере - уходим if(!this.m_hidden || !this.m_visible_in_container) return; //--- Отображаем панель CCanvasBase::Show(false); //--- Отображаем прикреплённые объекты for(int i=0;i2) { ::PrintFormat("%s: Error. You can only add one element to a container\nTo add multiple elements, use the panel",__FUNCTION__); return NULL; } //--- Создаём и добавляем новый элемент при помощи метода родительского класса //--- Элемент помещается в координаты 0,0 независимо от указанных в параметрах CElementBase *elm=CPanel::InsertNewElement(type,text,user_name,dx,dy,w,h); //--- Проверяем размеры элемента для отображения полос прокрутки this.CheckElementSizes(elm); //--- Возвращаем указатель на элемент return elm; } //+------------------------------------------------------------------+ //| CContainer::Добавляет указанный элемент в список | //+------------------------------------------------------------------+ CElementBase *CContainer::InsertElement(CElementBase *element,const int dx,const int dy) { //--- Проверяем, чтобы в списке было не более трёх объектов - две полосы прокрутки и добавляемый if(this.m_list_elm.Total()>2) { ::PrintFormat("%s: Error. You can only add one element to a container\nTo add multiple elements, use the panel",__FUNCTION__); return NULL; } //--- Добавляем указанный элемент при помощи метода родительского класса //--- Элемент помещается в координаты 0,0 независимо от указанных в параметрах CElementBase *elm=CPanel::InsertElement(element,0,0); //--- Проверяем размеры элемента для отображения полос прокрутки this.CheckElementSizes(elm); //--- Возвращаем указатель на элемент return elm; } //+------------------------------------------------------------------+ //| CContainer::Проверяет размеры элемента | //| для отображения полос прокрутки | //+------------------------------------------------------------------+ void CContainer::CheckElementSizes(CElementBase *element) { //--- Если передан пустой элемент, или прокрутка запрещена, или скроллбары не созданы - уходим if(element==NULL || !this.m_scroll_flag || this.m_scrollbar_h==NULL || this.m_scrollbar_v==NULL) return; //--- Получаем тип элемента и, если это скроллбар - уходим ENUM_ELEMENT_TYPE type=(ENUM_ELEMENT_TYPE)element.Type(); if(type==ELEMENT_TYPE_SCROLLBAR_H || type==ELEMENT_TYPE_SCROLLBAR_V) return; //--- Инициализируем флаги отображения полос прокрутки this.m_visible_scrollbar_h=false; this.m_visible_scrollbar_v=false; //--- Если ширина элемента больше ширины видимой области контейнера - //--- устанавливаем флаг отображения горизонтальной полосы прокрутки //--- и флаг отображения в контейнере if(element.Width()>this.ContentVisibleHorz()) { this.m_visible_scrollbar_h=true; this.m_scrollbar_h.SetVisibleInContainer(true); } //--- Если высота элемента больше высоты видимой области контейнера - //--- устанавливаем флаг отображения вертикальной полосы прокрутки //--- и флаг отображения в контейнере if(element.Height()>this.ContentVisibleVert()) { this.m_visible_scrollbar_v=true; this.m_scrollbar_v.SetVisibleInContainer(true); } //--- Если обе полосы прокрутки должны быть отображены if(this.m_visible_scrollbar_h && this.m_visible_scrollbar_v) { //--- Корректируем размер обеих полос прокрутки на толщину скроллбара и //--- устанавливаем размеры ползунков под новые размеры треков if(this.m_scrollbar_v.ResizeH(this.Height()-DEF_SCROLLBAR_TH)) this.m_scrollbar_v.SetThumbSize(this.ThumbSizeVert()); if(this.m_scrollbar_h.ResizeW(this.Width() -DEF_SCROLLBAR_TH)) this.m_scrollbar_h.SetThumbSize(this.ThumbSizeHorz()); } //--- Если горизонтальная полоса прокрутки должна быть показана if(this.m_visible_scrollbar_h) { //--- Уменьшаем размер видимого окна контейнера снизу на толщину полосы прокрутки + 1 пиксель this.SetBorderWidthBottom(this.m_scrollbar_h.Height()+1); //--- Корректируем размер ползунка под новый размер полосы прокрутки и //--- переносим скроллбар на передний план, делая его при этом видимым this.m_scrollbar_h.SetThumbSize(this.ThumbSizeHorz()); int end_track=this.X()+this.m_scrollbar_h.TrackBegin()+this.m_scrollbar_h.TrackLength(); int thumb_right=this.m_scrollbar_h.GetThumb().Right(); if(thumb_right>=end_track) { int pos=end_track-this.ThumbSizeHorz(); this.m_scrollbar_h.SetThumbPosition(pos); } this.m_scrollbar_h.SetVisibleInContainer(true); this.m_scrollbar_h.MoveY(this.Bottom()-DEF_SCROLLBAR_TH); this.m_scrollbar_h.BringToTop(false); } else { //--- Восстанавливаем размер видимого окна контейнера снизу, //--- скрываем горизонтальный скроллбар, ставим запрет его отображения в контейнере, //--- и устанавливаем высоту вертикального скроллбара по высоте контейнера this.SetBorderWidthBottom(this.m_init_border_size_bottom); this.m_scrollbar_h.Hide(false); this.m_scrollbar_h.SetVisibleInContainer(false); if(this.m_scrollbar_v.ResizeH(this.Height()-1)) this.m_scrollbar_v.SetThumbSize(this.ThumbSizeVert()); } //--- Если вертикальная полоса прокрутки должна быть показана if(this.m_visible_scrollbar_v) { //--- Уменьшаем размер видимого окна контейнера справа на толщину полосы прокрутки + 1 пиксель this.SetBorderWidthRight(this.m_scrollbar_v.Width()+1); //--- Корректируем размер ползунка под новый размер полосы прокрутки и //--- переносим скроллбар на передний план, делая его при этом видимым this.m_scrollbar_v.SetThumbSize(this.ThumbSizeVert()); int end_track=this.Y()+this.m_scrollbar_v.TrackBegin()+this.m_scrollbar_v.TrackLength(); int thumb_bottom=this.m_scrollbar_v.GetThumb().Bottom(); if(thumb_bottom>=end_track) { int pos=end_track-this.ThumbSizeVert(); this.m_scrollbar_v.SetThumbPosition(pos); } this.m_scrollbar_v.SetVisibleInContainer(true); this.m_scrollbar_v.MoveX(this.Right()-DEF_SCROLLBAR_TH); this.m_scrollbar_v.BringToTop(false); } else { //--- Восстанавливаем размер видимого окна контейнера справа, //--- скрываем вертикальный скроллбар, ставим запрет его отображения в контейнере, //--- и устанавливаем ширину горизонтального скроллбара по ширине контейнера this.SetBorderWidthRight(this.m_init_border_size_right); this.m_scrollbar_v.Hide(false); this.m_scrollbar_v.SetVisibleInContainer(false); if(this.m_scrollbar_h.ResizeW(this.Width()-1)) this.m_scrollbar_h.SetThumbSize(this.ThumbSizeHorz()); } //--- Если любая из полос прокрутки видима - обрезаем привязанный элемент по новым размерам видимой области if(this.m_visible_scrollbar_h || this.m_visible_scrollbar_v) { element.ObjectTrim(); } } //+-------------------------------------------------------------------+ //|CContainer::Рассчитывает размер ползунка горизонтального скроллбара| //+-------------------------------------------------------------------+ int CContainer::ThumbSizeHorz(void) { CElementBase *elm=this.GetAttachedElement(); if(elm==NULL || elm.Width()==0 || this.TrackLengthHorz()==0) return 0; return int(::round(::fmax(((double)this.ContentVisibleHorz() / (double)elm.Width()) * (double)this.TrackLengthHorz(), DEF_THUMB_MIN_SIZE))); } //+------------------------------------------------------------------+ //| CContainer::Рассчитывает размер ползунка вертикального скроллбара| //+------------------------------------------------------------------+ int CContainer::ThumbSizeVert(void) { CElementBase *elm=this.GetAttachedElement(); if(elm==NULL || elm.Height()==0 || this.TrackLengthVert()==0) return 0; return int(::round(::fmax(((double)this.ContentVisibleVert() / (double)elm.Height()) * (double)this.TrackLengthVert(), DEF_THUMB_MIN_SIZE))); } //+------------------------------------------------------------------+ //| CContainer::Полный размер содержимого по горизонтали | //+------------------------------------------------------------------+ int CContainer::ContentSizeHorz(void) { CElementBase *elm=this.GetAttachedElement(); return(elm!=NULL ? elm.Width() : 0); } //+------------------------------------------------------------------+ //| CContainer::Полный размер содержимого по вертикали | //+------------------------------------------------------------------+ int CContainer::ContentSizeVert(void) { CElementBase *elm=this.GetAttachedElement(); return(elm!=NULL ? elm.Height() : 0); } //+--------------------------------------------------------------------+ //|CContainer::Возвращает позицию содержимого контейнера по горизонтали| //+--------------------------------------------------------------------+ int CContainer::ContentPositionHorz(void) { CElementBase *elm=this.GetAttachedElement(); return(elm!=NULL ? elm.X()-this.X() : 0); } //+------------------------------------------------------------------+ //|CContainer::Возвращает позицию содержимого контейнера по вертикали| //+------------------------------------------------------------------+ int CContainer::ContentPositionVert(void) { CElementBase *elm=this.GetAttachedElement(); return(elm!=NULL ? elm.Y()-this.Y() : 0); } //+------------------------------------------------------------------+ //| CContainer::Рассчитывает и возвращает величину смещения | //| содержимого контейнера по горизонтали по положению ползунка | //+------------------------------------------------------------------+ int CContainer::CalculateContentOffsetHorz(const uint thumb_position) { CElementBase *elm=this.GetAttachedElement(); int effective_track_length=this.TrackEffectiveLengthHorz(); if(elm==NULL || effective_track_length==0) return 0; return (int)::round(((double)thumb_position / (double)effective_track_length) * ((double)elm.Width() - (double)this.ContentVisibleHorz())); } //+------------------------------------------------------------------+ //| CContainer::Рассчитывает и возвращает величину смещения | //| содержимого контейнера по вертикали по положению ползунка | //+------------------------------------------------------------------+ int CContainer::CalculateContentOffsetVert(const uint thumb_position) { CElementBase *elm=this.GetAttachedElement(); int effective_track_length=this.TrackEffectiveLengthVert(); if(elm==NULL || effective_track_length==0) return 0; return (int)::round(((double)thumb_position / (double)effective_track_length) * ((double)elm.Height() - (double)this.ContentVisibleVert())); } //+------------------------------------------------------------------+ //| CContainer::Рассчитывает и возвращает величину смещения ползунка | //| по горизонтали в зависимости от положения контента | //+------------------------------------------------------------------+ int CContainer::CalculateThumbOffsetHorz(const uint content_position) { CElementBase *elm=this.GetAttachedElement(); if(elm==NULL) return 0; int value=elm.Width()-this.ContentVisibleHorz(); if(value==0) return 0; return (int)::round(((double)content_position / (double)value) * ((double)this.TrackEffectiveLengthHorz() - (double)this.ThumbSizeHorz())); } //+------------------------------------------------------------------+ //| CContainer::Рассчитывает и возвращает величину смещения ползунка | //| по вертикали в зависимости от положения контента | //+------------------------------------------------------------------+ int CContainer::CalculateThumbOffsetVert(const uint content_position) { CElementBase *elm=this.GetAttachedElement(); if(elm==NULL) return 0; int value=elm.Height()-this.ContentVisibleVert(); if(value==0) return 0; return (int)::round(((double)content_position / (double)value) * ((double)this.TrackEffectiveLengthVert() - (double)this.ThumbSizeVert())); } //+-------------------------------------------------------------------+ //|CContainer::Смещает содержимое по горизонтали на указанное значение| //+-------------------------------------------------------------------+ bool CContainer::ContentShiftHorz(const int value) { //--- Получаем указатель на содержимое контейнера CElementBase *elm=this.GetAttachedElement(); if(elm==NULL) return false; //--- Для элемента CTableView получаем заголовок таблицы CElementBase *elm_container=elm.GetContainer(); CTableHeaderView *table_header=NULL; if(elm_container!=NULL && ::StringFind(elm.Name(),"Table")==0) { CElementBase *obj=elm_container.GetContainer(); if(obj!=NULL && obj.Type()==ELEMENT_TYPE_TABLE_VIEW) { CTableView *table_view=obj; table_header=table_view.GetHeader(); } } //--- Рассчитываем величину смещения по положению ползунка int content_offset=this.CalculateContentOffsetHorz(value); //--- Сдвигаем заголовок bool res=true; if(table_header!=NULL) { res &=table_header.MoveX(this.X()-content_offset); } //--- Возвращаем результат сдвига содержимого на рассчитанную величину res &=elm.MoveX(this.X()-content_offset); return res; } //+------------------------------------------------------------------+ //| CContainer::Смещает содержимое по вертикали на указанное значение| //+------------------------------------------------------------------+ bool CContainer::ContentShiftVert(const int value) { //--- Получаем указатель на содержимое контейнера CElementBase *elm=this.GetAttachedElement(); if(elm==NULL) return false; //--- Рассчитываем величину смещения по положению ползунка int content_offset=this.CalculateContentOffsetVert(value); //--- Возвращаем результат сдвига содержимого на рассчитанную величину return(elm.MoveY(this.Y()-content_offset)); } //+------------------------------------------------------------------+ //| Возвращает тип элемента, отправившего событие | //+------------------------------------------------------------------+ ENUM_ELEMENT_TYPE CContainer::GetEventElementType(const string name) { //--- Получаем имена всех элементов в иерархии (при ошибке - возвращаем -1) string names[]={}; int total = GetElementNames(name,"_",names); if(total==WRONG_VALUE) return WRONG_VALUE; //--- Найдём в массиве наименование контейнера, ближайшее к имени элемента с событием int cntr_index=-1; // Индекс наименования контейнера в массиве имён в иерархии элементов string cntr_name=""; // Наименование контейнера в массиве имён в иерархии элементов //--- Ищем в цикле самое первое с конца вхождение подстроки "CNTR" for(int i=total-1;i>=0;i--) { if(::StringFind(names[i],"CNTR")==0) { cntr_name=names[i]; cntr_index=i; break; } } //--- Если наименование контейнера не найдено в массиве (индекс равен -1) - возвращаем -1 if(cntr_index==WRONG_VALUE) return WRONG_VALUE; //--- Если в имени элемента нет подстроки с именем базового элемента, то это не наше событие - уходим string base_name=names[cntr_index]; if(::StringFind(this.NameFG(),base_name)==WRONG_VALUE) return WRONG_VALUE; //--- События, пришедшие не от скроллбаров, пропускаем string check_name=::StringSubstr(names[cntr_index+1],0,4); if(check_name!="SCBH" && check_name!="SCBV") return WRONG_VALUE; //--- Получаем имя элемента, от которого пришло событие и инициализируем тип элемента string elm_name=names[names.Size()-1]; ENUM_ELEMENT_TYPE type=WRONG_VALUE; //--- Проверяем и записываем тип элемента //--- Кнопка со стрелкой вверх if(::StringFind(elm_name,"BTARU")==0) type=ELEMENT_TYPE_BUTTON_ARROW_UP; //--- Кнопка со стрелкой вниз else if(::StringFind(elm_name,"BTARD")==0) type=ELEMENT_TYPE_BUTTON_ARROW_DOWN; //--- Кнопка со стрелкой влево else if(::StringFind(elm_name,"BTARL")==0) type=ELEMENT_TYPE_BUTTON_ARROW_LEFT; //--- Кнопка со стрелкой вправо else if(::StringFind(elm_name,"BTARR")==0) type=ELEMENT_TYPE_BUTTON_ARROW_RIGHT; //--- Ползунок горизонтальной полосы прокрутки else if(::StringFind(elm_name,"THMBH")==0) type=ELEMENT_TYPE_SCROLLBAR_THUMB_H; //--- Ползунок вертикальной полосы прокрутки else if(::StringFind(elm_name,"THMBV")==0) type=ELEMENT_TYPE_SCROLLBAR_THUMB_V; //--- Элемент управления ScrollBarHorisontal else if(::StringFind(elm_name,"SCBH")==0) type=ELEMENT_TYPE_SCROLLBAR_H; //--- Элемент управления ScrollBarVertical else if(::StringFind(elm_name,"SCBV")==0) type=ELEMENT_TYPE_SCROLLBAR_V; //--- Возвращаем тип элемента return type; } //+------------------------------------------------------------------+ //| CContainer::Обработчик пользовательского события элемента | //| при перемещении курсора в области объекта | //+------------------------------------------------------------------+ void CContainer::MouseMoveHandler(const int id,const long lparam,const double dparam,const string sparam) { bool res=false; //--- Получаем указатель на содержимое контейнера CElementBase *elm=this.GetAttachedElement(); //--- Получаем тип элемента, от которого пришло событие ENUM_ELEMENT_TYPE type=this.GetEventElementType(sparam); //--- Если не удалось получить тип элемента или указатель на содержимое - уходим if(type==WRONG_VALUE || elm==NULL) return; //--- Если событие ползунка горизонтального скроллбара - сдвигаем содержимое по горизонтали if(type==ELEMENT_TYPE_SCROLLBAR_THUMB_H) res=this.ContentShiftHorz((int)lparam); //--- Если событие ползунка вертикального скроллбара - сдвигаем содержимое по вертикали if(type==ELEMENT_TYPE_SCROLLBAR_THUMB_V) res=this.ContentShiftVert((int)lparam); //--- Если содержимое успешно сдвинуто - обновляем график if(res) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| CContainer::Обработчик пользовательского события элемента | //| при щелчке в области объекта | //+------------------------------------------------------------------+ void CContainer::MousePressHandler(const int id,const long lparam,const double dparam,const string sparam) { bool res=false; //--- Получаем указатель на содержимое контейнера CElementBase *elm=this.GetAttachedElement(); //--- Получаем тип элемента, от которого пришло событие ENUM_ELEMENT_TYPE type=this.GetEventElementType(sparam); //--- Если не удалось получить тип элемента или указатель на содержимое - уходим if(type==WRONG_VALUE || elm==NULL) return; //--- Если события кнопок горизонтального скроллбара, if(type==ELEMENT_TYPE_BUTTON_ARROW_LEFT || type==ELEMENT_TYPE_BUTTON_ARROW_RIGHT) { //--- Проверяем указатель на горизонтальный скроллбар if(this.m_scrollbar_h==NULL) return; //--- получаем указатель на ползунок скроллбара CScrollBarThumbH *obj=this.m_scrollbar_h.GetThumb(); if(obj==NULL) return; //--- определяем направление смещения ползунка по типу нажатой кнопки int direction=(type==ELEMENT_TYPE_BUTTON_ARROW_LEFT ? 120 : -120); //--- вызываем обработчик прокрутки объекта ползунка для смещения ползунка в направлении direction obj.OnWheelEvent(id,0,direction,this.NameFG()); //--- Успешно res=true; } //--- Если события кнопок вертикального скроллбара, if(type==ELEMENT_TYPE_BUTTON_ARROW_UP || type==ELEMENT_TYPE_BUTTON_ARROW_DOWN) { //--- Проверяем указатель на вертикальный скроллбар if(this.m_scrollbar_v==NULL) return; //--- получаем указатель на ползунок скроллбара CScrollBarThumbV *obj=this.m_scrollbar_v.GetThumb(); if(obj==NULL) return; //--- определяем направление смещения ползунка по типу нажатой кнопки int direction=(type==ELEMENT_TYPE_BUTTON_ARROW_UP ? 120 : -120); //--- вызываем обработчик прокрутки объекта ползунка для смещения ползунка в направлении direction obj.OnWheelEvent(id,0,direction,this.NameFG()); //--- Успешно res=true; } //--- Если событие щелчка по горизонтальному скроллбару (между ползунком и кнопками прокрутки), if(type==ELEMENT_TYPE_SCROLLBAR_H) { //--- Проверяем указатель на горизонтальный скроллбар if(this.m_scrollbar_h==NULL) return; //--- получаем указатель на ползунок скроллбара CScrollBarThumbH *thumb=this.m_scrollbar_h.GetThumb(); if(thumb==NULL) return; //--- Направление смещения ползунка int direction=(lparam>=thumb.Right() ? 1 : lparam<=thumb.X() ? -1 : 0); //--- Проверяем делитель на нулевое значение if(this.ContentSizeHorz()-this.ContentVisibleHorz()==0) return; //--- Рассчитываем смещение ползунка, пропорциональное смещению содержимого на один экран int thumb_shift=(int)::round(direction * ((double)this.ContentVisibleHorz() / double(this.ContentSizeHorz()-this.ContentVisibleHorz())) * (double)this.TrackEffectiveLengthHorz()); //--- вызываем обработчик прокрутки объекта ползунка для смещения ползунка в направлении смещения thumb.OnWheelEvent(id,thumb_shift,0,this.NameFG()); //--- Записываем результат смещения содержимого контейнера res=this.ContentShiftHorz(thumb_shift); } //--- Если событие щелчка по вертикальному скроллбару (между ползунком и кнопками прокрутки), if(type==ELEMENT_TYPE_SCROLLBAR_V) { //--- Проверяем указатель на вертикальный скроллбар if(this.m_scrollbar_v==NULL) return; //--- получаем указатель на ползунок скроллбара CScrollBarThumbV *thumb=this.m_scrollbar_v.GetThumb(); if(thumb==NULL) return; //--- Направление смещения ползунка int cursor=int(dparam-this.m_wnd_y); int direction=(cursor>=thumb.Bottom() ? 1 : cursor<=thumb.Y() ? -1 : 0); //--- Проверяем делитель на нулевое значение if(this.ContentSizeVert()-this.ContentVisibleVert()==0) return; //--- Рассчитываем смещение ползунка, пропорциональное смещению содержимого на один экран int thumb_shift=(int)::round(direction * ((double)this.ContentVisibleVert() / double(this.ContentSizeVert()-this.ContentVisibleVert())) * (double)this.TrackEffectiveLengthVert()); //--- вызываем обработчик прокрутки объекта ползунка для смещения ползунка в направлении смещения thumb.OnWheelEvent(id,thumb_shift,0,this.NameFG()); //--- Записываем результат смещения содержимого контейнера res=this.ContentShiftVert(thumb_shift); } //--- Если всё успешно - обновляем график if(res) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| CContainer::Обработчик пользовательского события элемента | //| при прокрутке колёсика в области ползунка скроллбара | //+------------------------------------------------------------------+ void CContainer::MouseWheelHandler(const int id,const long lparam,const double dparam,const string sparam) { bool res=false; //--- Получаем указатель на содержимое контейнера CElementBase *elm=this.GetAttachedElement(); //--- Получаем тип элемента, от которого пришло событие ENUM_ELEMENT_TYPE type=this.GetEventElementType(sparam); //--- Если не удалось получить указатель на содержимое, или тип элемента - уходим if(type==WRONG_VALUE || elm==NULL) return; //--- Если событие ползунка горизонтального скроллбара - сдвигаем содержимое по горизонтали if(type==ELEMENT_TYPE_SCROLLBAR_THUMB_H) res=this.ContentShiftHorz((int)lparam); //--- Если событие ползунка вертикального скроллбара - сдвигаем содержимое по вертикали if(type==ELEMENT_TYPE_SCROLLBAR_THUMB_V) res=this.ContentShiftVert((int)lparam); //--- Если содержимое успешно сдвинуто - обновляем график if(res) ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //| CContainer::Обработчик перетаскивания граней и углов элемента | //+------------------------------------------------------------------+ void CContainer::ResizeActionDragHandler(const int x, const int y) { //--- Проверяем валидность полос прокрутки if(this.m_scrollbar_h==NULL || this.m_scrollbar_v==NULL) return; //--- В зависимости от региона взаимодействия с курсором switch(this.ResizeRegion()) { //--- Изменение размера за правую границу case CURSOR_REGION_RIGHT : //--- Если новая ширина успешно установлена if(this.ResizeZoneRightHandler(x,y)) { //--- проверяем размер содержимого контейнера для отображения скроллбаров, //--- смещаем содержимое по новой позиции ползунка горизонтального скроллбара this.CheckElementSizes(this.GetAttachedElement()); this.ContentShiftHorz(this.m_scrollbar_h.ThumbPosition()); } break; //--- Изменение размера за нижнюю границу case CURSOR_REGION_BOTTOM : //--- Если новая высота успешно установлена if(this.ResizeZoneBottomHandler(x,y)) { //--- проверяем размер содержимого контейнера для отображения скроллбаров, //--- смещаем содержимое по новой позиции ползунка вертикального скроллбара this.CheckElementSizes(this.GetAttachedElement()); this.ContentShiftVert(this.m_scrollbar_v.ThumbPosition()); } break; //--- Изменение размера за левую границу case CURSOR_REGION_LEFT : //--- Если новые координата X и ширина успешно установлены if(this.ResizeZoneLeftHandler(x,y)) { //--- проверяем размер содержимого контейнера для отображения скроллбаров, //--- смещаем содержимое по новой позиции ползунка горизонтального скроллбара this.CheckElementSizes(this.GetAttachedElement()); this.ContentShiftHorz(this.m_scrollbar_h.ThumbPosition()); } break; //--- Изменение размера за верхнюю границу case CURSOR_REGION_TOP : //--- Если новые координата Y и высота успешно установлены if(this.ResizeZoneTopHandler(x,y)) { //--- проверяем размер содержимого контейнера для отображения скроллбаров, //--- смещаем содержимое по новой позиции ползунка вертикального скроллбара this.CheckElementSizes(this.GetAttachedElement()); this.ContentShiftVert(this.m_scrollbar_v.ThumbPosition()); } break; //--- Изменение размера за правый нижний угол case CURSOR_REGION_RIGHT_BOTTOM : //--- Если новые ширина и высота успешно установлены if(this.ResizeZoneRightBottomHandler(x,y)) { //--- проверяем размер содержимого контейнера для отображения скроллбаров, //--- смещаем содержимое по новым позициям ползунков скроллбаров this.CheckElementSizes(this.GetAttachedElement()); this.ContentShiftHorz(this.m_scrollbar_h.ThumbPosition()); this.ContentShiftVert(this.m_scrollbar_v.ThumbPosition()); } break; //--- Изменение размера за правый верхний угол case CURSOR_REGION_RIGHT_TOP : //--- Если новые координата Y, ширина и высота успешно установлены if(this.ResizeZoneRightTopHandler(x,y)) { //--- проверяем размер содержимого контейнера для отображения скроллбаров, //--- смещаем содержимое по новым позициям ползунков скроллбаров this.CheckElementSizes(this.GetAttachedElement()); this.ContentShiftHorz(this.m_scrollbar_h.ThumbPosition()); this.ContentShiftVert(this.m_scrollbar_v.ThumbPosition()); } break; //--- Изменение размера за левый нижний угол case CURSOR_REGION_LEFT_BOTTOM : //--- Если новые координата X, ширина и высота успешно установлены if(this.ResizeZoneLeftBottomHandler(x,y)) { //--- проверяем размер содержимого контейнера для отображения скроллбаров, //--- смещаем содержимое по новым позициям ползунков скроллбаров this.CheckElementSizes(this.GetAttachedElement()); this.ContentShiftHorz(this.m_scrollbar_h.ThumbPosition()); this.ContentShiftVert(this.m_scrollbar_v.ThumbPosition()); } break; //--- Изменение размера за левый верхний угол case CURSOR_REGION_LEFT_TOP : //--- Если новые координаты X и Y, ширина и высота успешно установлены if(this.ResizeZoneLeftTopHandler(x,y)) {} { //--- проверяем размер содержимого контейнера для отображения скроллбаров, //--- смещаем содержимое по новым позициям ползунков скроллбаров this.CheckElementSizes(this.GetAttachedElement()); this.ContentShiftHorz(this.m_scrollbar_h.ThumbPosition()); this.ContentShiftVert(this.m_scrollbar_v.ThumbPosition()); } break; //--- По умолчанию - уходим default: return; } ::ChartRedraw(this.m_chart_id); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс визуального представления ячейки таблицы | //+------------------------------------------------------------------+ class CTableCellView : public CBoundedObj { protected: CTableCell *m_table_cell_model; // Указатель на модель ячейки CImagePainter *m_painter; // Указатель на объект рисования CTableRowView *m_element_base; // Указатель на базовый элемент (строка таблицы) CCanvas *m_background; // Указатель на канвас фона CCanvas *m_foreground; // Указатель на канвас переднего плана int m_index; // Индекс в списке ячеек ENUM_ANCHOR_POINT m_text_anchor; // Точка привязки текста (выравнивание в ячейке) int m_text_x; // Координата X текста (смещение относительно левой границы области объекта) int m_text_y; // Координата Y текста (смещение относительно верхней границы области объекта) ushort m_text[]; // Текст color m_fore_color; // Цвет переднего плана //--- Возвращает смещения начальных координат рисования на холсте относительно канваса и координат базового элемента int CanvasOffsetX(void) const { return(this.m_element_base.ObjectX()-this.m_element_base.X()); } int CanvasOffsetY(void) const { return(this.m_element_base.ObjectY()-this.m_element_base.Y()); } //--- Возвращает скорректированную координату точки на холсте с учётом смещения холста относительно базового элемента int AdjX(const int x) const { return(x-this.CanvasOffsetX()); } int AdjY(const int y) const { return(y-this.CanvasOffsetY()); } //--- Возвращает координаты X и Y текста в зависимости от точки привязки bool GetTextCoordsByAnchor(int &x, int &y, int &dir_x, int dir_y); //--- Возвращает указатель на контейнер панели строк таблицы CContainer *GetRowsPanelContainer(void); public: //--- Возвращает указатель на назначенный канвас (1) фона, (2) переднего плана CCanvas *GetBackground(void) { return this.m_background; } CCanvas *GetForeground(void) { return this.m_foreground; } //--- Получение границ родительского объекта-контейнера int ContainerLimitLeft(void) const { return(this.m_element_base==NULL ? this.X() : this.m_element_base.LimitLeft()); } int ContainerLimitRight(void) const { return(this.m_element_base==NULL ? this.Right() : this.m_element_base.LimitRight()); } int ContainerLimitTop(void) const { return(this.m_element_base==NULL ? this.Y() : this.m_element_base.LimitTop()); } int ContainerLimitBottom(void) const { return(this.m_element_base==NULL ? this.Bottom() : this.m_element_base.LimitBottom()); } //--- Возвращает флаг того, что объект расположен за пределами своего контейнера virtual bool IsOutOfContainer(void); //--- (1) Устанавливает, (2) возвращает текст ячейки void SetText(const string text) { ::StringToShortArray(text,this.m_text); } string Text(void) const { return ::ShortArrayToString(this.m_text); } //--- (1) Устанавливает, (2) возвращает цвет текста ячейки void SetForeColor(const color clr) { this.m_fore_color=clr; } color ForeColor(void) const { return this.m_fore_color; } //--- Устанавливает идентификатор virtual void SetID(const int id) { this.m_index=this.m_id=id; } //--- (1) Устанавливает, (2) возвращает индекс ячейки void SetIndex(const int index) { this.SetID(index); } int Index(void) const { return this.m_index; } //--- (1) Устанавливает, (2) возвращает смещение текста по оси X void SetTextShiftX(const int shift) { this.m_text_x=shift; } int TextShiftX(void) const { return this.m_text_x; } //--- (1) Устанавливает, (2) возвращает смещение текста по оси Y void SetTextShiftY(const int shift) { this.m_text_y=shift; } int TextShiftY(void) const { return this.m_text_y; } //--- (1) Устанавливает, (2) возвращает точку привязки текста void SetTextAnchor(const ENUM_ANCHOR_POINT anchor,const bool cell_redraw,const bool chart_redraw); int TextAnchor(void) const { return this.m_text_anchor; } //--- Устанавливает точку привязки и смещения текста void SetTextPosition(const ENUM_ANCHOR_POINT anchor,const int shift_x,const int shift_y,const bool cell_redraw,const bool chart_redraw); //--- Назначает базовый элемент (строку таблицы) void RowAssign(CTableRowView *base_element); //--- (1) Назначает, (2) возвращает модель ячейки bool TableCellModelAssign(CTableCell *cell_model,int dx,int dy,int w,int h); CTableCell *GetTableCellModel(void) { return this.m_table_cell_model; } //--- Распечатывает в журнале назначенную модель ячейки void TableCellModelPrint(void); //--- (1) Заливает объект цветом фона, (2) обновляет объект для отображения изменений, (3) рисует внешний вид virtual void Clear(const bool chart_redraw); virtual void Update(const bool chart_redraw); virtual void Draw(const bool chart_redraw); //--- Выводит текст virtual void DrawText(const int dx, const int dy, const string text, const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0)const { return CBaseObj::Compare(node,mode); } virtual bool Save(const int file_handle); virtual bool Load(const int file_handle); virtual int Type(void) const { return(ELEMENT_TYPE_TABLE_CELL_VIEW); } //--- Инициализация объекта класса void Init(const string text); //--- Возвращает описание объекта virtual string Description(void); //--- Конструкторы/деструктор CTableCellView(void); CTableCellView(const int id, const string user_name, const string text, const int x, const int y, const int w, const int h); ~CTableCellView (void){} }; //+------------------------------------------------------------------+ //| CTableCellView::Конструктор по умолчанию. Строит объект в главном| //| окне текущего графика в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CTableCellView::CTableCellView(void) : CBoundedObj("TableCell",-1,0,0,DEF_PANEL_W,DEF_TABLE_ROW_H), m_index(-1),m_text_anchor(ANCHOR_LEFT) { //--- Инициализация this.Init(""); this.SetID(-1); this.SetName("TableCell"); } //+------------------------------------------------------------------+ //| CTableCellView::Конструктор параметрический. Строит объект | //| в указанном окне указанного графика с указанными текстом, | //| координатами и размерами | //+------------------------------------------------------------------+ CTableCellView::CTableCellView(const int id, const string user_name, const string text, const int x, const int y, const int w, const int h) : CBoundedObj(user_name,id,x,y,w,h), m_index(-1),m_text_anchor(ANCHOR_LEFT) { //--- Инициализация this.Init(text); this.SetID(id); this.SetName(user_name); } //+------------------------------------------------------------------+ //| CTableCellView::Инициализация | //+------------------------------------------------------------------+ void CTableCellView::Init(const string text) { //--- Класс не управляет канвасами this.m_canvas_owner=false; //--- Текст ячейки this.SetText(text); //--- Смещения текста по умолчанию this.m_text_x=2; this.m_text_y=0; } //+------------------------------------------------------------------+ //| CTableCellView::Возвращает описание объекта | //+------------------------------------------------------------------+ string CTableCellView::Description(void) { string nm=this.Name(); string name=(nm!="" ? ::StringFormat(" \"%s\"",nm) : nm); return ::StringFormat("%s%s ID %d, X %d, Y %d, W %d, H %d, Value: \"%s\"", ElementDescription((ENUM_ELEMENT_TYPE)this.Type()),name, this.ID(),this.X(),this.Y(),this.Width(),this.Height(),this.Text()); } //+------------------------------------------------------------------+ //| CTableCellView::Назначает строку, канвасы фона и переднего плана | //+------------------------------------------------------------------+ void CTableCellView::RowAssign(CTableRowView *base_element) { if(base_element==NULL) { ::PrintFormat("%s: Error. Empty element passed",__FUNCTION__); return; } this.m_element_base=base_element; this.m_background=this.m_element_base.GetBackground(); this.m_foreground=this.m_element_base.GetForeground(); this.m_painter=this.m_element_base.Painter(); this.m_fore_color=this.m_element_base.ForeColor(); } //+------------------------------------------------------------------+ //| CTableCellView::Назначает модель ячейки | //+------------------------------------------------------------------+ bool CTableCellView::TableCellModelAssign(CTableCell *cell_model,int dx,int dy,int w,int h) { //--- Если передан невалидный объект модели ячейки - сообщаем об этом и возвращаем false if(cell_model==NULL) { ::PrintFormat("%s: Error. Empty object passed",__FUNCTION__); return false; } //--- Если базовый элемент (строка таблицы) не назначен - сообщаем об этом и возвращаем false if(this.m_element_base==NULL) { ::PrintFormat("%s: Error. Base element not assigned. Please use RowAssign() method first",__FUNCTION__); return false; } //--- Сохраняем модель ячейки this.m_table_cell_model=cell_model; //--- Устанавливаем координаты и размеры визуального представления ячейки this.BoundSetXY(dx,dy); this.BoundResize(w,h); //--- Устанавливаем размеры области рисования визуального представления ячейки this.m_painter.SetBound(dx,dy,w,h); //--- Всё успешно return true; } //+------------------------------------------------------------------+ //| CTableCellView::Возвращает координаты X и Y текста | //| в зависимости от точки привязки | //+------------------------------------------------------------------+ bool CTableCellView::GetTextCoordsByAnchor(int &x,int &y, int &dir_x,int dir_y) { //--- Получаем размеры текста в ячейке int text_w=0, text_h=0; this.m_foreground.TextSize(this.Text(),text_w,text_h); if(text_w==0 || text_h==0) return false; //--- В зависимости от точки привязки текста в ячейке //--- рассчитываем его начальные координаты (верхний левый угол) switch(this.m_text_anchor) { //--- Точка привязки слева по центру case ANCHOR_LEFT : x=0; y=(this.Height()-text_h)/2; dir_x=1; dir_y=1; break; //--- Точка привязки в левом нижнем углу case ANCHOR_LEFT_LOWER : x=0; y=this.Height()-text_h; dir_x= 1; dir_y=-1; break; //--- Точка привязки снизу по центру case ANCHOR_LOWER : x=(this.Width()-text_w)/2; y=this.Height()-text_h; dir_x= 1; dir_y=-1; break; //--- Точка привязки в правом нижнем углу case ANCHOR_RIGHT_LOWER : x=this.Width()-text_w; y=this.Height()-text_h; dir_x=-1; dir_y=-1; break; //--- Точка привязки справа по центру case ANCHOR_RIGHT : x=this.Width()-text_w; y=(this.Height()-text_h)/2; dir_x=-1; dir_y= 1; break; //--- Точка привязки в правом верхнем углу case ANCHOR_RIGHT_UPPER : x=this.Width()-text_w; y=0; dir_x=-1; dir_y= 1; break; //--- Точка привязки сверху по центру case ANCHOR_UPPER : x=(this.Width()-text_w)/2; y=0; dir_x=1; dir_y=1; break; //--- Точка привязки строго по центру объекта case ANCHOR_CENTER : x=(this.Width()-text_w)/2; y=(this.Height()-text_h)/2; dir_x=1; dir_y=1; break; //--- Точка привязки в левом верхнем углу //---ANCHOR_LEFT_UPPER default: x=0; y=0; dir_x=1; dir_y=1; break; } return true; } //+------------------------------------------------------------------+ //| CTableCellView::Устанавливает точку привязки текста | //+------------------------------------------------------------------+ void CTableCellView::SetTextAnchor(const ENUM_ANCHOR_POINT anchor,const bool cell_redraw,const bool chart_redraw) { if(this.m_text_anchor==anchor) return; this.m_text_anchor=anchor; if(cell_redraw) this.Draw(chart_redraw); } //+------------------------------------------------------------------+ //| CTableCellView::Устанавливает точку привязки и смещения текста | //+------------------------------------------------------------------+ void CTableCellView::SetTextPosition(const ENUM_ANCHOR_POINT anchor,const int shift_x,const int shift_y,const bool cell_redraw,const bool chart_redraw) { this.SetTextShiftX(shift_x); this.SetTextShiftY(shift_y); this.SetTextAnchor(anchor,cell_redraw,chart_redraw); } //+------------------------------------------------------------------+ //| CTableCellView::Заливает объект цветом | //+------------------------------------------------------------------+ void CTableCellView::Clear(const bool chart_redraw) { //--- Устанавливаем корректные координаты углов ячейки int x1=this.AdjX(this.m_bound.X()); int y1=this.AdjY(this.m_bound.Y()); int x2=this.AdjX(this.m_bound.Right()); int y2=this.AdjY(this.m_bound.Bottom()); //--- Стираем фон и передний план внутри прямоугольной области расположения ячейки if(this.m_background!=NULL) this.m_background.FillRectangle(x1,y1,x2,y2-1,::ColorToARGB(this.m_element_base.BackColor(),this.m_element_base.AlphaBG())); if(this.m_foreground!=NULL) this.m_foreground.FillRectangle(x1,y1,x2,y2-1,clrNULL); } //+------------------------------------------------------------------+ //| CTableCellView::Обновляет объект для отображения изменений | //+------------------------------------------------------------------+ void CTableCellView::Update(const bool chart_redraw) { if(this.m_background!=NULL) this.m_background.Update(false); if(this.m_foreground!=NULL) this.m_foreground.Update(chart_redraw); } //+------------------------------------------------------------------+ //| CTableCellView::Возвращает указатель | //| на контейнер панели строк таблицы | //+------------------------------------------------------------------+ CContainer *CTableCellView::GetRowsPanelContainer(void) { //--- Проверяем строку if(this.m_element_base==NULL) return NULL; //--- Получаем панель для размещения строк CPanel *rows_area=this.m_element_base.GetContainer(); if(rows_area==NULL) return NULL; //--- Возвращаем контейнер панели со строками return rows_area.GetContainer(); } //+------------------------------------------------------------------+ //| CTableCellView::Возвращает флаг того, что объект | //| расположен за пределами своего контейнера | //+------------------------------------------------------------------+ bool CTableCellView::IsOutOfContainer(void) { //--- Проверяем строку if(this.m_element_base==NULL) return false; //--- Получаем контейнер панели со строками CContainer *container=this.GetRowsPanelContainer(); if(container==NULL) return false; //--- Получаем границы ячейки по всем сторонам int cell_l=this.m_element_base.X()+this.X(); int cell_r=this.m_element_base.X()+this.Right(); int cell_t=this.m_element_base.Y()+this.Y(); int cell_b=this.m_element_base.Y()+this.Bottom(); //--- Возвращаем результат проверки, что объект полностью выходит за пределы контейнера return(cell_r <= container.X() || cell_l >= container.Right() || cell_b <= container.Y() || cell_t >= container.Bottom()); } //+------------------------------------------------------------------+ //| CTableCellView::Рисует внешний вид | //+------------------------------------------------------------------+ void CTableCellView::Draw(const bool chart_redraw) { //--- Если ячейка за пределами контейнера строк таблицы - уходим if(this.IsOutOfContainer()) return; //--- Получаем координаты текста и направление смещения в зависимости от точки привязки int text_x=0, text_y=0; int dir_horz=0, dir_vert=0; if(!this.GetTextCoordsByAnchor(text_x,text_y,dir_horz,dir_vert)) return; //--- Корректируем координаты текста int x=this.AdjX(this.X()+text_x); int y=this.AdjY(this.Y()+text_y); //--- Устанавливаем координаты разделительной линии int x1=this.AdjX(this.X()); int x2=this.AdjX(this.X()); int y1=this.AdjY(this.Y()); int y2=this.AdjY(this.Bottom()); //--- Выводим текст на канвасе переднего плана с учётом направления смещения без обновления графика this.DrawText(x+this.m_text_x*dir_horz,y+this.m_text_y*dir_vert,this.Text(),false); //--- Если это не крайняя справа ячейка - рисуем у ячейки справа вертикальную разделительную полосу if(this.m_element_base!=NULL && this.Index()0 && h>0) { //--- Стираем текст у правой границы объекта по размеру текста "троеточие" и заменяем троеточием окончание текста метки this.m_foreground.FillRectangle(this.AdjX(this.Right())-w,this.AdjY(this.Y()),this.AdjX(this.Right()),this.AdjY(this.Y())+h,clrNULL); this.m_foreground.TextOut(this.AdjX(this.Right())-w,this.AdjY(dy),"...",::ColorToARGB(this.ForeColor(),this.m_element_base.AlphaFG())); } } //--- Обновляем канвас переднего плана с указанным флагом перерисовки графика this.m_foreground.Update(chart_redraw); } //+------------------------------------------------------------------+ //| CTableCellView::Распечатывает в журнале назначенную модель строки| //+------------------------------------------------------------------+ void CTableCellView::TableCellModelPrint(void) { if(this.m_table_cell_model!=NULL) this.m_table_cell_model.Print(); } //+------------------------------------------------------------------+ //| CTableCellView::Сохранение в файл | //+------------------------------------------------------------------+ bool CTableCellView::Save(const int file_handle) { //--- Сохраняем данные родительского объекта if(!CBaseObj::Save(file_handle)) return false; //--- Сохраняем номер ячейки if(::FileWriteInteger(file_handle,this.m_index,INT_VALUE)!=INT_VALUE) return false; //--- Сохраняем точку привязки текста if(::FileWriteInteger(file_handle,this.m_text_anchor,INT_VALUE)!=INT_VALUE) return false; //--- Сохраняем координату X текста if(::FileWriteInteger(file_handle,this.m_text_x,INT_VALUE)!=INT_VALUE) return false; //--- Сохраняем координату Y текста if(::FileWriteInteger(file_handle,this.m_text_y,INT_VALUE)!=INT_VALUE) return false; //--- Сохраняем текст if(::FileWriteArray(file_handle,this.m_text)!=sizeof(this.m_text)) return false; //--- Всё успешно return true; } //+------------------------------------------------------------------+ //| CTableCellView::Загрузка из файла | //+------------------------------------------------------------------+ bool CTableCellView::Load(const int file_handle) { //--- Загружаем данные родительского объекта if(!CBaseObj::Load(file_handle)) return false; //--- Загружаем номер ячейки this.m_id=this.m_index=::FileReadInteger(file_handle,INT_VALUE); //--- Загружаем точку привязки текста this.m_text_anchor=(ENUM_ANCHOR_POINT)::FileReadInteger(file_handle,INT_VALUE); //--- Загружаем координату X текста this.m_text_x=::FileReadInteger(file_handle,INT_VALUE); //--- Загружаем координату Y текста this.m_text_y=::FileReadInteger(file_handle,INT_VALUE); //--- Загружаем текст if(::FileReadArray(file_handle,this.m_text)!=sizeof(this.m_text)) return false; //--- Всё успешно return true; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс визуального представления строки таблицы | //+------------------------------------------------------------------+ class CTableRowView : public CPanel { protected: CTableCellView m_temp_cell; // Временный объект ячейки для поиска CTableRow *m_table_row_model; // Указатель на модель строки CListElm m_list_cells; // Список ячеек int m_index; // Индекс в списке строк //--- Создаёт и добавляет в список новый объект представления ячейки CTableCellView *InsertNewCellView(const int index,const string text,const int dx,const int dy,const int w,const int h); //--- Удаляет указанную область строки и ячейку с соответствующим индексом bool BoundCellDelete(const int index); public: //--- Возвращает (1) список, (2) количество ячеек, (3) ячейку CListElm *GetListCells(void) { return &this.m_list_cells; } int CellsTotal(void) const { return this.m_list_cells.Total(); } CTableCellView *GetCellView(const uint index) { return this.m_list_cells.GetNodeAtIndex(index); } //--- Устанавливает идентификатор virtual void SetID(const int id) { this.m_index=this.m_id=id; } //--- (1) Устанавливает, (2) возвращает индекс строки void SetIndex(const int index) { this.SetID(index); } int Index(void) const { return this.m_index; } //--- (1) Устанавливает, (2) возвращает модель строки bool TableRowModelAssign(CTableRow *row_model); CTableRow *GetTableRowModel(void) { return this.m_table_row_model; } //--- Обновляет сторку с обновлённой моделью bool TableRowModelUpdate(CTableRow *row_model); //--- Перерассчитывает области ячеек bool RecalculateBounds(CListElm *list_bounds); //--- Распечатывает в журнале назначенную модель строки void TableRowModelPrint(const bool detail, const bool as_table=false, const int cell_width=CELL_WIDTH_IN_CHARS); //--- Рисует внешний вид virtual void Draw(const bool chart_redraw); //--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта virtual int Compare(const CObject *node,const int mode=0)const { return CLabel::Compare(node,mode); } virtual bool Save(const int file_handle); virtual bool Load(const int file_handle); virtual int Type(void) const { return(ELEMENT_TYPE_TABLE_ROW_VIEW); } //--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию void Init(void); virtual void InitColors(void); //--- Конструкторы/деструктор CTableRowView(void); CTableRowView(const string object_name, const string text, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CTableRowView (void){ this.m_list_cells.Clear(); } }; //+------------------------------------------------------------------+ //| CTableRowView::Конструктор по умолчанию. Строит объект в главном | //| окне текущего графика в координатах 0,0 с размерами по умолчанию | //+------------------------------------------------------------------+ CTableRowView::CTableRowView(void) : CPanel("TableRow","",::ChartID(),0,0,0,DEF_PANEL_W,DEF_TABLE_ROW_H), m_index(-1) { //--- Инициализация this.Init(); } //+------------------------------------------------------------------+ //| CTableRowView::Конструктор параметрический. Строит объект в | //| указанном окне указанного графика с указанными текстом, | //| координатами и размерами | //+------------------------------------------------------------------+ CTableRowView::CTableRowView(const string object_name,const string text,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CPanel(object_name,text,chart_id,wnd,x,y,w,h), m_index(-1) { //--- Инициализация this.Init(); } //+------------------------------------------------------------------+ //| CTableRowView::Инициализация | //+------------------------------------------------------------------+ void CTableRowView::Init(void) { //--- Инициализация родительского объекта CPanel::Init(); //--- Фон - непрозрачный this.SetAlphaBG(255); //--- Ширина рамки this.SetBorderWidth(1); } //+------------------------------------------------------------------+ //| CTableRowView::Инициализация цветов объекта по умолчанию | //+------------------------------------------------------------------+ void CTableRowView::InitColors(void) { //--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона this.InitBackColors(clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke); this.InitBackColorsAct(clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke,clrWhiteSmoke); this.BackColorToDefault(); //--- Инициализируем цвета переднего плана для обычного и активированного состояний и делаем его текущим цветом текста this.InitForeColors(clrBlack,clrBlack,clrBlack,clrSilver); this.InitForeColorsAct(clrBlack,clrBlack,clrBlack,clrSilver); this.ForeColorToDefault(); //--- Инициализируем цвета рамки для обычного и активированного состояний и делаем его текущим цветом рамки this.InitBorderColors(C'200,200,200',C'200,200,200',C'200,200,200',clrSilver); this.InitBorderColorsAct(C'200,200,200',C'200,200,200',C'200,200,200',clrSilver); this.BorderColorToDefault(); //--- Инициализируем цвет рамки и цвет переднего плана для заблокированного элемента this.InitBorderColorBlocked(clrSilver); this.InitForeColorBlocked(clrSilver); } //+------------------------------------------------------------------+ //| CTableRowView::Создаёт и добавляет в список | //| новый объект представления ячейки | //+------------------------------------------------------------------+ CTableCellView *CTableRowView::InsertNewCellView(const int index,const string text,const int dx,const int dy,const int w,const int h) { //--- Проверяем есть ли в списке объект с указанным идентификатором и, если да - сообщаем об этом и возвращаем NULL this.m_temp_cell.SetIndex(index); //--- Запоминаем метод сортировки списка int sort_mode=this.m_list_cells.SortMode(); //--- Устанавливаем списку флаг сортировки по идентификатору this.m_list_cells.Sort(ELEMENT_SORT_BY_ID); if(this.m_list_cells.Search(&this.m_temp_cell)!=NULL) { //--- Возвращаем списку изначальную сортировку, сообщаем, что такой объект уже существует и возвращаем NULL this.m_list_cells.Sort(sort_mode); ::PrintFormat("%s: Error. The TableCellView object with index %d is already in the list",__FUNCTION__,index); return NULL; } //--- Возвращаем списку изначальную сортировку this.m_list_cells.Sort(sort_mode); //--- Создаём имя объекта ячейки string name="TableCellView"+(string)this.Index()+"x"+(string)index; //--- Создаём новый объект TableCellView; при неудаче - сообщаем об этом и возвращаем NULL CTableCellView *cell_view=new CTableCellView(index,name,text,dx,dy,w,h); if(cell_view==NULL) { ::PrintFormat("%s: Error. Failed to create CTableCellView object",__FUNCTION__); return NULL; } //--- Если новый объект не удалось добавить в список - сообщаем об этом, удаляем объект и возвращаем NULL if(this.m_list_cells.Add(cell_view)==-1) { ::PrintFormat("%s: Error. Failed to add CTableCellView object to list",__FUNCTION__); delete cell_view; return NULL; } //--- Назначаем базовый элемент (строку) и возвращаем указатель на объект cell_view.RowAssign(&this); return cell_view; } //+------------------------------------------------------------------+ //| CTableRowView::Устанавливает модель строки | //+------------------------------------------------------------------+ bool CTableRowView::TableRowModelAssign(CTableRow *row_model) { //--- Если передан пустой объект - сообщаем об этом и возвращаем false if(row_model==NULL) { ::PrintFormat("%s: Error. Empty object passed",__FUNCTION__); return false; } //--- Если в переданной модели строки нет ни одной ячейки - сообщаем об этом и возвращаем false int total=(int)row_model.CellsTotal(); if(total==0) { ::PrintFormat("%s: Error. Row model does not contain any cells",__FUNCTION__); return false; } //--- Сохраняем указатель на переданную модель строки this.m_table_row_model=row_model; //--- рассчитываем ширину ячейки по ширине панели строк CCanvasBase *base=this.GetContainer(); int w=(base!=NULL ? base.Width() : this.Width()); int cell_w=(int)::fmax(::round((double)w/(double)total),DEF_TABLE_COLUMN_MIN_W); //--- В цикле по количеству ячеек в модели строки for(int i=0;i0) { //--- В цикле по количеству недостающих областей for(int i=total_bounds;iend;i--) { if(!this.BoundCellDelete(i)) return false; } } //--- В цикле по количеству ячеек в модели строки for(int i=0;ibase_obj.ContainerLimitRight()) assigned_obj.Hide(false); else assigned_obj.Show(false); } } //--- Переходим к следующей области next_bound=this.m_list_bounds.GetNextNode(); } //--- Рассчитаем новую ширину заголовка таблицы по ширине заголовков столбцов int header_width=0; for(int i=0;i0) { //--- Получаем последнюю строку визуального представления таблицы (на основе её координат будут размещены добавляемые строки) row=this.m_table_area.GetAttachedElementAt(total_view-1); //--- В цикле по количеству недостающих строк for(int i=total_view;iend;i--) res &=list.Delete(i); if(!res) return false; } //--- В цикле по списку строк модели таблицы for(int i=0;i=0 && dparam>=0) return; //--- Получаем из sparam наименование объекта заголовка таблицы int len=::StringLen(this.NameFG()); string header_str=::StringSubstr(sparam,0,len); //--- Если извлечённое имя не совпадает с именем этого объекта - не наше событие, уходим if(header_str!=this.NameFG()) return; //--- Записываем индекс заголовка столбца //--- Так как в стандартном событии OBJECT_CLICK в lparam и dparam передаются координаты курсора, //--- то для этого обработчика передаётся отрицательное значение индекса заголовка, по которому было событие int index=(int)::fabs(lparam+1000); //--- Получаем заголовок столбца по индексу CColumnCaptionView *caption=this.GetColumnCaption(index); if(caption==NULL) return; //--- Сортируем список строк по значению сортировки в заголовке столбца и обновляем таблицу this.Sort(index,caption.SortMode()); if(this.UpdateTable()) this.Draw(true); } //+------------------------------------------------------------------+ //| CTableView::Сортирует таблицу по значению столбца и направлению | //+------------------------------------------------------------------+ bool CTableView::Sort(const uint column,const ENUM_TABLE_SORT_MODE sort_mode) { //--- Если модель таблицы не назначена, сообщаем об этом и возвращаем false if(this.m_table_model==NULL) { ::PrintFormat("%s: Error. The table model is not assigned. Please use the TableObjectAssign() method first",__FUNCTION__); return false; } //--- Если у таблицы нет заголовка или сортировка отсутствует - возвращаем false if(this.m_header_model==NULL || sort_mode==TABLE_SORT_MODE_NONE) return false; //--- Устанавливаем флаг направления сортировки и сортируем модель таблицы по указанному столбцу и направлению bool descending=(sort_mode==TABLE_SORT_MODE_DESC); this.m_table_model.SortByColumn(column,descending); //--- Успешно return true; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Класс управления таблицами | //+------------------------------------------------------------------+ class CTableControl : public CPanel { protected: CListObj m_list_table_model; //--- Добавляет объект (1) модели (CTable), (2) визуального представления (CTableView) таблицы в список bool TableModelAdd(CTable *table_model,const int table_id,const string source); CTableView *TableViewAdd(CTable *table_model,const string source); //--- Обновляет указанный столбец указанной таблицы bool ColumnUpdate(const string source, CTable *table_model, const uint table, const uint col, const bool cells_redraw); public: //--- Возвращает (1) модель, (2) объект визуального представления таблицы, (3) тип объекта CTable *GetTable(const uint index) { return this.m_list_table_model.GetNodeAtIndex(index); } CTableView *GetTableView(const uint index) { return this.GetAttachedElementAt(index); } //--- Создание таблицы на основании переданных данных template CTableView *TableCreate(T &row_data[][],const string &column_names[],const int table_id=WRONG_VALUE); CTableView *TableCreate(const uint num_rows, const uint num_columns,const int table_id=WRONG_VALUE); CTableView *TableCreate(const matrix &row_data,const string &column_names[],const int table_id=WRONG_VALUE); CTableView *TableCreate(CList &row_data,const string &column_names[],const int table_id=WRONG_VALUE); //--- Возвращает (1) строковое значение указанной ячейки (Model), указанную (2) строку, (3) ячейку таблицы (View) string CellValueAt(const uint table, const uint row, const uint col); CTableRowView *GetRowView(const uint table, const uint index); CTableCellView *GetCellView(const uint table, const uint row, const uint col); //--- Устанавливает (1) значение, (2) точность, (3) флаги отображения времени, (4) флаг отображения имён цветов в указанную ячейку (Model + View) template void CellSetValue(const uint table, const uint row, const uint col, const T value, const bool chart_redraw); void CellSetDigits(const uint table, const uint row, const uint col, const int digits, const bool chart_redraw); void CellSetTimeFlags(const uint table, const uint row, const uint col, const uint flags, const bool chart_redraw); void CellSetColorNamesFlag(const uint table, const uint row, const uint col, const bool flag, const bool chart_redraw); //--- Устанавливает цвет переднего плана в указанную ячейку (View) void CellSetForeColor(const uint table, const uint row, const uint col, const color clr, const bool chart_redraw); //--- (1) Устанавливает, (2) возвращает точку привязки текста в указанной ячейке (View) void CellSetTextAnchor(const uint table, const uint row, const uint col, const ENUM_ANCHOR_POINT anchor,const bool cell_redraw,const bool chart_redraw); ENUM_ANCHOR_POINT CellTextAnchor(const uint table, const uint row, const uint col); //--- Устанавливает (1) точность, (2) флаги отображения времени, (3) флаг отображения имён цветов, (4) точку привязки текста, (5) тип данных в указанном столбце (View) void ColumnSetDigits(const uint table, const uint col, const int digits, const bool cells_redraw, const bool chart_redraw); void ColumnSetTimeFlags(const uint table, const uint col, const uint flags, const bool cells_redraw, const bool chart_redraw); void ColumnSetColorNamesFlag(const uint table, const uint col, const bool flag, const bool cells_redraw, const bool chart_redraw); void ColumnSetTextAnchor(const uint table, const uint col, const ENUM_ANCHOR_POINT anchor, const bool cells_redraw, const bool chart_redraw); void ColumnSetDatatype(const uint table, const uint col, const ENUM_DATATYPE type, const bool cells_redraw, const bool chart_redraw); //--- Тип объекта virtual int Type(void) const { return(ELEMENT_TYPE_TABLE_CONTROL_VIEW); } //--- Конструкторы/деструктор CTableControl(void) { this.m_list_table_model.Clear(); } CTableControl(const string object_name, const long chart_id, const int wnd, const int x, const int y, const int w, const int h); ~CTableControl(void) {} }; //+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ CTableControl::CTableControl(const string object_name,const long chart_id,const int wnd,const int x,const int y,const int w,const int h) : CPanel(object_name,"",chart_id,wnd,x,y,w,h) { this.m_list_table_model.Clear(); this.SetName("Table Control"); } //+------------------------------------------------------------------+ //| Добавляет объект модели таблицы (CTable) в список | //+------------------------------------------------------------------+ bool CTableControl::TableModelAdd(CTable *table_model,const int table_id,const string source) { //--- Проверяем объект модели таблицы if(table_model==NULL) { ::PrintFormat("%s::%s: Error. Failed to create Table Model object",source,__FUNCTION__); return false; } //--- Устанавливаем в модель таблицы идентификатор - либо по размеру списка, либо заданный table_model.SetID(table_id<0 ? this.m_list_table_model.Total() : table_id); //--- Если модель таблицы с установленным идентификатором есть в списке - сообщаем об этом, удаляем объект и возвращаем false this.m_list_table_model.Sort(0); if(this.m_list_table_model.Search(table_model)!=NULL) { ::PrintFormat("%s::%s: Error: Table Model object with ID %d already exists in the list",source,__FUNCTION__,table_id); delete table_model; return false; } //--- Если модель таблицы не добавлена в список - сообщаем об этом, удаляем объект и возвращаем false if(this.m_list_table_model.Add(table_model)<0) { ::PrintFormat("%s::%s: Error. Failed to add Table Model object to list",source,__FUNCTION__); delete table_model; return false; } //--- Всё успешно return true; } //+------------------------------------------------------------------+ //| Создаёт новый и добавляет в список объект | //| визуального представления таблицы (CTableView) | //+------------------------------------------------------------------+ CTableView *CTableControl::TableViewAdd(CTable *table_model,const string source) { //--- Проверяем объект модели таблицы if(table_model==NULL) { ::PrintFormat("%s::%s: Error. An invalid Table Model object was passed",source,__FUNCTION__); return NULL; } //--- Создаём новый элемент - визуальное представление таблицы, прикреплённый к панели CTableView *table_view=this.InsertNewElement(ELEMENT_TYPE_TABLE_VIEW,"","TableView"+(string)table_model.ID(),1,1,this.Width()-2,this.Height()-2); if(table_view==NULL) { ::PrintFormat("%s::%s: Error. Failed to create Table View object",source,__FUNCTION__); return NULL; } //--- Графическому элементу "Таблица" (View) назначаем объект таблицы (Model) и его идентификатор table_view.TableObjectAssign(table_model); table_view.SetID(table_model.ID()); return table_view; } //+-------------------------------------------------------------------+ //| Создаёт таблицу с указанием массива таблицы и массива заголовков. | //| Определяет количество и наименования колонок согласно column_names| //| Количество строк определены размером массива данных row_data, | //| который используется и для заполнения таблицы | //+-------------------------------------------------------------------+ template CTableView *CTableControl::TableCreate(T &row_data[][],const string &column_names[],const int table_id=WRONG_VALUE) { //--- Создаём объект таблицы по указанным параметрам CTable *table_model=new CTable(row_data,column_names); //--- Если есть ошибки при создании или добавлении таблицы в список - возвращаем NULL if(!this.TableModelAdd(table_model,table_id,__FUNCTION__)) return NULL; //--- Создаём и возвращаем таблицу return this.TableViewAdd(table_model,__FUNCTION__); } //+------------------------------------------------------------------+ //| Создаёт таблицу с определением количества колонок и строк. | //| Колонки будут иметь Excel-наименования "A", "B", "C" и т.д. | //+------------------------------------------------------------------+ CTableView *CTableControl::TableCreate(const uint num_rows,const uint num_columns,const int table_id=WRONG_VALUE) { CTable *table_model=new CTable(num_rows,num_columns); //--- Если есть ошибки при создании или добавлении таблицы в список - возвращаем NULL if(!this.TableModelAdd(table_model,table_id,__FUNCTION__)) return NULL; //--- Создаём и возвращаем таблицу return this.TableViewAdd(table_model,__FUNCTION__); } //+------------------------------------------------------------------+ //| Создаёт таблицу с инициализацией колонок согласно column_names | //| Количество строк определены параметром row_data, с типом matrix | //+------------------------------------------------------------------+ CTableView *CTableControl::TableCreate(const matrix &row_data,const string &column_names[],const int table_id=WRONG_VALUE) { CTable *table_model=new CTable(row_data,column_names); //--- Если есть ошибки при создании или добавлении таблицы в список - возвращаем NULL if(!this.TableModelAdd(table_model,table_id,__FUNCTION__)) return NULL; //--- Создаём и возвращаем таблицу return this.TableViewAdd(table_model,__FUNCTION__); } //+------------------------------------------------------------------+ //| Создаёт таблицу с указанием массива таблицы на основе | //| списка row_data, содержащего объекты с данными полей структуры. | //| Определяет количество и наименования колонок согласно количеству | //| наименований столбцов в массиве column_names | //+------------------------------------------------------------------+ CTableView *CTableControl::TableCreate(CList &row_data,const string &column_names[],const int table_id=WRONG_VALUE) { CTableByParam *table_model=new CTableByParam(row_data,column_names); //--- Если есть ошибки при создании или добавлении таблицы в список - возвращаем NULL if(!this.TableModelAdd(table_model,table_id,__FUNCTION__)) return NULL; //--- Создаём и возвращаем таблицу return this.TableViewAdd(table_model,__FUNCTION__); } //+------------------------------------------------------------------+ //| Устанавливает значение в указанную ячейку (Model + View) | //+------------------------------------------------------------------+ template void CTableControl::CellSetValue(const uint table,const uint row,const uint col,const T value,const bool chart_redraw) { //--- Получаем модель таблицы CTable *table_model=this.GetTable(table); if(table_model==NULL) return; //--- Из модели таблицы получаем модель ячейки CTableCell *cell_model=table_model.GetCell(row,col); if(cell_model==NULL) return; //--- Получаем объект визуального представления ячейки CTableCellView *cell_view=this.GetCellView(table,row,col); if(cell_view==NULL) return; //--- Сравниваем установленное в ячейке значение с переданным bool equal=false; ENUM_DATATYPE datatype=cell_model.Datatype(); switch(datatype) { case TYPE_LONG : case TYPE_DATETIME: case TYPE_COLOR : equal=(cell_model.ValueL()==value); break; case TYPE_DOUBLE : equal=(::NormalizeDouble(cell_model.ValueD()-value,cell_model.Digits())==0); break; //---TYPE_STRING default : equal=(::StringCompare(cell_model.ValueS(),(string)value)==0); break; } //--- Если значения равны - уходим if(equal) return; //--- В модель ячейки устанавливаем новое значение; //--- в объект визуального представления ячейки вписываем значение из модели ячейки //--- Перерисовываем ячейку с флагом обновления графика table_model.CellSetValue(row,col,value); cell_view.SetText(cell_model.Value()); cell_view.Draw(chart_redraw); } //+------------------------------------------------------------------+ //| Устанавливает точность в указанную ячейку (Model + View) | //+------------------------------------------------------------------+ void CTableControl::CellSetDigits(const uint table,const uint row,const uint col,const int digits,const bool chart_redraw) { //--- Получаем модель таблицы CTable *table_model=this.GetTable(table); if(table_model==NULL) return; //--- Из модели таблицы получаем модель ячейки CTableCell *cell_model=table_model.GetCell(row,col); if(cell_model==NULL || cell_model.Digits()==digits) return; //--- Получаем объект визуального представления ячейки CTableCellView *cell_view=this.GetCellView(table,row,col); if(cell_view==NULL) return; //--- В модель ячейки устанавливаем новое значение точности; //--- в объект визуального представления ячейки вписываем значение из модели ячейки //--- Перерисовываем ячейку с флагом обновления графика table_model.CellSetDigits(row,col,digits); cell_view.SetText(cell_model.Value()); cell_view.Draw(chart_redraw); } //+------------------------------------------------------------------+ //| Устанавливает флаги отображения времени | //| в указанную ячейку (Model + View) | //+------------------------------------------------------------------+ void CTableControl::CellSetTimeFlags(const uint table,const uint row,const uint col,const uint flags,const bool chart_redraw) { //--- Получаем модель таблицы CTable *table_model=this.GetTable(table); if(table_model==NULL) return; //--- Из модели таблицы получаем модель ячейки CTableCell *cell_model=table_model.GetCell(row,col); if(cell_model==NULL || cell_model.DatetimeFlags()==flags) return; //--- Получаем объект визуального представления ячейки CTableCellView *cell_view=this.GetCellView(table,row,col); if(cell_view==NULL) return; //--- В модель ячейки устанавливаем новое значение флагов отображения времени; //--- в объект визуального представления ячейки вписываем значение из модели ячейки //--- Перерисовываем ячейку с флагом обновления графика table_model.CellSetTimeFlags(row,col,flags); cell_view.SetText(cell_model.Value()); cell_view.Draw(chart_redraw); } //+------------------------------------------------------------------+ //| Устанавливает флаг отображения имён цветов | //| в указанную ячейку (Model + View) | //+------------------------------------------------------------------+ void CTableControl::CellSetColorNamesFlag(const uint table,const uint row,const uint col,const bool flag,const bool chart_redraw) { //--- Получаем модель таблицы CTable *table_model=this.GetTable(table); if(table_model==NULL) return; //--- Из модели таблицы получаем модель ячейки CTableCell *cell_model=table_model.GetCell(row,col); if(cell_model==NULL || cell_model.ColorNameFlag()==flag) return; //--- Получаем объект визуального представления ячейки CTableCellView *cell_view=this.GetCellView(table,row,col); if(cell_view==NULL) return; //--- В модель ячейки устанавливаем новое значение флага отображения имён цветов; //--- в объект визуального представления ячейки вписываем значение из модели ячейки //--- Перерисовываем ячейку с флагом обновления графика table_model.CellSetColorNamesFlag(row,col,flag); cell_view.SetText(cell_model.Value()); cell_view.Draw(chart_redraw); } //+------------------------------------------------------------------+ //| Устанавливает цвет переднего плана в указанную ячейку (View) | //+------------------------------------------------------------------+ void CTableControl::CellSetForeColor(const uint table,const uint row,const uint col,const color clr,const bool chart_redraw) { //--- Получаем объект визуального представления ячейки CTableCellView *cell_view=this.GetCellView(table,row,col); if(cell_view==NULL) return; //--- В объект визуального представления ячейки устанавливаем цвет фона ячейки //--- Перерисовываем ячейку с флагом обновления графика cell_view.SetForeColor(clr); cell_view.Draw(chart_redraw); } //+------------------------------------------------------------------+ //| Устанавливает точку привязки текста в указанную ячейку (View) | //+------------------------------------------------------------------+ void CTableControl::CellSetTextAnchor(const uint table,const uint row,const uint col,const ENUM_ANCHOR_POINT anchor,const bool cell_redraw,const bool chart_redraw) { //--- Получаем объект визуального представления ячейки CTableCellView *cell_view=this.GetCellView(table,row,col); if(cell_view==NULL) return; //--- В объект визуального представления ячейки устанавливаем точку привязки текста //--- Перерисовываем ячейку с флагом обновления графика cell_view.SetTextAnchor(anchor,cell_redraw,chart_redraw); } //+------------------------------------------------------------------+ //| Возвращает точку привязки текста в указанной ячейке (View) | //+------------------------------------------------------------------+ ENUM_ANCHOR_POINT CTableControl::CellTextAnchor(const uint table,const uint row,const uint col) { //--- Получаем объект визуального представления ячейки CTableCellView *cell_view=this.GetCellView(table,row,col); if(cell_view==NULL) return ANCHOR_LEFT_UPPER; //--- Возвращаем точку привязки текста return((ENUM_ANCHOR_POINT)cell_view.TextAnchor()); } //+------------------------------------------------------------------+ //| Обновляет указанный столбец указанной таблицы | //+------------------------------------------------------------------+ bool CTableControl::ColumnUpdate(const string source,CTable *table_model,const uint table,const uint col,const bool cells_redraw) { //--- Проверяем модель таблицы if(::CheckPointer(table_model)==POINTER_INVALID) { ::PrintFormat("%s::%s: Error. Invalid table model pointer passed",source,__FUNCTION__); return false; } //--- Получаем визуальное представление таблицы CTableView *table_view=this.GetTableView(table); if(table_view==NULL) { ::PrintFormat("%s::%s: Error. Failed to get CTableView object",source,__FUNCTION__); return false; } //--- В цикле по строкам визуального представления таблицы int total=table_view.RowsTotal(); for(int i=0;i