8428 líneas
474 KiB
MQL5
8428 líneas
474 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| 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; i<num; i++)
|
||
|
|
{
|
||
|
|
//--- Читаем и проверяем маркер начала данных объекта - 0xFFFFFFFFFFFFFFFF
|
||
|
|
if(::FileReadLong(file_handle)!=MARKER_START_DATA)
|
||
|
|
return false;
|
||
|
|
//--- Читаем тип объекта
|
||
|
|
this.m_element_type=(ENUM_ELEMENT_TYPE)::FileReadInteger(file_handle,INT_VALUE);
|
||
|
|
node=this.CreateElement();
|
||
|
|
if(node==NULL)
|
||
|
|
return false;
|
||
|
|
this.Add(node);
|
||
|
|
//--- Сейчас файловый указатель смещён относительно начала маркера объекта на 12 байт (8 - маркер, 4 - тип)
|
||
|
|
//--- Поставим указатель на начало данных объекта и загрузим свойства объекта из файла методом Load() элемента node.
|
||
|
|
if(!::FileSeek(file_handle,-12,SEEK_CUR))
|
||
|
|
return false;
|
||
|
|
result &=node.Load(file_handle);
|
||
|
|
}
|
||
|
|
//--- Результат
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Метод создания элемента списка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CObject *CListElm::CreateElement(void)
|
||
|
|
{
|
||
|
|
//--- В зависимости от типа объекта в m_element_type, создаём новый объект
|
||
|
|
switch(this.m_element_type)
|
||
|
|
{
|
||
|
|
case ELEMENT_TYPE_BASE : return new CBaseObj(); // Базовый объект графических элементов
|
||
|
|
case ELEMENT_TYPE_COLOR : return new CColor(); // Объект цвета
|
||
|
|
case ELEMENT_TYPE_COLORS_ELEMENT : return new CColorElement(); // Объект цветов элемента графического объекта
|
||
|
|
case ELEMENT_TYPE_RECTANGLE_AREA : return new CBound(); // Прямоугольная область элемента
|
||
|
|
case ELEMENT_TYPE_IMAGE_PAINTER : return new CImagePainter(); // Объект для рисования изображений
|
||
|
|
case ELEMENT_TYPE_CANVAS_BASE : return new CCanvasBase(); // Базовый объект холста графических элементов
|
||
|
|
case ELEMENT_TYPE_ELEMENT_BASE : return new CElementBase(); // Базовый объект графических элементов
|
||
|
|
case ELEMENT_TYPE_HINT : return new CVisualHint(); // Подсказка
|
||
|
|
case ELEMENT_TYPE_LABEL : return new CLabel(); // Текстовая метка
|
||
|
|
case ELEMENT_TYPE_BUTTON : return new CButton(); // Простая кнопка
|
||
|
|
case ELEMENT_TYPE_BUTTON_TRIGGERED : return new CButtonTriggered(); // Двухпозиционная кнопка
|
||
|
|
case ELEMENT_TYPE_BUTTON_ARROW_UP : return new CButtonArrowUp(); // Кнопка со стрелкой вверх
|
||
|
|
case ELEMENT_TYPE_BUTTON_ARROW_DOWN : return new CButtonArrowDown(); // Кнопка со стрелкой вниз
|
||
|
|
case ELEMENT_TYPE_BUTTON_ARROW_LEFT : return new CButtonArrowLeft(); // Кнопка со стрелкой влево
|
||
|
|
case ELEMENT_TYPE_BUTTON_ARROW_RIGHT : return new CButtonArrowRight(); // Кнопка со стрелкой вправо
|
||
|
|
case ELEMENT_TYPE_CHECKBOX : return new CCheckBox(); // Элемент управления CheckBox
|
||
|
|
case ELEMENT_TYPE_RADIOBUTTON : return new CRadioButton(); // Элемент управления RadioButton
|
||
|
|
case ELEMENT_TYPE_TABLE_CELL_VIEW : return new CTableCellView(); // Ячейка таблицы (View)
|
||
|
|
case ELEMENT_TYPE_TABLE_ROW_VIEW : return new CTableRowView(); // Строка таблицы (View)
|
||
|
|
case ELEMENT_TYPE_TABLE_COLUMN_CAPTION_VIEW : return new CColumnCaptionView(); // Заголовок столбца таблицы (View)
|
||
|
|
case ELEMENT_TYPE_TABLE_HEADER_VIEW : return new CTableHeaderView(); // Заголовок таблицы (View)
|
||
|
|
case ELEMENT_TYPE_TABLE_VIEW : return new CTableView(); // Таблица (View)
|
||
|
|
case ELEMENT_TYPE_PANEL : return new CPanel(); // Элемент управления Panel
|
||
|
|
case ELEMENT_TYPE_GROUPBOX : return new CGroupBox(); // Элемент управления GroupBox
|
||
|
|
case ELEMENT_TYPE_CONTAINER : return new CContainer(); // Элемент управления GroupBox
|
||
|
|
default : return NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс рисования изображений |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CImagePainter : public CBaseObj
|
||
|
|
{
|
||
|
|
protected:
|
||
|
|
CCanvas *m_canvas; // Указатель на канвас, где рисуем
|
||
|
|
CBound m_bound; // Координаты и границы изображения
|
||
|
|
uchar m_alpha; // Прозрачность
|
||
|
|
|
||
|
|
//--- Проверяет валидность холста и корректность размеров
|
||
|
|
bool CheckBound(const string source);
|
||
|
|
|
||
|
|
public:
|
||
|
|
//--- (1) Назначает канвас для рисования, (2) устанавливает, (3) возвращает прозрачность
|
||
|
|
void CanvasAssign(CCanvas *canvas) { this.m_canvas=canvas; }
|
||
|
|
void SetAlpha(const uchar value) { this.m_alpha=value; }
|
||
|
|
uchar Alpha(void) const { return this.m_alpha; }
|
||
|
|
|
||
|
|
//--- (1) Устанавливает координаты, (2) изменяет размеры области
|
||
|
|
void SetXY(const int x,const int y) { this.m_bound.SetXY(x,y); }
|
||
|
|
void SetSize(const int w,const int h) { this.m_bound.Resize(w,h); }
|
||
|
|
//--- Устанавливает координаты и размеры области
|
||
|
|
void SetBound(const int x,const int y,const int w,const int h)
|
||
|
|
{
|
||
|
|
this.SetXY(x,y);
|
||
|
|
this.SetSize(w,h);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Возвращает границы и размеры рисунка
|
||
|
|
int X(void) const { return this.m_bound.X(); }
|
||
|
|
int Y(void) const { return this.m_bound.Y(); }
|
||
|
|
int Right(void) const { return this.m_bound.Right(); }
|
||
|
|
int Bottom(void) const { return this.m_bound.Bottom(); }
|
||
|
|
int Width(void) const { return this.m_bound.Width(); }
|
||
|
|
int Height(void) const { return this.m_bound.Height(); }
|
||
|
|
|
||
|
|
//--- Очищает область
|
||
|
|
bool Clear(const int x,const int y,const int w,const int h,const bool update=true);
|
||
|
|
//--- Рисует закрашенную стрелку (1) вверх, (2) вниз, (3) влево, (4) вправо
|
||
|
|
bool ArrowUp(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
bool ArrowDown(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
bool ArrowLeft(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
bool ArrowRight(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
|
||
|
|
//--- Рисует (1) горизонтальную 17х7, (2) вертикальную 7х17 двойную стрелку
|
||
|
|
bool ArrowHorz(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
bool ArrowVert(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
|
||
|
|
//--- Рисует диагональную (1) сверху-слева --- вниз-вправо, (2) снизу-слева --- вверх-вправо 17х17 двойную стрелку
|
||
|
|
bool ArrowNWSE(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
bool ArrowNESW(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
|
||
|
|
//--- Рисует стрелку смещения 18x18 по (1) горизонтали, (2) вертикали
|
||
|
|
bool ArrowShiftHorz(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
bool ArrowShiftVert(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
|
||
|
|
//--- Рисует (1) отмеченный, (2) неотмеченный CheckBox
|
||
|
|
bool CheckedBox(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
bool UncheckedBox(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
|
||
|
|
//--- Рисует (1) отмеченный, (2) неотмеченный RadioButton
|
||
|
|
bool CheckedRadioButton(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
bool UncheckedRadioButton(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true);
|
||
|
|
|
||
|
|
//--- Рисует рамку группы элементов
|
||
|
|
bool FrameGroupElements(const int x,const int y,const int w,const int h,const string text,
|
||
|
|
const color clr_text,const color clr_dark,const color clr_light,
|
||
|
|
const uchar alpha,const bool update=true);
|
||
|
|
|
||
|
|
//--- Виртуальные методы (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_IMAGE_PAINTER); }
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
CImagePainter(void) : m_canvas(NULL) { this.SetBound(1,1,DEF_BUTTON_H-2,DEF_BUTTON_H-2); this.SetName("Image Painter"); }
|
||
|
|
CImagePainter(CCanvas *canvas) : m_canvas(canvas) { this.SetBound(1,1,DEF_BUTTON_H-2,DEF_BUTTON_H-2); this.SetName("Image Painter"); }
|
||
|
|
CImagePainter(CCanvas *canvas,const int id,const string name) : m_canvas(canvas)
|
||
|
|
{
|
||
|
|
this.m_id=id;
|
||
|
|
this.SetName(name);
|
||
|
|
this.SetBound(1,1,DEF_BUTTON_H-2,DEF_BUTTON_H-2);
|
||
|
|
}
|
||
|
|
CImagePainter(CCanvas *canvas,const int id,const int dx,const int dy,const int w,const int h,const string name) : m_canvas(canvas)
|
||
|
|
{
|
||
|
|
this.m_id=id;
|
||
|
|
this.SetName(name);
|
||
|
|
this.SetBound(dx,dy,w,h);
|
||
|
|
}
|
||
|
|
~CImagePainter(void) {}
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Сравнение двух объектов |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CImagePainter::Compare(const CObject *node,const int mode=0) const
|
||
|
|
{
|
||
|
|
if(node==NULL)
|
||
|
|
return -1;
|
||
|
|
const CImagePainter *obj=node;
|
||
|
|
switch(mode)
|
||
|
|
{
|
||
|
|
case ELEMENT_SORT_BY_NAME : return(this.Name() >obj.Name() ? 1 : this.Name() <obj.Name() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_ALPHA_FG :
|
||
|
|
case ELEMENT_SORT_BY_ALPHA_BG : return(this.Alpha() >obj.Alpha() ? 1 : this.Alpha() <obj.Alpha() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_X : return(this.X() >obj.X() ? 1 : this.X() <obj.X() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_Y : return(this.Y() >obj.Y() ? 1 : this.Y() <obj.Y() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_WIDTH : return(this.Width() >obj.Width() ? 1 : this.Width() <obj.Width() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_HEIGHT : return(this.Height() >obj.Height() ? 1 : this.Height() <obj.Height() ? -1 : 0);
|
||
|
|
default : return(this.ID() >obj.ID() ? 1 : this.ID() <obj.ID() ? -1 : 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//|CImagePainter::Проверяет валидность холста и корректность размеров|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::CheckBound(const string source)
|
||
|
|
{
|
||
|
|
if(this.m_canvas==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. First you need to assign the canvas using the CanvasAssign() method",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if(this.Width()==0 || this.Height()==0)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s::%s Error: (w %d, h %d). First you need to set the area size using the SetSize() or SetImageBound() methods",source,__FUNCTION__,this.Width(),this.Height());
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Очищает область |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::Clear(const int x,const int y,const int w,const int h,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
//--- Очищаем прозрачным цветом всю область изображения
|
||
|
|
this.m_canvas.FillRectangle(x,y,x+w-1,y+h-1,clrNULL);
|
||
|
|
//--- Если указано - обновляем канвас
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует закрашенную стрелку вверх |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::ArrowUp(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Рассчитываем координаты углов стрелки внутри области изображения
|
||
|
|
int hw=(int)::floor(w/2); // Половина ширины
|
||
|
|
if(hw==0)
|
||
|
|
hw=1;
|
||
|
|
|
||
|
|
int x1 = x + 1; // X. Основание (левая точка)
|
||
|
|
int y1 = y + h - 4; // Y. Левая точка основания
|
||
|
|
int x2 = x1 + hw; // X. Вершина (центральная верхняя точка)
|
||
|
|
int y2 = y + 3; // Y. Вершина (верхняя точка)
|
||
|
|
int x3 = x1 + w - 1; // X. Основание (правая точка)
|
||
|
|
int y3 = y1; // Y. Основание (правая точка)
|
||
|
|
|
||
|
|
//--- Рисуем треугольник
|
||
|
|
this.m_canvas.FillTriangle(x1, y1, x2, y2, x3, y3, ::ColorToARGB(clr, alpha));
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует закрашенную стрелку вниз |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::ArrowDown(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Рассчитываем координаты углов стрелки внутри области изображения
|
||
|
|
int hw=(int)::floor(w/2); // Половина ширины
|
||
|
|
if(hw==0)
|
||
|
|
hw=1;
|
||
|
|
|
||
|
|
int x1=x+1; // X. Основание (левая точка)
|
||
|
|
int y1=y+4; // Y. Левая точка основания
|
||
|
|
int x2=x1+hw; // X. Вершина (центральная нижняя точка)
|
||
|
|
int y2=y+h-3; // Y. Вершина (нижняя точка)
|
||
|
|
int x3=x1+w-1; // X. Основание (правая точка)
|
||
|
|
int y3=y1; // Y. Основание (правая точка)
|
||
|
|
|
||
|
|
//--- Рисуем треугольник
|
||
|
|
this.m_canvas.FillTriangle(x1, y1, x2, y2, x3, y3, ::ColorToARGB(clr, alpha));
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует закрашенную стрелку влево |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::ArrowLeft(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Рассчитываем координаты углов стрелки внутри области изображения
|
||
|
|
int hh=(int)::floor(h/2); // Половина высоты
|
||
|
|
if(hh==0)
|
||
|
|
hh=1;
|
||
|
|
|
||
|
|
int x1=x+w-4; // X. Основание (правая сторона)
|
||
|
|
int y1=y+1; // Y. Верхний угол основания
|
||
|
|
int x2=x+3; // X. Вершина (левая центральная точка)
|
||
|
|
int y2=y1+hh; // Y. Центральная точка (вершина)
|
||
|
|
int x3=x1; // X. Нижний угол основания
|
||
|
|
int y3=y1+h-1; // Y. Нижний угол основания
|
||
|
|
|
||
|
|
//--- Рисуем треугольник
|
||
|
|
this.m_canvas.FillTriangle(x1, y1, x2, y2, x3, y3, ::ColorToARGB(clr, alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует закрашенную стрелку вправо |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::ArrowRight(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Рассчитываем координаты углов стрелки внутри области изображения
|
||
|
|
int hh=(int)::floor(h/2); // Половина высоты
|
||
|
|
if(hh==0)
|
||
|
|
hh=1;
|
||
|
|
|
||
|
|
int x1=x+4; // X. Основание треугольника (левая сторона)
|
||
|
|
int y1=y+1; // Y. Верхний угол основания
|
||
|
|
int x2=x+w-3; // X. Вершина (правая центральная точка)
|
||
|
|
int y2=y1+hh; // Y. Центральная точка (вершина)
|
||
|
|
int x3=x1; // X. Нижний угол основания
|
||
|
|
int y3=y1+h-1; // Y. Нижний угол основания
|
||
|
|
|
||
|
|
//--- Рисуем треугольник
|
||
|
|
this.m_canvas.FillTriangle(x1, y1, x2, y2, x3, y3, ::ColorToARGB(clr, alpha));
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует горизонтальную 17х7 двойную стрелку |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::ArrowHorz(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Координаты фигуры
|
||
|
|
int arrx[15]={0, 3, 4, 4, 12, 12, 13, 16, 13, 12, 12, 4, 4, 3, 0};
|
||
|
|
int arry[15]={3, 0, 0, 2, 2, 0, 0, 3, 6, 6, 4, 4, 6, 6, 3};
|
||
|
|
|
||
|
|
//--- Рисуем белую подложку
|
||
|
|
this.m_canvas.Polyline(arrx,arry,::ColorToARGB(clrWhite,alpha));
|
||
|
|
|
||
|
|
//--- Рисуем линию стрелок
|
||
|
|
this.m_canvas.Line(1,3, 15,3,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем левый треугольник
|
||
|
|
this.m_canvas.Line(1,3, 1,3,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(2,2, 2,4,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(3,1, 3,5,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем правый треугольник
|
||
|
|
this.m_canvas.Line(13,1, 13,5,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(14,2, 14,4,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(15,3, 15,3,::ColorToARGB(clr,alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует вертикальную 7х17 двойную стрелку |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::ArrowVert(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Координаты фигуры
|
||
|
|
int arrx[15]={3, 6, 6, 4, 4, 6, 6, 3, 0, 0, 2, 2, 0, 0, 3};
|
||
|
|
int arry[15]={0, 3, 4, 4, 12, 12, 13, 16, 13, 12, 12, 4, 4, 3, 0};
|
||
|
|
|
||
|
|
//--- Рисуем белую подложку
|
||
|
|
this.m_canvas.Polyline(arrx,arry,::ColorToARGB(clrWhite,alpha));
|
||
|
|
|
||
|
|
//--- Рисуем линию стрелок
|
||
|
|
this.m_canvas.Line(3,1, 3,15,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем верхний треугольник
|
||
|
|
this.m_canvas.Line(3,1, 3,1,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(2,2, 4,2,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(1,3, 5,3,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем нижний треугольник
|
||
|
|
this.m_canvas.Line(1,13, 5,13,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(2,14, 4,14,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(3,15, 3,15,::ColorToARGB(clr,alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует стрелку 18х18 горизонтального смещения |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::ArrowShiftHorz(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Координаты фигуры
|
||
|
|
int arrx[25]={0, 3, 4, 4, 7, 7, 10, 10, 13, 13, 14, 17, 17, 14, 13, 13, 10, 10, 7, 7, 4, 4, 3, 0, 0};
|
||
|
|
int arry[25]={8, 5, 5, 7, 7, 0, 0, 7, 7, 5, 5, 8, 9, 12, 12, 10, 10, 17, 17, 10, 10, 12, 12, 9, 8};
|
||
|
|
|
||
|
|
//--- Рисуем белую подложку
|
||
|
|
this.m_canvas.Polyline(arrx,arry,::ColorToARGB(clrWhite,alpha));
|
||
|
|
|
||
|
|
//--- Рисуем линию стрелок
|
||
|
|
this.m_canvas.FillRectangle(1,8, 16,9,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем разделительную линию
|
||
|
|
this.m_canvas.FillRectangle(8,1, 9,16,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем левый треугольник
|
||
|
|
this.m_canvas.Line(2,7, 2,10,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(3,6, 3,11,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем правый треугольник
|
||
|
|
this.m_canvas.Line(14,6, 14,11,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(15,7, 15,10,::ColorToARGB(clr,alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует стрелку 18х18 вертикального смещения |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::ArrowShiftVert(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
///*
|
||
|
|
//--- Координаты фигуры
|
||
|
|
int arrx[25]={0, 7, 7, 5, 5, 8, 9, 12, 12, 10, 10, 17, 17, 10, 10, 12, 12, 9, 8, 5, 5, 7, 7, 0, 0};
|
||
|
|
int arry[25]={7, 7, 4, 4, 3, 0, 0, 3, 4, 4, 7, 7, 10, 10, 13, 13, 14, 17, 17, 14, 13, 13, 10, 10, 7};
|
||
|
|
|
||
|
|
//--- Рисуем белую подложку
|
||
|
|
this.m_canvas.Polyline(arrx,arry,::ColorToARGB(clrWhite,alpha));
|
||
|
|
|
||
|
|
//--- Рисуем разделительную линию
|
||
|
|
this.m_canvas.FillRectangle(1,8, 16,9,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем линию стрелок
|
||
|
|
this.m_canvas.FillRectangle(8,1, 9,16,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем верхний треугольник
|
||
|
|
this.m_canvas.Line(7,2, 10,2,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(6,3, 11,3,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем нижний треугольник
|
||
|
|
this.m_canvas.Line(6,14, 11,14,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(7,15, 10,15,::ColorToARGB(clr,alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
//*/
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует диагональную сверху-слева --- вниз-вправо |
|
||
|
|
//| 13х13 двойную стрелку (NorthWest-SouthEast) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::ArrowNWSE(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Координаты фигуры
|
||
|
|
int arrx[19]={0, 4, 5, 4, 4, 9, 10, 11, 12, 12, 8, 7, 8, 8, 3, 2, 1, 0, 0};
|
||
|
|
int arry[19]={0, 0, 1, 2, 3, 8, 8, 7, 8, 12, 12, 11, 10, 9, 4, 4, 5, 4, 0};
|
||
|
|
|
||
|
|
//--- Рисуем белую подложку
|
||
|
|
this.m_canvas.Polyline(arrx,arry,::ColorToARGB(clrWhite,alpha));
|
||
|
|
|
||
|
|
//--- Рисуем линию стрелок
|
||
|
|
this.m_canvas.Line(3,3, 9,9,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем верхний-левый треугольник
|
||
|
|
this.m_canvas.Line(1,1, 4,1,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(1,2, 3,2,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(1,3, 3,3,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(1,4, 1,4,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем нижний-правый треугольник
|
||
|
|
this.m_canvas.Line(11,8, 11, 8,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(9, 9, 11, 9,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(9,10, 11,10,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(8,11, 11,11,::ColorToARGB(clr,alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует диагональную снизу-слева --- вверх-вправо |
|
||
|
|
//| 13х13 двойную стрелку (NorthEast-SouthWest) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::ArrowNESW(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Координаты фигуры
|
||
|
|
int arrx[19]={ 0, 0, 1, 2, 3, 8, 8, 7, 8, 12, 12, 11, 10, 9, 4, 4, 5, 4, 0};
|
||
|
|
int arry[19]={12, 8, 7, 8, 8, 3, 2, 1, 0, 0, 4, 5, 4, 4, 9, 10, 11, 12, 12};
|
||
|
|
|
||
|
|
//--- Рисуем белую подложку
|
||
|
|
this.m_canvas.Polyline(arrx,arry,::ColorToARGB(clrWhite,alpha));
|
||
|
|
|
||
|
|
//--- Рисуем линию стрелок
|
||
|
|
this.m_canvas.Line(3,9, 9,3,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем нижний-левый треугольник
|
||
|
|
this.m_canvas.Line(1, 8, 1,8, ::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(1, 9, 3,9, ::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(1,10, 3,10,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(1,11, 4,11,::ColorToARGB(clr,alpha));
|
||
|
|
//--- Рисуем верхний-правый треугольник
|
||
|
|
this.m_canvas.Line(8, 1, 11,1,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(9, 2, 11,2,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(9, 3, 11,3,::ColorToARGB(clr,alpha));
|
||
|
|
this.m_canvas.Line(11,4, 11,4,::ColorToARGB(clr,alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует отмеченный CheckBox |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::CheckedBox(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Координаты прямоугольника
|
||
|
|
int x1=x+1; // Левый верхний угол, X
|
||
|
|
int y1=y+1; // Левый верхний угол, Y
|
||
|
|
int x2=x+w-2; // Правый нижний угол, X
|
||
|
|
int y2=y+h-2; // Правый нижний угол, Y
|
||
|
|
|
||
|
|
//--- Рисуем прямоугольник
|
||
|
|
this.m_canvas.Rectangle(x1, y1, x2, y2, ::ColorToARGB(clr, alpha));
|
||
|
|
|
||
|
|
//--- Координаты "галочки"
|
||
|
|
int arrx[3], arry[3];
|
||
|
|
|
||
|
|
arrx[0]=x1+(x2-x1)/4; // X. Левая точка
|
||
|
|
arrx[1]=x1+w/3; // X. Центральная точка
|
||
|
|
arrx[2]=x2-(x2-x1)/4; // X. Правая точка
|
||
|
|
|
||
|
|
arry[0]=y1+1+(y2-y1)/2; // Y. Левая точка
|
||
|
|
arry[1]=y2-(y2-y1)/3; // Y. Центральная точка
|
||
|
|
arry[2]=y1+(y2-y1)/3; // Y. Правая точка
|
||
|
|
|
||
|
|
//--- Рисуем "галочку" линией двойной толщины
|
||
|
|
this.m_canvas.Polyline(arrx, arry, ::ColorToARGB(clr, alpha));
|
||
|
|
arrx[0]++;
|
||
|
|
arrx[1]++;
|
||
|
|
arrx[2]++;
|
||
|
|
this.m_canvas.Polyline(arrx, arry, ::ColorToARGB(clr, alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует неотмеченный CheckBox |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::UncheckedBox(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Координаты прямоугольника
|
||
|
|
int x1=x+1; // Левый верхний угол, X
|
||
|
|
int y1=y+1; // Левый верхний угол, Y
|
||
|
|
int x2=x+w-2; // Правый нижний угол, X
|
||
|
|
int y2=y+h-2; // Правый нижний угол, Y
|
||
|
|
|
||
|
|
//--- Рисуем прямоугольник
|
||
|
|
this.m_canvas.Rectangle(x1, y1, x2, y2, ::ColorToARGB(clr, alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует отмеченный RadioButton |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::CheckedRadioButton(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Координаты и радиус окружности
|
||
|
|
int x1=x+1; // Левый верхний угол области окружности, X
|
||
|
|
int y1=y+1; // Левый верхний угол области окружности, Y
|
||
|
|
int x2=x+w-2; // Правый нижний угол области окружности, X
|
||
|
|
int y2=y+h-2; // Правый нижний угол области окружности, Y
|
||
|
|
|
||
|
|
//--- Координаты и радиус окружности
|
||
|
|
int d=::fmin(x2-x1,y2-y1); // Диаметр по меньшей стороне (ширина или высота)
|
||
|
|
int r=d/2; // Радиус
|
||
|
|
if(r<2)
|
||
|
|
r=2;
|
||
|
|
int cx=x1+r; // Координата X центра
|
||
|
|
int cy=y1+r; // Координата Y центра
|
||
|
|
|
||
|
|
//--- Рисуем окружность
|
||
|
|
this.m_canvas.CircleWu(cx, cy, r, ::ColorToARGB(clr, alpha));
|
||
|
|
|
||
|
|
//--- Радиус "метки"
|
||
|
|
r/=2;
|
||
|
|
if(r<1)
|
||
|
|
r=1;
|
||
|
|
//--- Рисуем метку
|
||
|
|
this.m_canvas.FillCircle(cx, cy, r, ::ColorToARGB(clr, alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CImagePainter::Рисует неотмеченный RadioButton |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::UncheckedRadioButton(const int x,const int y,const int w,const int h,const color clr,const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Координаты и радиус окружности
|
||
|
|
int x1=x+1; // Левый верхний угол области окружности, X
|
||
|
|
int y1=y+1; // Левый верхний угол области окружности, Y
|
||
|
|
int x2=x+w-2; // Правый нижний угол области окружности, X
|
||
|
|
int y2=y+h-2; // Правый нижний угол области окружности, Y
|
||
|
|
|
||
|
|
//--- Координаты и радиус окружности
|
||
|
|
int d=::fmin(x2-x1,y2-y1); // Диаметр по меньшей стороне (ширина или высота)
|
||
|
|
int r=d/2; // Радиус
|
||
|
|
int cx=x1+r; // Координата X центра
|
||
|
|
int cy=y1+r; // Координата Y центра
|
||
|
|
|
||
|
|
//--- Рисуем окружность
|
||
|
|
this.m_canvas.CircleWu(cx, cy, r, ::ColorToARGB(clr, alpha));
|
||
|
|
|
||
|
|
if(update)
|
||
|
|
this.m_canvas.Update(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Рисует рамку группы элементов |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CImagePainter::FrameGroupElements(const int x,const int y,const int w,const int h,const string text,
|
||
|
|
const color clr_text,const color clr_dark,const color clr_light,
|
||
|
|
const uchar alpha,const bool update=true)
|
||
|
|
{
|
||
|
|
//--- Если область изображения не валидна - возвращаем false
|
||
|
|
if(!this.CheckBound(__FUNCTION__))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Корректировка координаты Y
|
||
|
|
int tw=0, th=0;
|
||
|
|
if(text!="" && text!=NULL)
|
||
|
|
this.m_canvas.TextSize(text,tw,th);
|
||
|
|
int shift_v=int(th!=0 ? ::ceil(th/2) : 0);
|
||
|
|
|
||
|
|
//--- Координаты и размеры рамки
|
||
|
|
int x1=x; // Левый верхний угол области рамки, X
|
||
|
|
int y1=y+shift_v; // Левый верхний угол области рамки, Y
|
||
|
|
int x2=x+w-1; // Правый нижний угол области рамки, X
|
||
|
|
int y2=y+h-1; // Правый нижний угол области рамки, Y
|
||
|
|
|
||
|
|
//--- Рисуем левую-верхнюю часть рамки
|
||
|
|
int arrx[3], arry[3];
|
||
|
|
arrx[0]=arrx[1]=x1;
|
||
|
|
arrx[2]=x2-1;
|
||
|
|
arry[0]=y2;
|
||
|
|
arry[1]=arry[2]=y1;
|
||
|
|
this.m_canvas.Polyline(arrx, arry, ::ColorToARGB(clr_dark, alpha));
|
||
|
|
arrx[0]++;
|
||
|
|
arrx[1]++;
|
||
|
|
arry[1]++;
|
||
|
|
arry[2]++;
|
||
|
|
this.m_canvas.Polyline(arrx, arry, ::ColorToARGB(clr_light, alpha));
|
||
|
|
//--- Рисуем правую-нижнюю часть рамки
|
||
|
|
arrx[0]=arrx[1]=x2-1;
|
||
|
|
arrx[2]=x1+1;
|
||
|
|
arry[0]=y1;
|
||
|
|
arry[1]=arry[2]=y2-1;
|
||
|
|
this.m_canvas.Polyline(arrx, arry, ::ColorToARGB(clr_dark, alpha));
|
||
|
|
arrx[0]++;
|
||
|
|
arrx[1]++;
|
||
|
|
arry[1]++;
|
||
|
|
arry[2]++;
|
||
|
|
this.m_canvas.Polyline(arrx, arry, ::ColorToARGB(clr_light, alpha));
|
||
|
|
|
||
|
|
if(tw>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.Name() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_X : return(this.X() >obj.X() ? 1 : this.X() <obj.X() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_Y : return(this.Y() >obj.Y() ? 1 : this.Y() <obj.Y() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_WIDTH : return(this.Width() >obj.Width() ? 1 : this.Width() <obj.Width() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_HEIGHT : return(this.Height() >obj.Height() ? 1 : this.Height() <obj.Height() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_COLOR_BG : return(this.BackColor() >obj.BackColor() ? 1 : this.BackColor() <obj.BackColor() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_COLOR_FG : return(this.ForeColor() >obj.ForeColor() ? 1 : this.ForeColor() <obj.ForeColor() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_ALPHA_BG : return(this.AlphaBG() >obj.AlphaBG() ? 1 : this.AlphaBG() <obj.AlphaBG() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_ALPHA_FG : return(this.AlphaFG() >obj.AlphaFG() ? 1 : this.AlphaFG() <obj.AlphaFG() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_STATE : return(this.State() >obj.State() ? 1 : this.State() <obj.State() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_GROUP : return(this.Group() >obj.Group() ? 1 : this.Group() <obj.Group() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_ZORDER : return(this.ObjectZOrder() >obj.ObjectZOrder() ? 1 : this.ObjectZOrder() <obj.ObjectZOrder() ? -1 : 0);
|
||
|
|
default : return(this.ID() >obj.ID() ? 1 : this.ID() <obj.ID() ? -1 : 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Возвращает описание объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
string CElementBase::Description(void)
|
||
|
|
{
|
||
|
|
string nm=this.Name();
|
||
|
|
string name=(nm!="" ? ::StringFormat(" \"%s\"",nm) : nm);
|
||
|
|
string area=::StringFormat("x %d, y %d, w %d, h %d, right %d, bottom %d",this.X(),this.Y(),this.Width(),this.Height(),this.Right(),this.Bottom());
|
||
|
|
return ::StringFormat("%s%s (%s, %s): ID %d, Group %d, %s",ElementDescription((ENUM_ELEMENT_TYPE)this.Type()),name,this.NameBG(),this.NameFG(),this.ID(),this.Group(),area);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Устанавливает флаг возможности изменения размеров |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CElementBase::SetResizable(const bool flag)
|
||
|
|
{
|
||
|
|
//--- В родительский объект записываем флаг
|
||
|
|
CCanvasBase::SetResizable(flag);
|
||
|
|
//--- Если флаг передан как true - создаём для курсора четыре подсказки со стрелками,
|
||
|
|
if(flag)
|
||
|
|
this.AddHintsArrowed();
|
||
|
|
//--- иначе - удаляем подсказки со стрелками для курсора
|
||
|
|
else
|
||
|
|
this.DeleteHintsArrowed();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Возвращает указатель на подсказку по индексу |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CVisualHint *CElementBase::GetHintAt(const int index)
|
||
|
|
{
|
||
|
|
return this.m_list_hints.GetNodeAtIndex(index);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Возвращает указатель на подсказку по идентификатору|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CVisualHint *CElementBase::GetHint(const int id)
|
||
|
|
{
|
||
|
|
int total=this.m_list_hints.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
CVisualHint *obj=this.GetHintAt(i);
|
||
|
|
if(obj!=NULL && obj.ID()==id)
|
||
|
|
return obj;
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//|CElementBase:: Возвращает указатель на подсказку по наименованию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CVisualHint *CElementBase::GetHint(const string name)
|
||
|
|
{
|
||
|
|
int total=this.m_list_hints.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
CVisualHint *obj=this.GetHintAt(i);
|
||
|
|
if(obj!=NULL && obj.Name()==name)
|
||
|
|
return obj;
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Добавляет указанный объект-подсказку в список |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::AddHintToList(CVisualHint *obj)
|
||
|
|
{
|
||
|
|
//--- Если передан пустой указатель - сообщаем об этом и возвращаем false
|
||
|
|
if(obj==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Empty element passed",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
//--- Запоминаем метод сортировки списка
|
||
|
|
int sort_mode=this.m_list_hints.SortMode();
|
||
|
|
//--- Устанавливаем списку флаг сортировки по идентификатору
|
||
|
|
this.m_list_hints.Sort(ELEMENT_SORT_BY_ID);
|
||
|
|
//--- Если такого элемента нет в списке,
|
||
|
|
if(this.m_list_hints.Search(obj)==NULL)
|
||
|
|
{
|
||
|
|
//--- возвращаем списку изначальную сортировку и возвращаем результат его добавления в список
|
||
|
|
this.m_list_hints.Sort(sort_mode);
|
||
|
|
return(this.m_list_hints.Add(obj)>-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;i<this.m_list_hints.Total();i++)
|
||
|
|
{
|
||
|
|
//--- получаем указатель на очередной объект
|
||
|
|
CVisualHint *obj=this.GetHintAt(i);
|
||
|
|
if(obj==NULL)
|
||
|
|
continue;
|
||
|
|
//--- Если это искомый тип подсказки - запоминаем указатель,
|
||
|
|
if(obj.HintType()==type)
|
||
|
|
hint=obj;
|
||
|
|
//--- иначе - скрываем объект
|
||
|
|
else
|
||
|
|
obj.Hide(false);
|
||
|
|
}
|
||
|
|
//--- Если искомый объект найден и он скрыт
|
||
|
|
if(hint!=NULL && hint.IsHidden())
|
||
|
|
{
|
||
|
|
//--- помещаем объект в указанные координаты,
|
||
|
|
//--- рисуем внешний вид и переносим объект на передний план, делая его видимым
|
||
|
|
hint.Move(x,y);
|
||
|
|
hint.Draw(false);
|
||
|
|
hint.BringToTop(true);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Скрывает все подсказки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CElementBase::HideHintsAll(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- В цикле по списку объектов-подсказок
|
||
|
|
for(int i=0;i<this.m_list_hints.Total();i++)
|
||
|
|
{
|
||
|
|
//--- получаем очередной объект и скрываем его
|
||
|
|
CVisualHint *obj=this.GetHintAt(i);
|
||
|
|
if(obj!=NULL)
|
||
|
|
obj.Hide(false);
|
||
|
|
}
|
||
|
|
//--- Если указано, перерисовываем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Отображает курсор изменения размеров |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::ShowCursorHint(const ENUM_CURSOR_REGION edge,int x,int y)
|
||
|
|
{
|
||
|
|
CVisualHint *hint=NULL; // Указатель на подсказку
|
||
|
|
int hint_shift_x=0; // Смещение подсказки по X
|
||
|
|
int hint_shift_y=0; // Смещение подсказки по Y
|
||
|
|
|
||
|
|
//--- В зависимости от расположения курсора на границах элемента
|
||
|
|
//--- указываем смещения подсказки относительно координат курсора,
|
||
|
|
//--- отображаем на графике требуемую подсказку и получаем указатель на этот объект
|
||
|
|
switch(edge)
|
||
|
|
{
|
||
|
|
//--- Курсор на правой или левой границе - горизонтальная двойная стрелка
|
||
|
|
case CURSOR_REGION_RIGHT :
|
||
|
|
case CURSOR_REGION_LEFT :
|
||
|
|
hint_shift_x=1;
|
||
|
|
hint_shift_y=18;
|
||
|
|
this.ShowHintArrowed(HINT_TYPE_ARROW_HORZ,x+hint_shift_x,y+hint_shift_y);
|
||
|
|
hint=this.GetHint(DEF_HINT_NAME_HORZ);
|
||
|
|
break;
|
||
|
|
|
||
|
|
//--- Курсор на верхней или нижней границе - вертикальная двойная стрелка
|
||
|
|
case CURSOR_REGION_TOP :
|
||
|
|
case CURSOR_REGION_BOTTOM :
|
||
|
|
hint_shift_x=12;
|
||
|
|
hint_shift_y=4;
|
||
|
|
this.ShowHintArrowed(HINT_TYPE_ARROW_VERT,x+hint_shift_x,y+hint_shift_y);
|
||
|
|
hint=this.GetHint(DEF_HINT_NAME_VERT);
|
||
|
|
break;
|
||
|
|
|
||
|
|
//--- Курсор в левом верхнем или правом нижнем углу - диагональная двойная стрелка от лево-верх до право-низ
|
||
|
|
case CURSOR_REGION_LEFT_TOP :
|
||
|
|
case CURSOR_REGION_RIGHT_BOTTOM :
|
||
|
|
hint_shift_x=10;
|
||
|
|
hint_shift_y=2;
|
||
|
|
this.ShowHintArrowed(HINT_TYPE_ARROW_NWSE,x+hint_shift_x,y+hint_shift_y);
|
||
|
|
hint=this.GetHint(DEF_HINT_NAME_NWSE);
|
||
|
|
break;
|
||
|
|
|
||
|
|
//--- Курсор в левом нижнем или правом верхнем углу - диагональная двойная стрелка от лево-низ до право-верх
|
||
|
|
case CURSOR_REGION_LEFT_BOTTOM :
|
||
|
|
case CURSOR_REGION_RIGHT_TOP :
|
||
|
|
hint_shift_x=5;
|
||
|
|
hint_shift_y=12;
|
||
|
|
this.ShowHintArrowed(HINT_TYPE_ARROW_NESW,x+hint_shift_x,y+hint_shift_y);
|
||
|
|
hint=this.GetHint(DEF_HINT_NAME_NESW);
|
||
|
|
break;
|
||
|
|
|
||
|
|
//--- По умолчанию ничего не делаем
|
||
|
|
default: break;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Возвращаем результат корректировки положения подсказки относительно курсора
|
||
|
|
return(hint!=NULL ? hint.Move(x+hint_shift_x,y+hint_shift_y) : false);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Обработчик изменения размеров |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CElementBase::OnResizeZoneEvent(const int id,const long lparam,const double dparam,const string sparam)
|
||
|
|
{
|
||
|
|
int x=(int)lparam; // Координата X курсора
|
||
|
|
int y=(int)dparam; // Координата Y курсора
|
||
|
|
int shift_x=0; // Смещение подсказки по X
|
||
|
|
int shift_y=0; // Смещение подсказки по Y
|
||
|
|
|
||
|
|
//--- Получаем положение курсора относительно границ элемента и режим взаимодействия
|
||
|
|
ENUM_CURSOR_REGION edge=(this.ResizeRegion()==CURSOR_REGION_NONE ? this.CheckResizeZone(x,y) : this.ResizeRegion());
|
||
|
|
ENUM_RESIZE_ZONE_ACTION action=(ENUM_RESIZE_ZONE_ACTION)id;
|
||
|
|
|
||
|
|
//--- Если курсор за границами изменения размеров или только что наведён на зону взаимодействия
|
||
|
|
if(action==RESIZE_ZONE_ACTION_NONE || (action==RESIZE_ZONE_ACTION_HOVER && edge==CURSOR_REGION_NONE))
|
||
|
|
{
|
||
|
|
//--- отключаем режим изменения размеров и регион взаимодействия,
|
||
|
|
//--- скрываем все подсказки
|
||
|
|
this.SetResizeMode(false);
|
||
|
|
this.SetResizeRegion(CURSOR_REGION_NONE);
|
||
|
|
this.HideHintsAll(true);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Курсор на одной из границ изменения размеров
|
||
|
|
if(action==RESIZE_ZONE_ACTION_HOVER)
|
||
|
|
{
|
||
|
|
//--- Отображаем подсказку со стрелкой для региона взаимодействия
|
||
|
|
if(this.ShowCursorHint(edge,x,y))
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Начало изменения размеров
|
||
|
|
if(action==RESIZE_ZONE_ACTION_BEGIN)
|
||
|
|
{
|
||
|
|
//--- включаем режим изменения размеров и регион взаимодействия,
|
||
|
|
//--- отображаем соответствующую подсказку курсора
|
||
|
|
this.SetResizeMode(true);
|
||
|
|
this.SetResizeRegion(edge);
|
||
|
|
this.ShowCursorHint(edge,x,y);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Перетаскивание границы объекта для изменения размеров элемента
|
||
|
|
if(action==RESIZE_ZONE_ACTION_DRAG)
|
||
|
|
{
|
||
|
|
//--- Вызываем обработчик перетягивания границ объекта для изменения его размеров,
|
||
|
|
//--- отображаем соответствующую подсказку курсора
|
||
|
|
this.ResizeActionDragHandler(x,y);
|
||
|
|
this.ShowCursorHint(edge,x,y);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Обработчик перетаскивания граней и углов элемента |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CElementBase::ResizeActionDragHandler(const int x, const int y)
|
||
|
|
{
|
||
|
|
//--- Изменение размера за правую границу
|
||
|
|
if(this.ResizeRegion()==CURSOR_REGION_RIGHT)
|
||
|
|
this.ResizeZoneRightHandler(x,y);
|
||
|
|
//--- Изменение размера за нижнюю границу
|
||
|
|
if(this.ResizeRegion()==CURSOR_REGION_BOTTOM)
|
||
|
|
this.ResizeZoneBottomHandler(x,y);
|
||
|
|
//--- Изменение размера за левую границу
|
||
|
|
if(this.ResizeRegion()==CURSOR_REGION_LEFT)
|
||
|
|
this.ResizeZoneLeftHandler(x,y);
|
||
|
|
//--- Изменение размера за верхнюю границу
|
||
|
|
if(this.ResizeRegion()==CURSOR_REGION_TOP)
|
||
|
|
this.ResizeZoneTopHandler(x,y);
|
||
|
|
//--- Изменение размера за правый нижний угол
|
||
|
|
if(this.ResizeRegion()==CURSOR_REGION_RIGHT_BOTTOM)
|
||
|
|
this.ResizeZoneRightBottomHandler(x,y);
|
||
|
|
//--- Изменение размера за правый верхний угол
|
||
|
|
if(this.ResizeRegion()==CURSOR_REGION_RIGHT_TOP)
|
||
|
|
this.ResizeZoneRightTopHandler(x,y);
|
||
|
|
//--- Изменение размера за левый нижний угол
|
||
|
|
if(this.ResizeRegion()==CURSOR_REGION_LEFT_BOTTOM)
|
||
|
|
this.ResizeZoneLeftBottomHandler(x,y);
|
||
|
|
//--- Изменение размера за левый верхний угол
|
||
|
|
if(this.ResizeRegion()==CURSOR_REGION_LEFT_TOP)
|
||
|
|
this.ResizeZoneLeftTopHandler(x,y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Обработчик изменения размеров за правую грань |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::ResizeZoneRightHandler(const int x,const int y)
|
||
|
|
{
|
||
|
|
//--- Рассчитываем и устанавливаем новую ширину элемента
|
||
|
|
int width=::fmax(x-this.X()+1,DEF_PANEL_MIN_W);
|
||
|
|
if(!this.ResizeW(width))
|
||
|
|
return false;
|
||
|
|
//--- Получаем указатель на подсказку
|
||
|
|
CVisualHint *hint=this.GetHint(DEF_HINT_NAME_HORZ);
|
||
|
|
if(hint==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Смещаем подсказку на указанные величины относительно курсора
|
||
|
|
int shift_x=1;
|
||
|
|
int shift_y=18;
|
||
|
|
return hint.Move(x+shift_x,y+shift_y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Обработчик изменения размеров за нижнюю грань |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::ResizeZoneBottomHandler(const int x,const int y)
|
||
|
|
{
|
||
|
|
//--- Рассчитываем и устанавливаем новую высоту элемента
|
||
|
|
int height=::fmax(y-this.Y(),DEF_PANEL_MIN_H);
|
||
|
|
if(!this.ResizeH(height))
|
||
|
|
return false;
|
||
|
|
//--- Получаем указатель на подсказку
|
||
|
|
CVisualHint *hint=this.GetHint(DEF_HINT_NAME_VERT);
|
||
|
|
if(hint==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Смещаем подсказку на указанные величины относительно курсора
|
||
|
|
int shift_x=12;
|
||
|
|
int shift_y=4;
|
||
|
|
return hint.Move(x+shift_x,y+shift_y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Изменение размера за левую грань |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::ResizeZoneLeftHandler(const int x,const int y)
|
||
|
|
{
|
||
|
|
//--- Рассчитываем новые координату X и ширину элемента
|
||
|
|
int new_x=::fmin(x,this.Right()-DEF_PANEL_MIN_W+1);
|
||
|
|
int width=this.Right()-new_x+1;
|
||
|
|
//--- Устанавливаем новые координату X и ширину элемента
|
||
|
|
if(!this.MoveXYWidthResize(new_x,this.Y(),width,this.Height()))
|
||
|
|
return false;
|
||
|
|
//--- Получаем указатель на подсказку
|
||
|
|
CVisualHint *hint=this.GetHint(DEF_HINT_NAME_HORZ);
|
||
|
|
if(hint==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Смещаем подсказку на указанные величины относительно курсора
|
||
|
|
int shift_x=1;
|
||
|
|
int shift_y=18;
|
||
|
|
return hint.Move(x+shift_x,y+shift_y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Изменение размера за верхнюю грань |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::ResizeZoneTopHandler(const int x,const int y)
|
||
|
|
{
|
||
|
|
//--- Рассчитываем новые координату Y и высоту элемента
|
||
|
|
int new_y=::fmin(y,this.Bottom()-DEF_PANEL_MIN_H+1);
|
||
|
|
int height=this.Bottom()-new_y+1;
|
||
|
|
//--- Устанавливаем новые координату Y и высоту элемента
|
||
|
|
if(!this.MoveXYWidthResize(this.X(),new_y,this.Width(),height))
|
||
|
|
return false;
|
||
|
|
//--- Получаем указатель на подсказку
|
||
|
|
CVisualHint *hint=this.GetHint(DEF_HINT_NAME_VERT);
|
||
|
|
if(hint==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Смещаем подсказку на указанные величины относительно курсора
|
||
|
|
int shift_x=12;
|
||
|
|
int shift_y=4;
|
||
|
|
return hint.Move(x+shift_x,y+shift_y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Изменение размера за правый нижний угол |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::ResizeZoneRightBottomHandler(const int x,const int y)
|
||
|
|
{
|
||
|
|
//--- Рассчитываем и устанавливаем новые ширину и высоту элемента
|
||
|
|
int width =::fmax(x-this.X()+1, DEF_PANEL_MIN_W);
|
||
|
|
int height=::fmax(y-this.Y()+1, DEF_PANEL_MIN_H);
|
||
|
|
if(!this.Resize(width,height))
|
||
|
|
return false;
|
||
|
|
//--- Получаем указатель на подсказку
|
||
|
|
CVisualHint *hint=this.GetHint(DEF_HINT_NAME_NWSE);
|
||
|
|
if(hint==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Смещаем подсказку на указанные величины относительно курсора
|
||
|
|
int shift_x=10;
|
||
|
|
int shift_y=2;
|
||
|
|
return hint.Move(x+shift_x,y+shift_y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Изменение размера за правый верхний угол |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::ResizeZoneRightTopHandler(const int x,const int y)
|
||
|
|
{
|
||
|
|
//--- Рассчитываем и устанавливаем новые координату Y, ширину и высоту элемента
|
||
|
|
int new_y=::fmin(y, this.Bottom()-DEF_PANEL_MIN_H+1);
|
||
|
|
int width =::fmax(x-this.X()+1, DEF_PANEL_MIN_W);
|
||
|
|
int height=this.Bottom()-new_y+1;
|
||
|
|
if(!this.MoveXYWidthResize(this.X(),new_y,width,height))
|
||
|
|
return false;
|
||
|
|
//--- Получаем указатель на подсказку
|
||
|
|
CVisualHint *hint=this.GetHint(DEF_HINT_NAME_NESW);
|
||
|
|
if(hint==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Смещаем подсказку на указанные величины относительно курсора
|
||
|
|
int shift_x=5;
|
||
|
|
int shift_y=12;
|
||
|
|
return hint.Move(x+shift_x,y+shift_y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Изменение размера за левый нижний угол |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::ResizeZoneLeftBottomHandler(const int x,const int y)
|
||
|
|
{
|
||
|
|
//--- Рассчитываем и устанавливаем новые координату X, ширину и высоту элемента
|
||
|
|
int new_x=::fmin(x, this.Right()-DEF_PANEL_MIN_W+1);
|
||
|
|
int width =this.Right()-new_x+1;
|
||
|
|
int height=::fmax(y-this.Y()+1, DEF_PANEL_MIN_H);
|
||
|
|
if(!this.MoveXYWidthResize(new_x,this.Y(),width,height))
|
||
|
|
return false;
|
||
|
|
//--- Получаем указатель на подсказку
|
||
|
|
CVisualHint *hint=this.GetHint(DEF_HINT_NAME_NESW);
|
||
|
|
if(hint==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Смещаем подсказку на указанные величины относительно курсора
|
||
|
|
int shift_x=5;
|
||
|
|
int shift_y=12;
|
||
|
|
return hint.Move(x+shift_x,y+shift_y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Изменение размера за левый верхний угол |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::ResizeZoneLeftTopHandler(const int x,const int y)
|
||
|
|
{
|
||
|
|
//--- Рассчитываем и устанавливаем новые координаты X и Y, ширину и высоту элемента
|
||
|
|
int new_x=::fmin(x,this.Right()-DEF_PANEL_MIN_W+1);
|
||
|
|
int new_y=::fmin(y,this.Bottom()-DEF_PANEL_MIN_H+1);
|
||
|
|
int width =this.Right() -new_x+1;
|
||
|
|
int height=this.Bottom()-new_y+1;
|
||
|
|
if(!this.MoveXYWidthResize(new_x, new_y,width,height))
|
||
|
|
return false;
|
||
|
|
//--- Получаем указатель на подсказку
|
||
|
|
CVisualHint *hint=this.GetHint(DEF_HINT_NAME_NWSE);
|
||
|
|
if(hint==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Смещаем подсказку на указанные величины относительно курсора
|
||
|
|
int shift_x=10;
|
||
|
|
int shift_y=2;
|
||
|
|
return hint.Move(x+shift_x,y+shift_y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Сохранение в файл |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::Save(const int file_handle)
|
||
|
|
{
|
||
|
|
//--- Сохраняем данные родительского объекта
|
||
|
|
if(!CCanvasBase::Save(file_handle))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Сохраняем список подсказок
|
||
|
|
if(!this.m_list_hints.Save(file_handle))
|
||
|
|
return false;
|
||
|
|
//--- Сохраняем объект изображения
|
||
|
|
if(!this.m_painter.Save(file_handle))
|
||
|
|
return false;
|
||
|
|
//--- Сохраняем группу
|
||
|
|
if(::FileWriteInteger(file_handle,this.m_group,INT_VALUE)!=INT_VALUE)
|
||
|
|
return false;
|
||
|
|
//--- Сохраняем флаг видимости в контейнере
|
||
|
|
if(::FileWriteInteger(file_handle,this.m_visible_in_container,INT_VALUE)!=INT_VALUE)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CElementBase::Загрузка из файла |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CElementBase::Load(const int file_handle)
|
||
|
|
{
|
||
|
|
//--- Загружаем данные родительского объекта
|
||
|
|
if(!CCanvasBase::Load(file_handle))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Загружаем список подсказок
|
||
|
|
if(!this.m_list_hints.Load(file_handle))
|
||
|
|
return false;
|
||
|
|
//--- Загружаем объект изображения
|
||
|
|
if(!this.m_painter.Load(file_handle))
|
||
|
|
return false;
|
||
|
|
//--- Загружаем группу
|
||
|
|
this.m_group=::FileReadInteger(file_handle,INT_VALUE);
|
||
|
|
//--- Загружаем флаг видимости в контейнере
|
||
|
|
this.m_visible_in_container=::FileReadInteger(file_handle,INT_VALUE);
|
||
|
|
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс текстовой метки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CLabel : public CElementBase
|
||
|
|
{
|
||
|
|
protected:
|
||
|
|
ushort m_text[]; // Текст
|
||
|
|
ushort m_text_prev[]; // Прошлый текст
|
||
|
|
int m_text_x; // Координата X текста (смещение относительно левой границы объекта)
|
||
|
|
int m_text_y; // Координата Y текста (смещение относительно верхней границы объекта)
|
||
|
|
|
||
|
|
//--- (1) Устанавливает, (2) возвращает прошлый текст
|
||
|
|
void SetTextPrev(const string text) { ::StringToShortArray(text,this.m_text_prev); }
|
||
|
|
string TextPrev(void) const { return ::ShortArrayToString(this.m_text_prev);}
|
||
|
|
|
||
|
|
//--- Стирает текст
|
||
|
|
void ClearText(void);
|
||
|
|
|
||
|
|
public:
|
||
|
|
//--- (1) Устанавливает, (2) возвращает текст
|
||
|
|
void SetText(const string text) { ::StringToShortArray(text,this.m_text); }
|
||
|
|
string Text(void) const { return ::ShortArrayToString(this.m_text); }
|
||
|
|
|
||
|
|
//--- Возвращает координату (1) X, (2) Y текста
|
||
|
|
int TextX(void) const { return this.m_text_x; }
|
||
|
|
int TextY(void) const { return this.m_text_y; }
|
||
|
|
|
||
|
|
//--- Устанавливает координату (1) X, (2) Y текста
|
||
|
|
void SetTextShiftH(const int x) { this.ClearText(); this.m_text_x=x; }
|
||
|
|
void SetTextShiftV(const int y) { this.ClearText(); this.m_text_y=y; }
|
||
|
|
|
||
|
|
//--- Выводит текст
|
||
|
|
virtual void DrawText(const int dx, const int dy, const string text, const bool chart_redraw);
|
||
|
|
|
||
|
|
//--- Рисует внешний вид
|
||
|
|
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_LABEL); }
|
||
|
|
|
||
|
|
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
|
||
|
|
void Init(const string text);
|
||
|
|
virtual void InitColors(void){}
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
CLabel(void);
|
||
|
|
CLabel(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(void) {}
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CLabel::Конструктор по умолчанию. Строит метку в главном окне |
|
||
|
|
//| текущего графика в координатах 0,0 с размерами по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CLabel::CLabel(void) : CElementBase("Label","Label",::ChartID(),0,0,0,DEF_LABEL_W,DEF_LABEL_H), m_text_x(0), m_text_y(0)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init("Label");
|
||
|
|
}
|
||
|
|
//+-------------------------------------------------------------------+
|
||
|
|
//| CLabel::Конструктор параметрический. Строит метку в указанном окне|
|
||
|
|
//| указанного графика с указанными текстом, координатами и размерами |
|
||
|
|
//+-------------------------------------------------------------------+
|
||
|
|
CLabel::CLabel(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(object_name,text,chart_id,wnd,x,y,w,h), m_text_x(0), m_text_y(0)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init(text);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CLabel::Инициализация |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CLabel::Init(const string text)
|
||
|
|
{
|
||
|
|
//--- Устанавливаем текущий и предыдущий текст
|
||
|
|
this.SetText(text);
|
||
|
|
this.SetTextPrev("");
|
||
|
|
//--- Фон - прозрачный, передний план - нет
|
||
|
|
this.SetAlphaBG(0);
|
||
|
|
this.SetAlphaFG(255);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CLabel::Сравнение двух объектов |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CLabel::Compare(const CObject *node,const int mode=0) const
|
||
|
|
{
|
||
|
|
if(node==NULL)
|
||
|
|
return -1;
|
||
|
|
const CLabel *obj=node;
|
||
|
|
switch(mode)
|
||
|
|
{
|
||
|
|
case ELEMENT_SORT_BY_NAME : return(this.Name() >obj.Name() ? 1 : this.Name() <obj.Name() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_TEXT : return(this.Text() >obj.Text() ? 1 : this.Text() <obj.Text() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_X : return(this.X() >obj.X() ? 1 : this.X() <obj.X() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_Y : return(this.Y() >obj.Y() ? 1 : this.Y() <obj.Y() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_WIDTH : return(this.Width() >obj.Width() ? 1 : this.Width() <obj.Width() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_HEIGHT : return(this.Height() >obj.Height() ? 1 : this.Height() <obj.Height() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_COLOR_BG : return(this.BackColor() >obj.BackColor() ? 1 : this.BackColor() <obj.BackColor() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_COLOR_FG : return(this.ForeColor() >obj.ForeColor() ? 1 : this.ForeColor() <obj.ForeColor() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_ALPHA_BG : return(this.AlphaBG() >obj.AlphaBG() ? 1 : this.AlphaBG() <obj.AlphaBG() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_ALPHA_FG : return(this.AlphaFG() >obj.AlphaFG() ? 1 : this.AlphaFG() <obj.AlphaFG() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_STATE : return(this.State() >obj.State() ? 1 : this.State() <obj.State() ? -1 : 0);
|
||
|
|
case ELEMENT_SORT_BY_ZORDER : return(this.ObjectZOrder() >obj.ObjectZOrder() ? 1 : this.ObjectZOrder() <obj.ObjectZOrder() ? -1 : 0);
|
||
|
|
default : return(this.ID() >obj.ID() ? 1 : this.ID() <obj.ID() ? -1 : 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CLabel::Стирает текст |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CLabel::ClearText(void)
|
||
|
|
{
|
||
|
|
int w=0, h=0;
|
||
|
|
string text=this.TextPrev();
|
||
|
|
//--- Получаем размеры прошлого текста
|
||
|
|
if(text!="")
|
||
|
|
this.m_foreground.TextSize(text,w,h);
|
||
|
|
//--- Если размеры получены - рисуем на месте текста прозрачный прямоугольник, стирая текст
|
||
|
|
if(w>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()-dx<this.m_foreground.TextWidth(text))
|
||
|
|
{
|
||
|
|
//--- Получаем размеры текста "троеточие"
|
||
|
|
int w=0,h=0;
|
||
|
|
this.m_foreground.TextSize("... ",w,h);
|
||
|
|
if(w>0 && 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<total;i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.ObjectTrim();
|
||
|
|
}
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Изменяет высоту объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CPanel::ResizeH(const int h)
|
||
|
|
{
|
||
|
|
if(!this.ObjectResizeH(h))
|
||
|
|
return false;
|
||
|
|
this.BoundResizeH(h);
|
||
|
|
this.SetImageSize(this.Width(),h);
|
||
|
|
if(!this.ObjectTrim())
|
||
|
|
{
|
||
|
|
this.Update(false);
|
||
|
|
this.Draw(false);
|
||
|
|
}
|
||
|
|
//--- Получаем указатель на базовый элемент и, если он есть, и его тип - контейнер,
|
||
|
|
//--- проверяем отношение размеров текущего элемента относительно размеров контейнера
|
||
|
|
//--- для отображения полос прокрутки в контейнере при необходимости
|
||
|
|
CContainer *base=this.GetContainer();
|
||
|
|
if(base!=NULL && base.Type()==ELEMENT_TYPE_CONTAINER)
|
||
|
|
base.CheckElementSizes(&this);
|
||
|
|
|
||
|
|
//--- В цикле по присоединённым элементам обрезаем каждый элемент по границам контейнера
|
||
|
|
int total=this.m_list_elm.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.ObjectTrim();
|
||
|
|
}
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Изменяет размеры объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CPanel::Resize(const int w,const int h)
|
||
|
|
{
|
||
|
|
if(!this.ObjectResize(w,h))
|
||
|
|
return false;
|
||
|
|
this.BoundResize(w,h);
|
||
|
|
this.SetImageSize(w,h);
|
||
|
|
if(!this.ObjectTrim())
|
||
|
|
{
|
||
|
|
this.Update(false);
|
||
|
|
this.Draw(false);
|
||
|
|
}
|
||
|
|
//--- Получаем указатель на базовый элемент и, если он есть, и его тип - контейнер,
|
||
|
|
//--- проверяем отношение размеров текущего элемента относительно размеров контейнера
|
||
|
|
//--- для отображения полос прокрутки в контейнере при необходимости
|
||
|
|
CContainer *base=this.GetContainer();
|
||
|
|
if(base!=NULL && base.Type()==ELEMENT_TYPE_CONTAINER)
|
||
|
|
base.CheckElementSizes(&this);
|
||
|
|
|
||
|
|
//--- В цикле по присоединённым элементам обрезаем каждый элемент по границам контейнера
|
||
|
|
int total=this.m_list_elm.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.ObjectTrim();
|
||
|
|
}
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Рисует внешний вид |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::Draw(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Заливаем объект цветом фона
|
||
|
|
this.Fill(this.BackColor(),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_dark =(this.BackColor()==clrNULL ? this.BackColor() : this.GetBackColorControl().NewColor(this.BackColor(),-20,-20,-20));
|
||
|
|
color clr_light=(this.BackColor()==clrNULL ? this.BackColor() : this.GetBackColorControl().NewColor(this.BackColor(), 6, 6, 6));
|
||
|
|
if(this.BorderWidthBottom()+this.BorderWidthLeft()+this.BorderWidthRight()+this.BorderWidthTop()!=0)
|
||
|
|
this.m_painter.FrameGroupElements(this.AdjX(this.m_painter.X()),this.AdjY(this.m_painter.Y()),
|
||
|
|
this.m_painter.Width(),this.m_painter.Height(),this.Text(),
|
||
|
|
this.ForeColor(),clr_dark,clr_light,this.AlphaFG(),true);
|
||
|
|
|
||
|
|
//--- Обновляем канвас фона без перерисовки графика
|
||
|
|
this.m_background.Update(false);
|
||
|
|
|
||
|
|
//--- Рисуем элементы списка
|
||
|
|
for(int i=0;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL && elm.Type()!=ELEMENT_TYPE_SCROLLBAR_H && elm.Type()!=ELEMENT_TYPE_SCROLLBAR_V)
|
||
|
|
elm.Draw(false);
|
||
|
|
}
|
||
|
|
//--- Если указано - обновляем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Добавляет новый элемент в список |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CPanel::AddNewElement(CElementBase *element)
|
||
|
|
{
|
||
|
|
//--- Если передан пустой указатель - сообщаем об этом и возвращаем false
|
||
|
|
if(element==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Empty element passed",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
//--- Запоминаем метод сортировки списка
|
||
|
|
int sort_mode=this.m_list_elm.SortMode();
|
||
|
|
//--- Устанавливаем списку флаг сортировки по идентификатору
|
||
|
|
this.m_list_elm.Sort(ELEMENT_SORT_BY_ID);
|
||
|
|
//--- Если такого элемента нет в списке,
|
||
|
|
if(this.m_list_elm.Search(element)==NULL)
|
||
|
|
{
|
||
|
|
//--- возвращаем списку изначальную сортировку и возвращаем результат его добавления в список
|
||
|
|
this.m_list_elm.Sort(sort_mode);
|
||
|
|
return(this.m_list_elm.Add(element)>-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;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL && elm.ID()==id)
|
||
|
|
return elm;
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Возвращает элемент по назначенному имени объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CElementBase *CPanel::GetAttachedElementByName(const string name)
|
||
|
|
{
|
||
|
|
for(int i=0;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL && elm.Name()==name)
|
||
|
|
return elm;
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Создаёт и добавляет в список новую область |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CBound *CPanel::InsertNewBound(const string name,const int dx,const int dy,const int w,const int h)
|
||
|
|
{
|
||
|
|
//--- Проверяем есть ли в списке область с указанным именем и, если да - сообщаем об этом и возвращаем NULL
|
||
|
|
this.m_temp_bound.SetName(name);
|
||
|
|
//--- Запоминаем метод сортировки списка
|
||
|
|
int sort_mode=this.m_list_bounds.SortMode();
|
||
|
|
//--- Устанавливаем списку флаг сортировки по наименованию
|
||
|
|
this.m_list_bounds.Sort(ELEMENT_SORT_BY_NAME);
|
||
|
|
if(this.m_list_bounds.Search(&this.m_temp_bound)!=NULL)
|
||
|
|
{
|
||
|
|
//--- Возвращаем списку изначальную сортировку, сообщаем, что такой объект уже существует и возвращаем NULL
|
||
|
|
this.m_list_bounds.Sort(sort_mode);
|
||
|
|
::PrintFormat("%s: Error. An area named \"%s\" is already in the list",__FUNCTION__,name);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
//--- Возвращаем списку изначальную сортировку
|
||
|
|
this.m_list_bounds.Sort(sort_mode);
|
||
|
|
//--- Создаём новый объект-область; при неудаче - сообщаем об этом и возвращаем NULL
|
||
|
|
CBound *bound=new CBound(dx,dy,w,h);
|
||
|
|
if(bound==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to create CBound object",__FUNCTION__);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
//--- Устанавливаем имя области и идентификатор, и возвращаем указатель на объект
|
||
|
|
bound.SetName(name);
|
||
|
|
bound.SetID(this.m_list_bounds.Total());
|
||
|
|
//--- Если новый объект не удалось добавить в список - сообщаем об этом, удаляем объект и возвращаем NULL
|
||
|
|
if(this.m_list_bounds.Add(bound)==-1)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to add CBound object to list",__FUNCTION__);
|
||
|
|
delete bound;
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
return bound;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Возвращает область по идентификатору |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CBound *CPanel::GetBoundByID(const int id)
|
||
|
|
{
|
||
|
|
int total=this.m_list_bounds.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
CBound *bound=this.GetBoundAt(i);
|
||
|
|
if(bound!=NULL && bound.ID()==id)
|
||
|
|
return bound;
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Возвращает область по назначенному имени области |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CBound *CPanel::GetBoundByName(const string name)
|
||
|
|
{
|
||
|
|
int total=this.m_list_bounds.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
CBound *bound=this.GetBoundAt(i);
|
||
|
|
if(bound!=NULL && bound.Name()==name)
|
||
|
|
return bound;
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Назначает объект на указанную область |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CPanel::AssignObjectToBound(const int bound,CBaseObj *object)
|
||
|
|
{
|
||
|
|
CBound *bound_obj=this.GetBoundAt(bound);
|
||
|
|
if(bound_obj==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to get Bound at index %d",__FUNCTION__,bound);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
bound_obj.AssignObject(object);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Отменяет назначение объекта с указанной области |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CPanel::UnassignObjectFromBound(const int bound)
|
||
|
|
{
|
||
|
|
CBound *bound_obj=this.GetBoundAt(bound);
|
||
|
|
if(bound_obj==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to get Bound at index %d",__FUNCTION__,bound);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
bound_obj.UnassignObject();
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Выводит в журнал описание объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::Print(void)
|
||
|
|
{
|
||
|
|
CBaseObj::Print();
|
||
|
|
this.PrintAttached();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Распечатывает список присоединённых объектов |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::PrintAttached(const uint tab=3)
|
||
|
|
{
|
||
|
|
//--- В цикле по всем привязанным элементам
|
||
|
|
int total=this.m_list_elm.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- получаем очередной элемент
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm==NULL)
|
||
|
|
continue;
|
||
|
|
//--- Получаем тип элемента и, если это полоса прокрутки - пропускаем его
|
||
|
|
ENUM_ELEMENT_TYPE type=(ENUM_ELEMENT_TYPE)elm.Type();
|
||
|
|
if(type==ELEMENT_TYPE_SCROLLBAR_H || type==ELEMENT_TYPE_SCROLLBAR_V)
|
||
|
|
continue;
|
||
|
|
//--- Распечатываем в журнале описание элемента
|
||
|
|
::PrintFormat("%*s[%d]: %s",tab,"",i,elm.Description());
|
||
|
|
//--- Если элемент является контейнером - распечатываем в журнал его список привязанных элементов
|
||
|
|
if(type==ELEMENT_TYPE_PANEL || type==ELEMENT_TYPE_GROUPBOX || type==ELEMENT_TYPE_CONTAINER)
|
||
|
|
{
|
||
|
|
CPanel *obj=elm;
|
||
|
|
obj.PrintAttached(tab*2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Распечатывает список областей |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::PrintBounds(void)
|
||
|
|
{
|
||
|
|
//--- В цикле по списку областей элемента
|
||
|
|
int total=this.m_list_bounds.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- получаем очередную область и распечатываем её описание в журнал
|
||
|
|
CBound *obj=this.GetBoundAt(i);
|
||
|
|
if(obj==NULL)
|
||
|
|
continue;
|
||
|
|
::PrintFormat(" [%d]: %s",i,obj.Description());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Устанавливает объекту новые координаты X и Y |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CPanel::Move(const int x,const int y)
|
||
|
|
{
|
||
|
|
//--- Вычисляем дистанцию, на которую сместится элемент
|
||
|
|
int delta_x=x-this.X();
|
||
|
|
int delta_y=y-this.Y();
|
||
|
|
|
||
|
|
//--- Перемещаем элемент на указанные координаты
|
||
|
|
bool res=this.ObjectMove(x,y);
|
||
|
|
if(!res)
|
||
|
|
return false;
|
||
|
|
this.BoundMove(x,y);
|
||
|
|
this.ObjectTrim();
|
||
|
|
|
||
|
|
//--- Перемещаем все привязанные элементы на рассчитанную дистанцию
|
||
|
|
int total=this.m_list_elm.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- Перемещаем привязанный элемент с учётом смещения родительского элемента
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
res &=elm.Move(elm.X()+delta_x,elm.Y()+delta_y);
|
||
|
|
}
|
||
|
|
//--- Возвращаем результат перемещения всех привязанных элементов
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Смещает объект по осям X и Y на указанное смещение |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CPanel::Shift(const int dx,const int dy)
|
||
|
|
{
|
||
|
|
//--- Смещаем элемент на указанную дистанцию
|
||
|
|
bool res=this.ObjectShift(dx,dy);
|
||
|
|
if(!res)
|
||
|
|
return false;
|
||
|
|
this.BoundShift(dx,dy);
|
||
|
|
this.ObjectTrim();
|
||
|
|
|
||
|
|
//--- Смещаем все привязанные элементы
|
||
|
|
int total=this.m_list_elm.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
res &=elm.Shift(dx,dy);
|
||
|
|
}
|
||
|
|
//--- Возвращаем результат смещения всех привязанных элементов
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Устанавливает одновременно координаты и размеры элемента |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CPanel::MoveXYWidthResize(const int x,const int y,const int w,const int h)
|
||
|
|
{
|
||
|
|
//--- Вычисляем дистанцию, на которую сместится элемент
|
||
|
|
int delta_x=x-this.X();
|
||
|
|
int delta_y=y-this.Y();
|
||
|
|
|
||
|
|
//--- Перемещаем элемент на указанные координаты с изменением размеров
|
||
|
|
if(!CCanvasBase::MoveXYWidthResize(x,y,w,h))
|
||
|
|
return false;
|
||
|
|
this.BoundMove(x,y);
|
||
|
|
this.BoundResize(w,h);
|
||
|
|
this.SetImageBound(0,0,this.Width(),this.Height());
|
||
|
|
if(!this.ObjectTrim())
|
||
|
|
{
|
||
|
|
this.Update(false);
|
||
|
|
this.Draw(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Перемещаем все привязанные элементы на рассчитанную дистанцию
|
||
|
|
bool res=true;
|
||
|
|
int total=this.m_list_elm.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- Перемещаем привязанный элемент с учётом смещения родительского элемента
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
res &=elm.Move(elm.X()+delta_x,elm.Y()+delta_y);
|
||
|
|
}
|
||
|
|
//--- Возвращаем результат перемещения всех привязанных элементов
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Скрывает объект на всех периодах графика |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::Hide(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Если объект уже скрыт - уходим
|
||
|
|
if(this.m_hidden)
|
||
|
|
return;
|
||
|
|
|
||
|
|
//--- Скрываем панель
|
||
|
|
CCanvasBase::Hide(false);
|
||
|
|
//--- Скрываем прикреплённые объекты
|
||
|
|
for(int i=0;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.Hide(false);
|
||
|
|
}
|
||
|
|
//--- Если указано - перерисовываем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Отображает объект на всех периодах графика |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::Show(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Если объект уже видимый, или не должен отображаться в контейнере - уходим
|
||
|
|
if(!this.m_hidden || !this.m_visible_in_container)
|
||
|
|
return;
|
||
|
|
|
||
|
|
//--- Отображаем панель
|
||
|
|
CCanvasBase::Show(false);
|
||
|
|
//--- Отображаем прикреплённые объекты
|
||
|
|
for(int i=0;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
{
|
||
|
|
if(elm.Type()==ELEMENT_TYPE_SCROLLBAR_H || elm.Type()==ELEMENT_TYPE_SCROLLBAR_V)
|
||
|
|
continue;
|
||
|
|
elm.Show(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//--- Если указано - перерисовываем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Помещает объект на передний план |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::BringToTop(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Помещаем панель на передний план
|
||
|
|
CCanvasBase::BringToTop(false);
|
||
|
|
//--- Помещаем на передний план прикреплённые объекты
|
||
|
|
for(int i=0;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
{
|
||
|
|
if(elm.Type()==ELEMENT_TYPE_SCROLLBAR_H || elm.Type()==ELEMENT_TYPE_SCROLLBAR_V)
|
||
|
|
continue;
|
||
|
|
elm.ObjectTrim();
|
||
|
|
elm.BringToTop(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//--- Если указано - перерисовываем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Блокирует элемент |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::Block(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Если элемент уже заблокирован - уходим
|
||
|
|
if(this.m_blocked)
|
||
|
|
return;
|
||
|
|
|
||
|
|
//--- Блокируем панель
|
||
|
|
CCanvasBase::Block(false);
|
||
|
|
//--- Блокируем прикреплённые объекты
|
||
|
|
for(int i=0;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.Block(false);
|
||
|
|
}
|
||
|
|
//--- Если указано - перерисовываем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Разблокирует элемент |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::Unblock(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Если элемент уже разблокирован - уходим
|
||
|
|
if(!this.m_blocked)
|
||
|
|
return;
|
||
|
|
|
||
|
|
//--- Разблокируем панель
|
||
|
|
CCanvasBase::Unblock(false);
|
||
|
|
//--- Разблокируем прикреплённые объекты
|
||
|
|
for(int i=0;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.Unblock(false);
|
||
|
|
}
|
||
|
|
//--- Если указано - перерисовываем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Сохранение в файл |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CPanel::Save(const int file_handle)
|
||
|
|
{
|
||
|
|
//--- Сохраняем данные родительского объекта
|
||
|
|
if(!CElementBase::Save(file_handle))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Сохраняем список прикреплённых элементов
|
||
|
|
if(!this.m_list_elm.Save(file_handle))
|
||
|
|
return false;
|
||
|
|
//--- Сохраняем список областей
|
||
|
|
if(!this.m_list_bounds.Save(file_handle))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Загрузка из файла |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CPanel::Load(const int file_handle)
|
||
|
|
{
|
||
|
|
//--- Загружаем данные родительского объекта
|
||
|
|
if(!CElementBase::Load(file_handle))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Загружаем список прикреплённых элементов
|
||
|
|
if(!this.m_list_elm.Load(file_handle))
|
||
|
|
return false;
|
||
|
|
//--- Загружаем список областей
|
||
|
|
if(!this.m_list_bounds.Load(file_handle))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Обработчик событий |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
|
||
|
|
{
|
||
|
|
//--- Вызываем обработчик событий родительского класса
|
||
|
|
CCanvasBase::OnChartEvent(id,lparam,dparam,sparam);
|
||
|
|
//--- В цикле по всем привязанным элементам
|
||
|
|
int total=this.m_list_elm.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- получаем очередной элемент и вызываем его обработчик событий
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.OnChartEvent(id,lparam,dparam,sparam);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CPanel::Обработчик события таймера |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CPanel::TimerEventHandler(void)
|
||
|
|
{
|
||
|
|
//--- В цикле по всем привязанным элементам
|
||
|
|
for(int i=0;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
//--- получаем очередной элемент и вызываем его обработчик событий таймера
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.TimerEventHandler();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс группы объектов |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CGroupBox : public CPanel
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
//--- Тип объекта
|
||
|
|
virtual int Type(void) const { return(ELEMENT_TYPE_GROUPBOX); }
|
||
|
|
|
||
|
|
//--- Инициализация объекта класса
|
||
|
|
void Init(void);
|
||
|
|
|
||
|
|
//--- Устанавливает группу элементов
|
||
|
|
virtual void SetGroup(const int group);
|
||
|
|
|
||
|
|
//--- Создаёт и добавляет (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);
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
CGroupBox(void);
|
||
|
|
CGroupBox(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);
|
||
|
|
~CGroupBox(void) {}
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CGroupBox::Конструктор по умолчанию. |
|
||
|
|
//| Строит элемент в главном окне текущего графика |
|
||
|
|
//| в координатах 0,0 с размерами по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CGroupBox::CGroupBox(void) : CPanel("GroupBox","",::ChartID(),0,0,0,DEF_PANEL_W,DEF_PANEL_H)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CGroupBox::Конструктор параметрический. |
|
||
|
|
//| Строит элемент в указанном окне указанного графика |
|
||
|
|
//| с указанными текстом, координатами и размерами |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CGroupBox::CGroupBox(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)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CGroupBox::Инициализация |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CGroupBox::Init(void)
|
||
|
|
{
|
||
|
|
//--- Инициализация при помощи родительского класса
|
||
|
|
CPanel::Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CGroupBox::Устанавливает группу элементов |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CGroupBox::SetGroup(const int group)
|
||
|
|
{
|
||
|
|
//--- Устанавливаем группу этому элементу методом родительского класса
|
||
|
|
CElementBase::SetGroup(group);
|
||
|
|
//--- В цикле по списку привязанных элементов
|
||
|
|
for(int i=0;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
//--- получаем очередной элемент и назначаем ему группу
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.SetGroup(group);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CGroupBox::Создаёт и добавляет новый элемент в список |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CElementBase *CGroupBox::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)
|
||
|
|
{
|
||
|
|
//--- Создаём и добавляем в список элементов новый элемент
|
||
|
|
CElementBase *element=CPanel::InsertNewElement(type,text,user_name,dx,dy,w,h);
|
||
|
|
if(element==NULL)
|
||
|
|
return NULL;
|
||
|
|
//--- Устанавливаем созданному элементу группу, равную группе этого объекта
|
||
|
|
element.SetGroup(this.Group());
|
||
|
|
return element;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CGroupBox::Добавляет указанный элемент в список |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CElementBase *CGroupBox::InsertElement(CElementBase *element,const int dx,const int dy)
|
||
|
|
{
|
||
|
|
//--- Добавляем в список элементов новый элемент
|
||
|
|
if(CPanel::InsertElement(element,dx,dy)==NULL)
|
||
|
|
return NULL;
|
||
|
|
//--- Устанавливаем добавленному элементу группу, равную группе этого объекта
|
||
|
|
element.SetGroup(this.Group());
|
||
|
|
return element;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс ползунка горизонтальной полосы прокрутки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CScrollBarThumbH : 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_H); }
|
||
|
|
|
||
|
|
//--- Инициализация (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);
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
CScrollBarThumbH(void);
|
||
|
|
CScrollBarThumbH(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);
|
||
|
|
~CScrollBarThumbH (void) {}
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarThumbH::Конструктор по умолчанию. |
|
||
|
|
//| Строит элемент в главном окне текущего графика |
|
||
|
|
//| в координатах 0,0 с размерами по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CScrollBarThumbH::CScrollBarThumbH(void) : CButton("SBThumb","",::ChartID(),0,0,0,DEF_PANEL_W,DEF_SCROLLBAR_TH)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init("");
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarThumbH::Конструктор параметрический. |
|
||
|
|
//| Строит элемент в указанном окне указанного графика |
|
||
|
|
//| с указанными текстом, координатами и размерами |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CScrollBarThumbH::CScrollBarThumbH(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("");
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarThumbH::Инициализация |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CScrollBarThumbH::Init(const string text)
|
||
|
|
{
|
||
|
|
//--- Инициализация родительского класса
|
||
|
|
CButton::Init("");
|
||
|
|
//--- Устанавливаем флаги перемещаемости и обновления графика
|
||
|
|
this.SetMovable(true);
|
||
|
|
this.SetChartRedrawFlag(false);
|
||
|
|
//--- Элемент не обрезается по границам контейнера
|
||
|
|
this.m_trim_flag=false;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarThumbH::Обработчик перемещения курсора |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CScrollBarThumbH::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_w=base_obj.Width();
|
||
|
|
int base_left=base_obj.X()+base_obj.Height();
|
||
|
|
int base_right=base_obj.Right()-base_obj.Height()+1;
|
||
|
|
|
||
|
|
//--- Из координат курсора и размеров ползунка рассчитываем ограничения для перемещения
|
||
|
|
int x=(int)lparam-this.m_cursor_delta_x;
|
||
|
|
if(x<base_left)
|
||
|
|
x=base_left;
|
||
|
|
if(x+this.Width()>base_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(y<base_top)
|
||
|
|
y=base_top;
|
||
|
|
if(y+this.Height()>base_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<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.Draw(false);
|
||
|
|
}
|
||
|
|
//--- Если указано - обновляем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarH::Возвращает длину трека |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CScrollBarH::TrackLength(void) const
|
||
|
|
{
|
||
|
|
if(this.m_butt_left==NULL || this.m_butt_right==NULL)
|
||
|
|
return 0;
|
||
|
|
return(this.m_butt_right.X()-this.m_butt_left.Right());
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarH::Возвращает начало трека |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CScrollBarH::TrackBegin(void) const
|
||
|
|
{
|
||
|
|
return(this.m_butt_left!=NULL ? this.m_butt_left.Width() : 0);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarH::Возвращает позицию ползунка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CScrollBarH::ThumbPosition(void) const
|
||
|
|
{
|
||
|
|
int pos=(this.m_thumb!=NULL ? this.m_thumb.X()-this.TrackBegin()-this.X() : 0);
|
||
|
|
return(pos<0 ? 0 : pos);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarH::Изменяет ширину объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CScrollBarH::ResizeW(const int size)
|
||
|
|
{
|
||
|
|
//--- Получаем указатели на левую и правую кнопки
|
||
|
|
if(this.m_butt_left==NULL || this.m_butt_right==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Изменяем ширину объекта
|
||
|
|
if(!CCanvasBase::ResizeW(size))
|
||
|
|
return false;
|
||
|
|
//--- Смещаем кнопки на новое расположение относительно левой и правой границ изменившего размер элемента
|
||
|
|
if(!this.m_butt_left.MoveX(this.X()))
|
||
|
|
return false;
|
||
|
|
return(this.m_butt_right.MoveX(this.Right()-this.m_butt_right.Width()+1));
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarH::Обработчик прокрутки колёсика |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CScrollBarH::OnWheelEvent(const int id,const long lparam,const double dparam,const string sparam)
|
||
|
|
{
|
||
|
|
//--- Вызываем обработчик прокрутки для ползунка
|
||
|
|
if(this.m_thumb!=NULL)
|
||
|
|
this.m_thumb.OnWheelEvent(id,this.ThumbPosition(),dparam,this.NameFG());
|
||
|
|
|
||
|
|
//--- Отправляем пользовательское событие на график с позицией ползунка в lparam и именем объекта в sparam
|
||
|
|
::EventChartCustom(this.m_chart_id,CHARTEVENT_MOUSE_WHEEL,this.ThumbPosition(),dparam,this.NameFG());
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс вертикальной полосы прокрутки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CScrollBarV : public CPanel
|
||
|
|
{
|
||
|
|
protected:
|
||
|
|
CButtonArrowUp *m_butt_up; // Кнопка со стрелкой вверх
|
||
|
|
CButtonArrowDown *m_butt_down; // Кнопка со стрелкой вниз
|
||
|
|
CScrollBarThumbV *m_thumb; // Ползунок скроллбара
|
||
|
|
|
||
|
|
public:
|
||
|
|
//--- Возвращает указатель на (1) левую, (2) правую кнопку, (3) ползунок
|
||
|
|
CButtonArrowUp *GetButtonUp(void) { return this.m_butt_up; }
|
||
|
|
CButtonArrowDown *GetButtonDown(void) { return this.m_butt_down; }
|
||
|
|
CScrollBarThumbV *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.MoveY(pos) : false); }
|
||
|
|
//--- Изменяет размер ползунка
|
||
|
|
bool SetThumbSize(const uint size) const { return(this.m_thumb!=NULL ? this.m_thumb.ResizeH(size) : false); }
|
||
|
|
|
||
|
|
//--- Изменяет высоту объекта
|
||
|
|
virtual bool ResizeH(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_V); }
|
||
|
|
|
||
|
|
//--- Инициализация (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);
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
CScrollBarV(void);
|
||
|
|
CScrollBarV(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);
|
||
|
|
~CScrollBarV(void) {}
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Конструктор по умолчанию. |
|
||
|
|
//| Строит элемент в главном окне текущего графика |
|
||
|
|
//| в координатах 0,0 с размерами по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CScrollBarV::CScrollBarV(void) : CPanel("ScrollBarV","",::ChartID(),0,0,0,DEF_PANEL_W,DEF_PANEL_H),m_butt_up(NULL),m_butt_down(NULL),m_thumb(NULL)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Конструктор параметрический. |
|
||
|
|
//| Строит элемент в указанном окне указанного графика |
|
||
|
|
//| с указанными текстом, координатами и размерами |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CScrollBarV::CScrollBarV(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_up(NULL),m_butt_down(NULL),m_thumb(NULL)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Инициализация |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CScrollBarV::Init(void)
|
||
|
|
{
|
||
|
|
//--- Инициализация родительского класса
|
||
|
|
CPanel::Init();
|
||
|
|
//--- Фон - непрозрачный
|
||
|
|
this.SetAlphaBG(255);
|
||
|
|
//--- Ширина рамки и текст
|
||
|
|
this.SetBorderWidth(0);
|
||
|
|
this.SetText("");
|
||
|
|
|
||
|
|
//--- Создаём кнопки прокрутки
|
||
|
|
int w=this.Width();
|
||
|
|
int h=this.Width();
|
||
|
|
this.m_butt_up = this.InsertNewElement(ELEMENT_TYPE_BUTTON_ARROW_UP, "","ButtU",0,0,w,h);
|
||
|
|
this.m_butt_down= this.InsertNewElement(ELEMENT_TYPE_BUTTON_ARROW_DOWN,"","ButtD",0,this.Height()-w,w,h);
|
||
|
|
if(this.m_butt_up==NULL || this.m_butt_down==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Init failed",__FUNCTION__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
//--- Настраиваем цвета и вид кнопки со стрелкой вверх
|
||
|
|
this.m_butt_up.SetImageBound(1,0,w-4,h-2);
|
||
|
|
this.m_butt_up.InitBackColors(this.m_butt_up.BackColorFocused());
|
||
|
|
this.m_butt_up.ColorsToDefault();
|
||
|
|
this.m_butt_up.InitBorderColors(this.BorderColor(),this.m_butt_up.BackColorFocused(),this.m_butt_up.BackColorPressed(),this.m_butt_up.BackColorBlocked());
|
||
|
|
this.m_butt_up.ColorsToDefault();
|
||
|
|
|
||
|
|
//--- Настраиваем цвета и вид кнопки со стрелкой вниз
|
||
|
|
this.m_butt_down.SetImageBound(1,0,w-4,h-2);
|
||
|
|
this.m_butt_down.InitBackColors(this.m_butt_down.BackColorFocused());
|
||
|
|
this.m_butt_down.ColorsToDefault();
|
||
|
|
this.m_butt_down.InitBorderColors(this.BorderColor(),this.m_butt_down.BackColorFocused(),this.m_butt_down.BackColorPressed(),this.m_butt_down.BackColorBlocked());
|
||
|
|
|
||
|
|
//--- Создаём ползунок
|
||
|
|
int tsz=this.Height()-w*2;
|
||
|
|
this.m_thumb=this.InsertNewElement(ELEMENT_TYPE_SCROLLBAR_THUMB_V,"","ThumbV",1,w,w-2,tsz/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);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Инициализация цветов объекта по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CScrollBarV::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);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Устанавливает флаг видимости в контейнере |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CScrollBarV::SetVisibleInContainer(const bool flag)
|
||
|
|
{
|
||
|
|
this.m_visible_in_container=flag;
|
||
|
|
if(this.m_butt_up!=NULL)
|
||
|
|
this.m_butt_up.SetVisibleInContainer(flag);
|
||
|
|
if(this.m_butt_down!=NULL)
|
||
|
|
this.m_butt_down.SetVisibleInContainer(flag);
|
||
|
|
if(this.m_thumb!=NULL)
|
||
|
|
this.m_thumb.SetVisibleInContainer(flag);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Устанавливает флаг обрезки по границам контейнера |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CScrollBarV::SetTrimmered(const bool flag)
|
||
|
|
{
|
||
|
|
this.m_trim_flag=flag;
|
||
|
|
if(this.m_butt_up!=NULL)
|
||
|
|
this.m_butt_up.SetTrimmered(flag);
|
||
|
|
if(this.m_butt_down!=NULL)
|
||
|
|
this.m_butt_down.SetTrimmered(flag);
|
||
|
|
if(this.m_thumb!=NULL)
|
||
|
|
this.m_thumb.SetTrimmered(flag);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Рисует внешний вид |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CScrollBarV::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<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
elm.Draw(false);
|
||
|
|
}
|
||
|
|
//--- Если указано - обновляем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Возвращает длину трека |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CScrollBarV::TrackLength(void) const
|
||
|
|
{
|
||
|
|
if(this.m_butt_up==NULL || this.m_butt_down==NULL)
|
||
|
|
return 0;
|
||
|
|
return(this.m_butt_down.Y()-this.m_butt_up.Bottom());
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Возвращает начало ползунка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CScrollBarV::TrackBegin(void) const
|
||
|
|
{
|
||
|
|
return(this.m_butt_up!=NULL ? this.m_butt_up.Height() : 0);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Возвращает позицию ползунка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CScrollBarV::ThumbPosition(void) const
|
||
|
|
{
|
||
|
|
int pos=(this.m_thumb!=NULL ? this.m_thumb.Y()-this.TrackBegin()-this.Y() : 0);
|
||
|
|
return(pos<0 ? 0 : pos);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Изменяет высоту объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CScrollBarV::ResizeH(const int size)
|
||
|
|
{
|
||
|
|
//--- Получаем указатели на верхнюю и нижнюю кнопки
|
||
|
|
if(this.m_butt_up==NULL || this.m_butt_down==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Изменяем высоту объекта
|
||
|
|
if(!CCanvasBase::ResizeH(size))
|
||
|
|
return false;
|
||
|
|
//--- Смещаем кнопки на новое расположение относительно верхней и нижней границ изменившего размер элемента
|
||
|
|
if(!this.m_butt_up.MoveY(this.Y()))
|
||
|
|
return false;
|
||
|
|
return(this.m_butt_down.MoveY(this.Bottom()-this.m_butt_down.Height()+1));
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CScrollBarV::Обработчик прокрутки колёсика |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CScrollBarV::OnWheelEvent(const int id,const long lparam,const double dparam,const string sparam)
|
||
|
|
{
|
||
|
|
//--- Вызываем обработчик прокрутки для ползунка
|
||
|
|
if(this.m_thumb!=NULL)
|
||
|
|
this.m_thumb.OnWheelEvent(id,this.ThumbPosition(),dparam,this.NameFG());
|
||
|
|
|
||
|
|
//--- Отправляем пользовательское событие на график с позицией ползунка в lparam и именем объекта в sparam
|
||
|
|
::EventChartCustom(this.m_chart_id,CHARTEVENT_MOUSE_WHEEL,this.ThumbPosition(),dparam,this.NameFG());
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс Контейнер |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CContainer : public CPanel
|
||
|
|
{
|
||
|
|
private:
|
||
|
|
bool m_visible_scrollbar_h; // Флаг видимости горизонтальной полосы прокрутки
|
||
|
|
bool m_visible_scrollbar_v; // Флаг видимости вертикальной полосы прокрутки
|
||
|
|
int m_init_border_size_top; // Изначальный размер рамки сверху
|
||
|
|
int m_init_border_size_bottom; // Изначальный размер рамки снизу
|
||
|
|
int m_init_border_size_left; // Изначальный размер рамки слева
|
||
|
|
int m_init_border_size_right; // Изначальный размер рамки справа
|
||
|
|
|
||
|
|
//--- Возвращает тип элемента, отправившего событие
|
||
|
|
ENUM_ELEMENT_TYPE GetEventElementType(const string name);
|
||
|
|
|
||
|
|
protected:
|
||
|
|
CScrollBarH *m_scrollbar_h; // Указатель на горизонтальную полосу прокрутки
|
||
|
|
CScrollBarV *m_scrollbar_v; // Указатель на вертикальную полосу прокрутки
|
||
|
|
|
||
|
|
//--- Обработчик перетаскивания граней и углов элемента
|
||
|
|
virtual void ResizeActionDragHandler(const int x, const int y);
|
||
|
|
|
||
|
|
public:
|
||
|
|
//--- Проверяет размеры элемента для отображения полос прокрутки
|
||
|
|
void CheckElementSizes(CElementBase *element);
|
||
|
|
protected:
|
||
|
|
//--- Рассчитывает и возвращает размер (1) ползунка, (2) полный, (3) рабочий размер трека горизонтального скроллбара
|
||
|
|
int ThumbSizeHorz(void);
|
||
|
|
int TrackLengthHorz(void) const { return(this.m_scrollbar_h!=NULL ? this.m_scrollbar_h.TrackLength() : 0); }
|
||
|
|
int TrackEffectiveLengthHorz(void) { return(this.TrackLengthHorz()-this.ThumbSizeHorz()); }
|
||
|
|
//--- Рассчитывает и возвращает размер (1) ползунка, (2) полный, (3) рабочий размер трека вертикального скроллбара
|
||
|
|
int ThumbSizeVert(void);
|
||
|
|
int TrackLengthVert(void) const { return(this.m_scrollbar_v!=NULL ? this.m_scrollbar_v.TrackLength() : 0); }
|
||
|
|
int TrackEffectiveLengthVert(void) { return(this.TrackLengthVert()-this.ThumbSizeVert()); }
|
||
|
|
//--- Размер видимой области содержимого по (1) горизонтали, (2) вертикали
|
||
|
|
int ContentVisibleHorz(void) const { return int(this.Width()-this.BorderWidthLeft()-this.BorderWidthRight()); }
|
||
|
|
int ContentVisibleVert(void) const { return int(this.Height()-this.BorderWidthTop()-this.BorderWidthBottom()); }
|
||
|
|
|
||
|
|
//--- Полный размер содержимого по (1) горизонтали, (2) вертикали
|
||
|
|
int ContentSizeHorz(void);
|
||
|
|
int ContentSizeVert(void);
|
||
|
|
|
||
|
|
//--- Позиция содержимого по (1) горизонтали, (2) вертикали
|
||
|
|
int ContentPositionHorz(void);
|
||
|
|
int ContentPositionVert(void);
|
||
|
|
//--- Рассчитывает и возвращает величину смещения содержимого по (1) горизонтали, (2) вертикали в зависимости от положения ползунка
|
||
|
|
int CalculateContentOffsetHorz(const uint thumb_position);
|
||
|
|
int CalculateContentOffsetVert(const uint thumb_position);
|
||
|
|
//--- Рассчитывает и возвращает величину смещения ползунка по (1) горизонтали, (2) вертикали в зависимости от положения контента
|
||
|
|
int CalculateThumbOffsetHorz(const uint content_position);
|
||
|
|
int CalculateThumbOffsetVert(const uint content_position);
|
||
|
|
|
||
|
|
//--- Смещает содержимое по (1) горизонтали, (2) вертикали на указанное значение
|
||
|
|
bool ContentShiftHorz(const int value);
|
||
|
|
bool ContentShiftVert(const int value);
|
||
|
|
|
||
|
|
public:
|
||
|
|
//--- Возврат указателей на скроллбары, кнопки и ползунки скроллбаров
|
||
|
|
CScrollBarH *GetScrollBarH(void) { return this.m_scrollbar_h; }
|
||
|
|
CScrollBarV *GetScrollBarV(void) { return this.m_scrollbar_v; }
|
||
|
|
CButtonArrowUp *GetScrollBarButtonUp(void) { return(this.m_scrollbar_v!=NULL ? this.m_scrollbar_v.GetButtonUp() : NULL); }
|
||
|
|
CButtonArrowDown *GetScrollBarButtonDown(void) { return(this.m_scrollbar_v!=NULL ? this.m_scrollbar_v.GetButtonDown() : NULL); }
|
||
|
|
CButtonArrowLeft *GetScrollBarButtonLeft(void) { return(this.m_scrollbar_h!=NULL ? this.m_scrollbar_h.GetButtonLeft() : NULL); }
|
||
|
|
CButtonArrowRight*GetScrollBarButtonRight(void) { return(this.m_scrollbar_h!=NULL ? this.m_scrollbar_h.GetButtonRight(): NULL); }
|
||
|
|
CScrollBarThumbH *GetScrollBarThumbH(void) { return(this.m_scrollbar_h!=NULL ? this.m_scrollbar_h.GetThumb() : NULL); }
|
||
|
|
CScrollBarThumbV *GetScrollBarThumbV(void) { return(this.m_scrollbar_v!=NULL ? this.m_scrollbar_v.GetThumb() : NULL); }
|
||
|
|
|
||
|
|
//--- Возвращает флаг видимости (1) горизонтального, (2) вертикального скроллбара
|
||
|
|
bool ScrollBarHorzIsVisible(void) const { return this.m_visible_scrollbar_h; }
|
||
|
|
bool ScrollBarVertIsVisible(void) const { return this.m_visible_scrollbar_v; }
|
||
|
|
|
||
|
|
//--- Возвращает прикреплённый элемент (содержимое контейнера)
|
||
|
|
CElementBase *GetAttachedElement(void) { return this.GetAttachedElementAt(2); }
|
||
|
|
|
||
|
|
//--- Создаёт и добавляет (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);
|
||
|
|
|
||
|
|
//--- (1) Отображает объект на всех периодах графика, (2) помещает объект на передний план
|
||
|
|
virtual void Show(const bool chart_redraw);
|
||
|
|
virtual void BringToTop(const bool chart_redraw);
|
||
|
|
|
||
|
|
//--- Рисует внешний вид
|
||
|
|
virtual void Draw(const bool chart_redraw);
|
||
|
|
|
||
|
|
//--- Тип объекта
|
||
|
|
virtual int Type(void) const { return(ELEMENT_TYPE_CONTAINER); }
|
||
|
|
|
||
|
|
//--- Обработчики пользовательских событий элемента при наведении курсора, щелчке и прокрутке колёсика в области объекта
|
||
|
|
virtual void MouseMoveHandler(const int id, const long lparam, const double dparam, const string sparam);
|
||
|
|
virtual void MousePressHandler(const int id, const long lparam, const double dparam, const string sparam);
|
||
|
|
virtual void MouseWheelHandler(const int id, const long lparam, const double dparam, const string sparam);
|
||
|
|
|
||
|
|
//--- Инициализация объекта класса
|
||
|
|
void Init(void);
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
CContainer(void);
|
||
|
|
CContainer(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);
|
||
|
|
~CContainer (void) {}
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CContainer::Конструктор по умолчанию. |
|
||
|
|
//| Строит элемент в главном окне текущего графика |
|
||
|
|
//| в координатах 0,0 с размерами по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CContainer::CContainer(void) : CPanel("Container","",::ChartID(),0,0,0,DEF_PANEL_W,DEF_PANEL_H), m_visible_scrollbar_h(false), m_visible_scrollbar_v(false)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CContainer::Конструктор параметрический. |
|
||
|
|
//| Строит элемент в указанном окне указанного графика |
|
||
|
|
//| с указанными текстом, координатами и размерами |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CContainer::CContainer(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_visible_scrollbar_h(false), m_visible_scrollbar_v(false)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CContainer::Инициализация |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CContainer::Init(void)
|
||
|
|
{
|
||
|
|
//--- Инициализация родительского объекта
|
||
|
|
CPanel::Init();
|
||
|
|
//--- Ширина рамки
|
||
|
|
this.SetBorderWidth(0);
|
||
|
|
//--- Запоминаем установленную ширину рамки с каждой стороны
|
||
|
|
this.m_init_border_size_top = (int)this.BorderWidthTop();
|
||
|
|
this.m_init_border_size_bottom= (int)this.BorderWidthBottom();
|
||
|
|
this.m_init_border_size_left = (int)this.BorderWidthLeft();
|
||
|
|
this.m_init_border_size_right = (int)this.BorderWidthRight();
|
||
|
|
|
||
|
|
//--- Создаём горизонтальный скроллбар
|
||
|
|
this.m_scrollbar_h=dynamic_cast<CScrollBarH *>(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<CScrollBarV *>(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;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
{
|
||
|
|
if(elm.Type()==ELEMENT_TYPE_SCROLLBAR_H && !this.m_visible_scrollbar_h)
|
||
|
|
continue;
|
||
|
|
if(elm.Type()==ELEMENT_TYPE_SCROLLBAR_V && !this.m_visible_scrollbar_v)
|
||
|
|
continue;
|
||
|
|
elm.Show(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//--- Если указано - перерисовываем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CContainer::Помещает объект на передний план |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CContainer::BringToTop(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Помещаем панель на передний план
|
||
|
|
CCanvasBase::BringToTop(false);
|
||
|
|
//--- Помещаем на передний план прикреплённые объекты
|
||
|
|
for(int i=0;i<this.m_list_elm.Total();i++)
|
||
|
|
{
|
||
|
|
CElementBase *elm=this.GetAttachedElementAt(i);
|
||
|
|
if(elm!=NULL)
|
||
|
|
{
|
||
|
|
if(elm.Type()==ELEMENT_TYPE_SCROLLBAR_H && !this.m_visible_scrollbar_h)
|
||
|
|
{
|
||
|
|
elm.Hide(false);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if(elm.Type()==ELEMENT_TYPE_SCROLLBAR_V && !this.m_visible_scrollbar_v)
|
||
|
|
{
|
||
|
|
elm.Hide(false);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
elm.BringToTop(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//--- Если указано - перерисовываем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CContainer::Рисует внешний вид |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CContainer::Draw(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Рисуем внешний вид
|
||
|
|
CPanel::Draw(false);
|
||
|
|
|
||
|
|
//--- Если прокрутка разрешена
|
||
|
|
if(this.m_scroll_flag)
|
||
|
|
{
|
||
|
|
//--- Если оба скроллбара видимы
|
||
|
|
if(this.m_visible_scrollbar_h && this.m_visible_scrollbar_v)
|
||
|
|
{
|
||
|
|
//--- Получаем указатель на горизонтальную полосу прокрутки и берём цвет её фона
|
||
|
|
CScrollBarH *scroll_bar=this.GetScrollBarH();
|
||
|
|
color clr=(scroll_bar!=NULL ? scroll_bar.BackColor() : clrWhiteSmoke);
|
||
|
|
|
||
|
|
//--- Устанавливаем координаты, в которых будет нарисован закрашенный прямоугольник
|
||
|
|
int x1=this.Width()-DEF_SCROLLBAR_TH-1;
|
||
|
|
int y1=this.Height()-DEF_SCROLLBAR_TH-1;
|
||
|
|
int x2=this.Width()-3;
|
||
|
|
int y2=this.Height()-3;
|
||
|
|
|
||
|
|
//--- Рисуем прямоугольник цветом фона скроллбара в нижнем правом углу
|
||
|
|
this.m_foreground.FillRectangle(x1,y1,x2,y2,::ColorToARGB(clr));
|
||
|
|
this.m_foreground.Update(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Если указано - обновляем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CContainer::Создаёт и добавляет новый элемент в список |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CElementBase *CContainer::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)
|
||
|
|
{
|
||
|
|
//--- Проверяем, чтобы в списке было не более трёх объектов - две полосы прокрутки и добавляемый
|
||
|
|
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::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()<this.m_element_base.CellsTotal()-1)
|
||
|
|
{
|
||
|
|
int line_x=this.AdjX(this.Right());
|
||
|
|
this.m_background.Line(line_x,y1,line_x,y2,::ColorToARGB(this.m_element_base.BorderColor(),this.m_element_base.AlphaBG()));
|
||
|
|
}
|
||
|
|
//--- Обновляем канвас фона с указанным флагом перерисовки графика
|
||
|
|
this.m_background.Update(chart_redraw);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableCellView::Выводит текст |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableCellView::DrawText(const int dx,const int dy,const string text,const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Проверяем базовый элемент
|
||
|
|
if(this.m_element_base==NULL)
|
||
|
|
return;
|
||
|
|
|
||
|
|
//--- Очищаем ячейку и устанавливаем текст
|
||
|
|
this.Clear(false);
|
||
|
|
this.SetText(text);
|
||
|
|
|
||
|
|
//--- Выводим установленный текст на канвасе переднего плана
|
||
|
|
this.m_foreground.TextOut(dx,dy,this.Text(),::ColorToARGB(this.ForeColor(),this.m_element_base.AlphaFG()));
|
||
|
|
|
||
|
|
//--- Если текст выходит за правую границу области ячейки
|
||
|
|
if(this.Right()-dx<this.m_foreground.TextWidth(text))
|
||
|
|
{
|
||
|
|
//--- Получаем размеры текста "троеточие"
|
||
|
|
int w=0,h=0;
|
||
|
|
this.m_foreground.TextSize("... ",w,h);
|
||
|
|
if(w>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;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- получаем модель очередной ячейки,
|
||
|
|
CTableCell *cell_model=this.m_table_row_model.GetCell(i);
|
||
|
|
if(cell_model==NULL)
|
||
|
|
return false;
|
||
|
|
//--- рассчитываем координату и создаём имя для области ячейки
|
||
|
|
int x=cell_w*i;
|
||
|
|
string name="CellBound"+(string)this.m_table_row_model.Index()+"x"+(string)i;
|
||
|
|
//--- Создаём новую область ячейки
|
||
|
|
CBound *cell_bound=this.InsertNewBound(name,x,0,cell_w,this.Height());
|
||
|
|
if(cell_bound==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Создаём новый объект визуального представления ячейки
|
||
|
|
CTableCellView *cell_view=this.InsertNewCellView(i,cell_model.Value(),x,0,cell_w,this.Height());
|
||
|
|
if(cell_view==NULL)
|
||
|
|
return false;
|
||
|
|
//--- На текущую область ячейки назначаем соответствующий объект визуального представления ячейки
|
||
|
|
cell_bound.AssignObject(cell_view);
|
||
|
|
}
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableRowView::Обновляет сторку с обновлённой моделью |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableRowView::TableRowModelUpdate(CTableRow *row_model)
|
||
|
|
{
|
||
|
|
//--- Если передан пустой объект - сообщаем об этом и возвращаем false
|
||
|
|
if(row_model==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Empty object passed",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
//--- Если в переданной модели строки нет ни одной ячейки - сообщаем об этом и возвращаем false
|
||
|
|
int total_model=(int)row_model.CellsTotal(); // Количество ячеек в модели строки
|
||
|
|
if(total_model==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_model),DEF_TABLE_COLUMN_MIN_W);
|
||
|
|
|
||
|
|
CBound *cell_bound=NULL;
|
||
|
|
int total_bounds=this.m_list_bounds.Total(); // Количество областей
|
||
|
|
int diff=total_model-total_bounds; // Разница между количеством областей в строке и ячеек в модели строки
|
||
|
|
|
||
|
|
//--- Если в модели больше ячеек, чем областей в списке - создадим недостающие области и ячейки в конце списков
|
||
|
|
if(diff>0)
|
||
|
|
{
|
||
|
|
//--- В цикле по количеству недостающих областей
|
||
|
|
for(int i=total_bounds;i<total_bounds+diff;i++)
|
||
|
|
{
|
||
|
|
//--- создаём и добавляем в список diff количество областей ячеек строки.
|
||
|
|
//--- Получаем модель очередной ячейки,
|
||
|
|
CTableCell *cell_model=this.m_table_row_model.GetCell(i);
|
||
|
|
if(cell_model==NULL)
|
||
|
|
return false;
|
||
|
|
//--- рассчитываем координату и создаём имя для области ячейки
|
||
|
|
int x=cell_w*i;
|
||
|
|
string name="CellBound"+(string)this.m_table_row_model.Index()+"x"+(string)i;
|
||
|
|
//--- Создаём новую область ячейки
|
||
|
|
CBound *cell_bound=this.InsertNewBound(name,x,0,cell_w,this.Height());
|
||
|
|
if(cell_bound==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Создаём новый объект визуального представления ячейки
|
||
|
|
CTableCellView *cell_view=this.InsertNewCellView(i,cell_model.Value(),x,0,cell_w,this.Height());
|
||
|
|
if(cell_view==NULL)
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Если в списке больше областей, чем ячеек в модели - удалим лишние области в конце списка
|
||
|
|
if(diff<0)
|
||
|
|
{
|
||
|
|
int start=total_bounds-1;
|
||
|
|
int end=start-diff;
|
||
|
|
bool res=true;
|
||
|
|
for(int i=start;i>end;i--)
|
||
|
|
{
|
||
|
|
if(!this.BoundCellDelete(i))
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- В цикле по количеству ячеек в модели строки
|
||
|
|
for(int i=0;i<total_model;i++)
|
||
|
|
{
|
||
|
|
//--- получаем модель очередной ячейки,
|
||
|
|
CTableCell *cell_model=this.m_table_row_model.GetCell(i);
|
||
|
|
if(cell_model==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- рассчитываем координату ячейки
|
||
|
|
int x=cell_w*i;
|
||
|
|
//--- Получаем очередную область ячейки
|
||
|
|
CBound *cell_bound=this.GetBoundAt(i);
|
||
|
|
if(cell_bound==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Получаем из списка объект визуального представления ячейки
|
||
|
|
CTableCellView *cell_view=this.m_list_cells.GetNodeAtIndex(i);
|
||
|
|
if(cell_view==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- На текущую область ячейки назначаем соответствующий объект визуального представления ячейки и его текст
|
||
|
|
cell_bound.AssignObject(cell_view);
|
||
|
|
cell_view.SetText(cell_model.Value());
|
||
|
|
}
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableRowView::Удаляет указанную область строки |
|
||
|
|
//| и ячейку с соответствующим индексом |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableRowView::BoundCellDelete(const int index)
|
||
|
|
{
|
||
|
|
if(!this.m_list_cells.Delete(index))
|
||
|
|
return false;
|
||
|
|
return this.m_list_bounds.Delete(index);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableRowView::Рисует внешний вид |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableRowView::Draw(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Если строка за пределами контейнера - уходим
|
||
|
|
if(this.IsOutOfContainer())
|
||
|
|
return;
|
||
|
|
|
||
|
|
//--- Заливаем объект цветом фона, рисуем линию строки и обновляем канвас фона
|
||
|
|
this.Fill(this.BackColor(),false);
|
||
|
|
this.m_background.Line(this.AdjX(0),this.AdjY(this.Height()-1),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG()));
|
||
|
|
|
||
|
|
//--- Рисуем ячейки строки
|
||
|
|
int total=this.m_list_bounds.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- Получаем область очередной ячейки
|
||
|
|
CBound *cell_bound=this.GetBoundAt(i);
|
||
|
|
if(cell_bound==NULL)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
//--- Из области ячейки получаем присоединённый объект ячейки
|
||
|
|
CTableCellView *cell_view=cell_bound.GetAssignedObj();
|
||
|
|
//--- Рисуем визуальное представление ячейки
|
||
|
|
if(cell_view!=NULL)
|
||
|
|
cell_view.Draw(false);
|
||
|
|
}
|
||
|
|
//--- Обновляем канвасы фона и переднего плана с указанным флагом перерисовки графика
|
||
|
|
this.Update(chart_redraw);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableRowView::Распечатывает в журнале назначенную модель строки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableRowView::TableRowModelPrint(const bool detail, const bool as_table=false, const int cell_width=CELL_WIDTH_IN_CHARS)
|
||
|
|
{
|
||
|
|
if(this.m_table_row_model!=NULL)
|
||
|
|
this.m_table_row_model.Print(detail,as_table,cell_width);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableRowView::Перерассчитывает области ячеек |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableRowView::RecalculateBounds(CListElm *list_bounds)
|
||
|
|
{
|
||
|
|
//--- Проверяем список
|
||
|
|
if(list_bounds==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- В цикле по количеству областей в списке
|
||
|
|
for(int i=0;i<list_bounds.Total();i++)
|
||
|
|
{
|
||
|
|
//--- получаем очередную область заголовка и соответствующую ей область ячейки
|
||
|
|
CBound *capt_bound=list_bounds.GetNodeAtIndex(i);
|
||
|
|
CBound *cell_bound=this.GetBoundAt(i);
|
||
|
|
if(capt_bound==NULL || cell_bound==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- В область ячейки устанавливаем координату и размер области заголовка
|
||
|
|
cell_bound.SetX(capt_bound.X());
|
||
|
|
cell_bound.ResizeW(capt_bound.Width());
|
||
|
|
|
||
|
|
//--- Из области ячейки получаем присоединённый объект ячейки
|
||
|
|
CTableCellView *cell_view=cell_bound.GetAssignedObj();
|
||
|
|
if(cell_view==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- В объект визуального представления ячейки устанавливаем координату и размер области ячейки
|
||
|
|
cell_view.BoundSetX(cell_bound.X());
|
||
|
|
cell_view.BoundResizeW(cell_bound.Width());
|
||
|
|
}
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableRowView::Сохранение в файл |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableRowView::Save(const int file_handle)
|
||
|
|
{
|
||
|
|
//--- Сохраняем данные родительского объекта
|
||
|
|
if(!CPanel::Save(file_handle))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Сохраняем список ячеек
|
||
|
|
if(!this.m_list_cells.Save(file_handle))
|
||
|
|
return false;
|
||
|
|
//--- Сохраняем номер строки
|
||
|
|
if(::FileWriteInteger(file_handle,this.m_index,INT_VALUE)!=INT_VALUE)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableRowView::Загрузка из файла |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableRowView::Load(const int file_handle)
|
||
|
|
{
|
||
|
|
//--- Загружаем данные родительского объекта
|
||
|
|
if(!CPanel::Load(file_handle))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Загружаем список ячеек
|
||
|
|
if(!this.m_list_cells.Load(file_handle))
|
||
|
|
return false;
|
||
|
|
//--- Загружаем номер строки
|
||
|
|
this.m_id=this.m_index=(uchar)::FileReadInteger(file_handle,INT_VALUE);
|
||
|
|
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс визуального представления заголовка столбца таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CColumnCaptionView : public CButton
|
||
|
|
{
|
||
|
|
protected:
|
||
|
|
CColumnCaption *m_column_caption_model; // Указатель на модель заголовка столбца
|
||
|
|
CBound *m_bound_node; // Указатель на область заголовка
|
||
|
|
int m_index; // Индекс в списке столбцов
|
||
|
|
ENUM_TABLE_SORT_MODE m_sort_mode; // Режим сортировки столбца таблицы
|
||
|
|
|
||
|
|
//--- Добавляет в список объекты-подсказки со стрелками
|
||
|
|
virtual bool AddHintsArrowed(void);
|
||
|
|
//--- Отображает курсор изменения размеров
|
||
|
|
virtual bool ShowCursorHint(const ENUM_CURSOR_REGION edge,int x,int y);
|
||
|
|
|
||
|
|
public:
|
||
|
|
//--- Устанавливает идентификатор
|
||
|
|
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) возвращает область заголовка, которой назначен объект
|
||
|
|
void AssignBoundNode(CBound *bound) { this.m_bound_node=bound; }
|
||
|
|
CBound *GetBoundNode(void) { return this.m_bound_node; }
|
||
|
|
|
||
|
|
//--- (1) Назначает, (2) возвращает модель заголовка столбца
|
||
|
|
bool ColumnCaptionModelAssign(CColumnCaption *caption_model);
|
||
|
|
CColumnCaption *ColumnCaptionModel(void) { return this.m_column_caption_model; }
|
||
|
|
|
||
|
|
//--- Распечатывает в журнале назначенную модель заголовка столбца
|
||
|
|
void ColumnCaptionModelPrint(void);
|
||
|
|
|
||
|
|
//--- (1) Устанавливает, (2) возвращает режим сортировки
|
||
|
|
void SetSortMode(const ENUM_TABLE_SORT_MODE mode) { this.m_sort_mode=mode; }
|
||
|
|
ENUM_TABLE_SORT_MODE SortMode(void) const { return this.m_sort_mode; }
|
||
|
|
|
||
|
|
//--- Устанавливает противоположное направление сортировки
|
||
|
|
void SetSortModeReverse(void);
|
||
|
|
|
||
|
|
//--- Рисует (1) внешний вид, (2) стрелку направления сортировки
|
||
|
|
virtual void Draw(const bool chart_redraw);
|
||
|
|
protected:
|
||
|
|
void DrawSortModeArrow(void);
|
||
|
|
public:
|
||
|
|
//--- Обработчик изменения размеров элемента по правой стороне
|
||
|
|
virtual bool ResizeZoneRightHandler(const int x, const int y);
|
||
|
|
|
||
|
|
//--- Обработчики изменения размеров элемента по сторонам и углам
|
||
|
|
virtual bool ResizeZoneLeftHandler(const int x, const int y) { return false; }
|
||
|
|
virtual bool ResizeZoneTopHandler(const int x, const int y) { return false; }
|
||
|
|
virtual bool ResizeZoneBottomHandler(const int x, const int y) { return false; }
|
||
|
|
virtual bool ResizeZoneLeftTopHandler(const int x, const int y) { return false; }
|
||
|
|
virtual bool ResizeZoneRightTopHandler(const int x, const int y) { return false; }
|
||
|
|
virtual bool ResizeZoneLeftBottomHandler(const int x, const int y) { return false; }
|
||
|
|
virtual bool ResizeZoneRightBottomHandler(const int x, const int y){ return false; }
|
||
|
|
|
||
|
|
//--- Изменяет ширину объекта
|
||
|
|
virtual bool ResizeW(const int w);
|
||
|
|
|
||
|
|
//--- Обработчик событий нажатий кнопок мышки (Press)
|
||
|
|
virtual void OnPressEvent(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 { return CButton::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_COLUMN_CAPTION_VIEW);}
|
||
|
|
|
||
|
|
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
|
||
|
|
void Init(const string text);
|
||
|
|
virtual void InitColors(void);
|
||
|
|
|
||
|
|
//--- Возвращает описание объекта
|
||
|
|
virtual string Description(void);
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
CColumnCaptionView(void);
|
||
|
|
CColumnCaptionView(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);
|
||
|
|
~CColumnCaptionView (void){}
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Конструктор по умолчанию. Строит объект |
|
||
|
|
//| в главном окне текущего графика в координатах 0,0 |
|
||
|
|
//| с размерами по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CColumnCaptionView::CColumnCaptionView(void) : CButton("ColumnCaption","Caption",::ChartID(),0,0,0,DEF_PANEL_W,DEF_TABLE_ROW_H), m_index(0), m_sort_mode(TABLE_SORT_MODE_NONE)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init("Caption");
|
||
|
|
this.SetID(0);
|
||
|
|
this.SetName("ColumnCaption");
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Конструктор параметрический. |
|
||
|
|
//| Строит объект в указанном окне указанного графика с |
|
||
|
|
//| указанными текстом, координатами и размерами |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CColumnCaptionView::CColumnCaptionView(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), m_index(0), m_sort_mode(TABLE_SORT_MODE_NONE)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init(text);
|
||
|
|
this.SetID(0);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Инициализация |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CColumnCaptionView::Init(const string text)
|
||
|
|
{
|
||
|
|
//--- Смещения текста по умолчанию
|
||
|
|
this.m_text_x=4;
|
||
|
|
this.m_text_y=2;
|
||
|
|
//--- Устанавливаем цвета различных состояний
|
||
|
|
this.InitColors();
|
||
|
|
//--- Возможно изменять размеры
|
||
|
|
this.SetResizable(true);
|
||
|
|
this.SetMovable(false);
|
||
|
|
this.SetImageBound(this.ObjectWidth()-14,4,8,11);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Инициализация цветов объекта по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CColumnCaptionView::InitColors(void)
|
||
|
|
{
|
||
|
|
//--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона
|
||
|
|
this.InitBackColors(clrWhiteSmoke,this.GetBackColorControl().NewColor(clrWhiteSmoke,-6,-6,-6),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(clrSilver);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Рисует внешний вид |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CColumnCaptionView::Draw(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Если объект за пределами своего контейнера - уходим
|
||
|
|
if(this.IsOutOfContainer())
|
||
|
|
return;
|
||
|
|
|
||
|
|
//--- Заливаем объект цветом фона, рисуем слева светлую вертикальную линию, справа - тёмную
|
||
|
|
this.Fill(this.BackColor(),false);
|
||
|
|
color clr_dark =this.BorderColor(); // "Тёмный цвет"
|
||
|
|
color clr_light=this.GetBackColorControl().NewColor(this.BorderColor(), 100, 100, 100); // "Светлый цвет"
|
||
|
|
this.m_background.Line(this.AdjX(0),this.AdjY(0),this.AdjX(0),this.AdjY(this.Height()-1),::ColorToARGB(clr_light,this.AlphaBG())); // Линия слева
|
||
|
|
this.m_background.Line(this.AdjX(this.Width()-1),this.AdjY(0),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(clr_dark,this.AlphaBG())); // Линия справа
|
||
|
|
//--- обновляем канвас фона
|
||
|
|
this.m_background.Update(false);
|
||
|
|
|
||
|
|
//--- Выводим текст заголовка
|
||
|
|
CLabel::Draw(false);
|
||
|
|
|
||
|
|
//--- Рисуем стрелки направления сортировки
|
||
|
|
this.DrawSortModeArrow();
|
||
|
|
|
||
|
|
//--- Если указано - обновляем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Рисует стрелку направления сортировки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CColumnCaptionView::DrawSortModeArrow(void)
|
||
|
|
{
|
||
|
|
//--- Задаём цвет стрелки для обычного и заблокированного состояний объекта
|
||
|
|
color clr=(!this.IsBlocked() ? this.GetForeColorControl().NewColor(this.ForeColor(),90,90,90) : this.ForeColor());
|
||
|
|
switch(this.m_sort_mode)
|
||
|
|
{
|
||
|
|
//--- Сортировка по возрастанию
|
||
|
|
case TABLE_SORT_MODE_ASC :
|
||
|
|
//--- Очищаем область рисунка и рисуем стрелку вниз
|
||
|
|
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.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);
|
||
|
|
break;
|
||
|
|
//--- Сортировка по убыванию
|
||
|
|
case TABLE_SORT_MODE_DESC :
|
||
|
|
//--- Очищаем область рисунка и рисуем стрелку вверх
|
||
|
|
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.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);
|
||
|
|
break;
|
||
|
|
//--- Нет сортировки
|
||
|
|
default :
|
||
|
|
//--- Очищаем область рисунка
|
||
|
|
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);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Разворачивает направление сортировки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CColumnCaptionView::SetSortModeReverse(void)
|
||
|
|
{
|
||
|
|
switch(this.m_sort_mode)
|
||
|
|
{
|
||
|
|
case TABLE_SORT_MODE_ASC : this.m_sort_mode=TABLE_SORT_MODE_DESC; break;
|
||
|
|
case TABLE_SORT_MODE_DESC : this.m_sort_mode=TABLE_SORT_MODE_ASC; break;
|
||
|
|
default : break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Возвращает описание объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
string CColumnCaptionView::Description(void)
|
||
|
|
{
|
||
|
|
string nm=this.Name();
|
||
|
|
string name=(nm!="" ? ::StringFormat(" \"%s\"",nm) : nm);
|
||
|
|
string sort=(this.SortMode()==TABLE_SORT_MODE_ASC ? "ascending" : this.SortMode()==TABLE_SORT_MODE_DESC ? "descending" : "none");
|
||
|
|
return ::StringFormat("%s%s ID %d, X %d, Y %d, W %d, H %d, sort %s",ElementDescription((ENUM_ELEMENT_TYPE)this.Type()),name,this.ID(),this.X(),this.Y(),this.Width(),this.Height(),sort);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Назначает модель заголовка столбца |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CColumnCaptionView::ColumnCaptionModelAssign(CColumnCaption *caption_model)
|
||
|
|
{
|
||
|
|
//--- Если передан невалидный объект модели заголовка столбца - сообщаем об этом и возвращаем false
|
||
|
|
if(caption_model==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Empty object passed",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
//--- Сохраняем модель заголовка столбца
|
||
|
|
this.m_column_caption_model=caption_model;
|
||
|
|
//--- Устанавливаем размеры области рисования визуального представления заголовка столбца
|
||
|
|
this.m_painter.SetBound(0,0,this.Width(),this.Height());
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Распечатывает в журнале |
|
||
|
|
//| назначенную модель заголовка столбца |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CColumnCaptionView::ColumnCaptionModelPrint(void)
|
||
|
|
{
|
||
|
|
if(this.m_column_caption_model!=NULL)
|
||
|
|
this.m_column_caption_model.Print();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Добавляет в список |
|
||
|
|
//| объекты-подсказки со стрелками |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CColumnCaptionView::AddHintsArrowed(void)
|
||
|
|
{
|
||
|
|
//--- Создаём подсказку стрелки горизонтального смещения
|
||
|
|
CVisualHint *hint=this.CreateAndAddNewHint(HINT_TYPE_ARROW_SHIFT_HORZ,DEF_HINT_NAME_SHIFT_HORZ,18,18);
|
||
|
|
if(hint==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Устанавливаем размер области изображения подсказки
|
||
|
|
hint.SetImageBound(0,0,hint.Width(),hint.Height());
|
||
|
|
|
||
|
|
//--- скрываем подсказку и рисуем внешний вид
|
||
|
|
hint.Hide(false);
|
||
|
|
hint.Draw(false);
|
||
|
|
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Отображает курсор изменения размеров |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CColumnCaptionView::ShowCursorHint(const ENUM_CURSOR_REGION edge,int x,int y)
|
||
|
|
{
|
||
|
|
CVisualHint *hint=NULL; // Указатель на подсказку
|
||
|
|
int hint_shift_x=0; // Смещение подсказки по X
|
||
|
|
int hint_shift_y=0; // Смещение подсказки по Y
|
||
|
|
|
||
|
|
//--- В зависимости от расположения курсора на границах элемента
|
||
|
|
//--- указываем смещения подсказки относительно координат курсора,
|
||
|
|
//--- отображаем на графике требуемую подсказку и получаем указатель на этот объект
|
||
|
|
if(edge!=CURSOR_REGION_RIGHT)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
hint_shift_x=-8;
|
||
|
|
hint_shift_y=-12;
|
||
|
|
this.ShowHintArrowed(HINT_TYPE_ARROW_SHIFT_HORZ,x+hint_shift_x,y+hint_shift_y);
|
||
|
|
hint=this.GetHint(DEF_HINT_NAME_SHIFT_HORZ);
|
||
|
|
|
||
|
|
//--- Возвращаем результат корректировки положения подсказки относительно курсора
|
||
|
|
return(hint!=NULL ? hint.Move(x+hint_shift_x,y+hint_shift_y) : false);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Обработчик изменения размеров за правую грань|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CColumnCaptionView::ResizeZoneRightHandler(const int x,const int y)
|
||
|
|
{
|
||
|
|
//--- Рассчитываем и устанавливаем новую ширину элемента
|
||
|
|
int width=::fmax(x-this.X()+1,DEF_TABLE_COLUMN_MIN_W);
|
||
|
|
if(!this.ResizeW(width))
|
||
|
|
return false;
|
||
|
|
//--- Получаем указатель на подсказку
|
||
|
|
CVisualHint *hint=this.GetHint(DEF_HINT_NAME_SHIFT_HORZ);
|
||
|
|
if(hint==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Смещаем подсказку на указанные величины относительно курсора
|
||
|
|
int shift_x=-8;
|
||
|
|
int shift_y=-12;
|
||
|
|
|
||
|
|
CTableHeaderView *header=this.m_container;
|
||
|
|
if(header==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
bool res=header.RecalculateBounds(this.GetBoundNode(),this.Width());
|
||
|
|
res &=hint.Move(x+shift_x,y+shift_y);
|
||
|
|
if(res)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Изменяет ширину объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CColumnCaptionView::ResizeW(const int w)
|
||
|
|
{
|
||
|
|
if(!CCanvasBase::ResizeW(w))
|
||
|
|
return 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);
|
||
|
|
//--- Устанавливаем новую область рисунка
|
||
|
|
this.SetImageBound(this.Width()-14,4,8,11);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Обработчик событий нажатий кнопок мышки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CColumnCaptionView::OnPressEvent(const int id,const long lparam,const double dparam,const string sparam)
|
||
|
|
{
|
||
|
|
//--- Если кнопка мышки отпущена в области перетаскивания правой грани элемента - уходим
|
||
|
|
if(this.ResizeRegion()==CURSOR_REGION_RIGHT)
|
||
|
|
return;
|
||
|
|
//--- Меняем стрелку направления сортировки на обратную и вызываем обработчик щелчка мышки
|
||
|
|
this.SetSortModeReverse();
|
||
|
|
CCanvasBase::OnPressEvent(id,lparam,dparam,sparam);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Сохранение в файл |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CColumnCaptionView::Save(const int file_handle)
|
||
|
|
{
|
||
|
|
//--- Сохраняем данные родительского объекта
|
||
|
|
if(!CButton::Save(file_handle))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Сохраняем номер заголовка
|
||
|
|
if(::FileWriteInteger(file_handle,this.m_index,INT_VALUE)!=INT_VALUE)
|
||
|
|
return false;
|
||
|
|
//--- Сохраняем направление сортировки
|
||
|
|
if(::FileWriteInteger(file_handle,this.m_sort_mode,INT_VALUE)!=INT_VALUE)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CColumnCaptionView::Загрузка из файла |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CColumnCaptionView::Load(const int file_handle)
|
||
|
|
{
|
||
|
|
//--- Загружаем данные родительского объекта
|
||
|
|
if(!CButton::Load(file_handle))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Загружаем номер заголовка
|
||
|
|
this.m_id=this.m_index=::FileReadInteger(file_handle,INT_VALUE);
|
||
|
|
//--- Загружаем направление сортировки
|
||
|
|
this.m_id=this.m_sort_mode=(ENUM_TABLE_SORT_MODE)::FileReadInteger(file_handle,INT_VALUE);
|
||
|
|
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс визуального представления заголовка таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CTableHeaderView : public CPanel
|
||
|
|
{
|
||
|
|
protected:
|
||
|
|
CColumnCaptionView m_temp_caption; // Временный объект заголовка столбца для поиска
|
||
|
|
CTableHeader *m_table_header_model; // Указатель на модель заголовка таблицы
|
||
|
|
|
||
|
|
//--- Создаёт и добавляет в список новый объект представления заголовка столбца
|
||
|
|
CColumnCaptionView *InsertNewColumnCaptionView(const string text, const int x, const int y, const int w, const int h);
|
||
|
|
|
||
|
|
public:
|
||
|
|
//--- (1) Устанавливает, (2) возвращает модель заголовка таблицы
|
||
|
|
bool TableHeaderModelAssign(CTableHeader *header_model);
|
||
|
|
CTableHeader *GetTableHeaderModel(void) { return this.m_table_header_model; }
|
||
|
|
|
||
|
|
//--- Перерассчитывает области заголовков
|
||
|
|
bool RecalculateBounds(CBound *bound,int new_width);
|
||
|
|
|
||
|
|
//--- Распечатывает в журнале назначенную модель заголовка таблицы
|
||
|
|
void TableHeaderModelPrint(const bool detail, const bool as_table=false, const int cell_width=CELL_WIDTH_IN_CHARS);
|
||
|
|
|
||
|
|
//--- Рисует внешний вид
|
||
|
|
virtual void Draw(const bool chart_redraw);
|
||
|
|
|
||
|
|
//--- Устанавливает заголовку столбца флаг сортировки
|
||
|
|
void SetSortedColumnCaption(const uint index);
|
||
|
|
|
||
|
|
//--- Получает заголовок столбца (1) по индексу, (2) с флагом сортировки
|
||
|
|
CColumnCaptionView *GetColumnCaption(const uint index);
|
||
|
|
CColumnCaptionView *GetSortedColumnCaption(void);
|
||
|
|
//--- Возвращает индекс заголовка столбца с флагом сортировки
|
||
|
|
int IndexSortedColumnCaption(void);
|
||
|
|
|
||
|
|
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
|
||
|
|
virtual int Compare(const CObject *node,const int mode=0)const { return CPanel::Compare(node,mode); }
|
||
|
|
virtual bool Save(const int file_handle) { return CPanel::Save(file_handle); }
|
||
|
|
virtual bool Load(const int file_handle) { return CPanel::Load(file_handle); }
|
||
|
|
virtual int Type(void) const { return(ELEMENT_TYPE_TABLE_HEADER_VIEW); }
|
||
|
|
|
||
|
|
//--- Обработчик пользовательского события элемента при щелчке на области объекта
|
||
|
|
virtual void MousePressHandler(const int id, const long lparam, const double dparam, const string sparam);
|
||
|
|
|
||
|
|
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
|
||
|
|
void Init(void);
|
||
|
|
virtual void InitColors(void);
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
CTableHeaderView(void);
|
||
|
|
CTableHeaderView(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);
|
||
|
|
~CTableHeaderView (void){}
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Конструктор по умолчанию. Строит объект в |
|
||
|
|
//| главном окне текущего графика в координатах 0,0 |
|
||
|
|
//| с размерами по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableHeaderView::CTableHeaderView(void) : CPanel("TableHeader","",::ChartID(),0,0,0,DEF_PANEL_W,DEF_TABLE_ROW_H)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Конструктор параметрический. Строит объект в |
|
||
|
|
//| указанном окне указанного графика с указанными текстом, |
|
||
|
|
//| координатами и размерами |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableHeaderView::CTableHeaderView(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)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Инициализация |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableHeaderView::Init(void)
|
||
|
|
{
|
||
|
|
//--- Инициализация родительского объекта
|
||
|
|
CPanel::Init();
|
||
|
|
//--- Цвет фона - непрозрачный
|
||
|
|
this.SetAlphaBG(255);
|
||
|
|
//--- Ширина рамки
|
||
|
|
this.SetBorderWidth(1);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Инициализация цветов объекта по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableHeaderView::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);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Создаёт и добавляет в список |
|
||
|
|
//| новый объект представления заголовка столбца |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CColumnCaptionView *CTableHeaderView::InsertNewColumnCaptionView(const string text,const int x,const int y,const int w,const int h)
|
||
|
|
{
|
||
|
|
//--- Создаём наименование объекта и возвращаем результат создания нового заголовка столбца
|
||
|
|
string user_name="ColumnCaptionView"+(string)this.m_list_elm.Total();
|
||
|
|
CColumnCaptionView *caption_view=this.InsertNewElement(ELEMENT_TYPE_TABLE_COLUMN_CAPTION_VIEW,text,user_name,x,y,w,h);
|
||
|
|
return(caption_view!=NULL ? caption_view : NULL);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Устанавливает модель заголовка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableHeaderView::TableHeaderModelAssign(CTableHeader *header_model)
|
||
|
|
{
|
||
|
|
//--- Если передан пустой объект - сообщаем об этом и возвращаем false
|
||
|
|
if(header_model==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Empty object passed",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
//--- Если в переданной модели заголовка нет ни одного заголовка столбца - сообщаем об этом и возвращаем false
|
||
|
|
int total=(int)header_model.ColumnsTotal();
|
||
|
|
if(total==0)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Header model does not contain any columns",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
//--- Сохраняем указатель на переданную модель заголовка таблицы и рассчитываем ширину каждого заголовка столбца
|
||
|
|
this.m_table_header_model=header_model;
|
||
|
|
int caption_w=(int)::fmax(::round((double)this.Width()/(double)total),DEF_TABLE_COLUMN_MIN_W);
|
||
|
|
|
||
|
|
//--- В цикле по количеству заголовков столбцов в модели заголовка таблицы
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- получаем модель очередного заголовка столбца,
|
||
|
|
CColumnCaption *caption_model=this.m_table_header_model.GetColumnCaption(i);
|
||
|
|
if(caption_model==NULL)
|
||
|
|
return false;
|
||
|
|
//--- рассчитываем координату и создаём имя для области заголовка столбца
|
||
|
|
int x=caption_w*i;
|
||
|
|
string name="CaptionBound"+(string)i;
|
||
|
|
//--- Создаём новую область заголовка столбца
|
||
|
|
CBound *caption_bound=this.InsertNewBound(name,x,0,caption_w,this.Height());
|
||
|
|
if(caption_bound==NULL)
|
||
|
|
return false;
|
||
|
|
caption_bound.SetID(i);
|
||
|
|
//--- Создаём новый объект визуального представления заголовка столбца
|
||
|
|
CColumnCaptionView *caption_view=this.InsertNewColumnCaptionView(caption_model.Value(),x,0,caption_w,this.Height());
|
||
|
|
if(caption_view==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- На текущую область заголовка столбца назначаем соответствующий объект визуального представления заголовка столбца
|
||
|
|
caption_bound.AssignObject(caption_view);
|
||
|
|
caption_view.AssignBoundNode(caption_bound);
|
||
|
|
|
||
|
|
//--- Для самого первого заголовка устанавливаем флаг сортировки по возрастанию
|
||
|
|
if(i==0)
|
||
|
|
caption_view.SetSortMode(TABLE_SORT_MODE_ASC);
|
||
|
|
}
|
||
|
|
//--- Всё успешно
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Перерассчитывает области заголовков |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableHeaderView::RecalculateBounds(CBound *bound,int new_width)
|
||
|
|
{
|
||
|
|
//--- Если передан пустой объект области или его ширина не изменилась - возвращаем false
|
||
|
|
if(bound==NULL || bound.Width()==new_width)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Получаем индекс области в списке
|
||
|
|
int index=this.m_list_bounds.IndexOf(bound);
|
||
|
|
if(index==WRONG_VALUE)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Вычисляем смещение и, если его нет - возвращаем false
|
||
|
|
int delta=new_width-bound.Width();
|
||
|
|
if(delta==0)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Изменяем ширину текущей области и назначенного на область объекта
|
||
|
|
bound.ResizeW(new_width);
|
||
|
|
CElementBase *assigned_obj=bound.GetAssignedObj();
|
||
|
|
if(assigned_obj!=NULL)
|
||
|
|
assigned_obj.ResizeW(new_width);
|
||
|
|
|
||
|
|
//--- Получаем следующую область после текущей
|
||
|
|
CBound *next_bound=this.m_list_bounds.GetNextNode();
|
||
|
|
//--- Пересчитываем координаты X для всех последующих областей
|
||
|
|
while(!::IsStopped() && next_bound!=NULL)
|
||
|
|
{
|
||
|
|
//--- Сдвигаем область на значение delta
|
||
|
|
int new_x = next_bound.X()+delta;
|
||
|
|
int prev_width=next_bound.Width();
|
||
|
|
next_bound.SetX(new_x);
|
||
|
|
next_bound.Resize(prev_width,next_bound.Height());
|
||
|
|
|
||
|
|
//--- Если в области есть назначенный объект, обновляем его положение
|
||
|
|
CElementBase *assigned_obj=next_bound.GetAssignedObj();
|
||
|
|
if(assigned_obj!=NULL)
|
||
|
|
{
|
||
|
|
assigned_obj.Move(assigned_obj.X()+delta,assigned_obj.Y());
|
||
|
|
|
||
|
|
//--- Этот блок кода - часть мероприятий по поиску и устранению артефактов при перетаскивании заголовков
|
||
|
|
CCanvasBase *base_obj=assigned_obj.GetContainer();
|
||
|
|
if(base_obj!=NULL)
|
||
|
|
{
|
||
|
|
if(assigned_obj.X()>base_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;i<this.m_list_bounds.Total();i++)
|
||
|
|
{
|
||
|
|
CBound *bound=this.GetBoundAt(i);
|
||
|
|
if(bound!=NULL)
|
||
|
|
header_width+=bound.Width();
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Если рассчитанная ширина заголовка таблицы отличается от текущей - изменяем ширину
|
||
|
|
if(header_width!=this.Width())
|
||
|
|
{
|
||
|
|
if(!this.ResizeW(header_width))
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Получаем указатель на объект таблицы (View)
|
||
|
|
CTableView *table_view=this.GetContainer();
|
||
|
|
if(table_view==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Из объекта таблицы получаем указатель на панель со строками таблицы
|
||
|
|
CPanel *table_area=table_view.GetTableArea();
|
||
|
|
if(table_area==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Меняем размер панели строк таблицы под общий размер заголовков столбцов
|
||
|
|
if(!table_area.ResizeW(header_width))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Получаем список строк таблицы и проходим в цикле по всем строкам
|
||
|
|
CListElm *list=table_area.GetListAttachedElements();
|
||
|
|
int total=list.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- Получаем очередную строку таблицы
|
||
|
|
CTableRowView *row=table_area.GetAttachedElementAt(i);
|
||
|
|
if(row!=NULL)
|
||
|
|
{
|
||
|
|
//--- Меняем размер строки под размер панели и перерассчитываем области ячеек
|
||
|
|
row.ResizeW(table_area.Width());
|
||
|
|
row.RecalculateBounds(&this.m_list_bounds);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//--- Перерисовываем все строки таблицы
|
||
|
|
table_area.Draw(false);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Рисует внешний вид |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableHeaderView::Draw(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Заливаем объект цветом фона, рисуем линию строки и обновляем канвас фона
|
||
|
|
this.Fill(this.BackColor(),false);
|
||
|
|
this.m_background.Line(this.AdjX(0),this.AdjY(this.Height()-1),this.AdjX(this.Width()-1),this.AdjY(this.Height()-1),::ColorToARGB(this.BorderColor(),this.AlphaBG()));
|
||
|
|
this.m_background.Update(false);
|
||
|
|
|
||
|
|
//--- Рисуем заголовки столбцов
|
||
|
|
int total=this.m_list_bounds.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- Получаем область очередного заголовка столбца
|
||
|
|
CBound *cell_bound=this.GetBoundAt(i);
|
||
|
|
if(cell_bound==NULL)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
//--- Из области заголовка столбца получаем присоединённый объект заголовка столбца
|
||
|
|
CColumnCaptionView *caption_view=cell_bound.GetAssignedObj();
|
||
|
|
//--- Рисуем визуальное представление заголовка столбца
|
||
|
|
if(caption_view!=NULL)
|
||
|
|
{
|
||
|
|
caption_view.Draw(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//--- Если указано - обновляем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Устанавливает заголовку столбца флаг сортировки|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableHeaderView::SetSortedColumnCaption(const uint index)
|
||
|
|
{
|
||
|
|
int total=this.m_list_bounds.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- Получаем область очередного заголовка столбца и
|
||
|
|
//--- из неё получаем присоединённый объект заголовка столбца
|
||
|
|
CColumnCaptionView *caption_view=this.GetColumnCaption(i);
|
||
|
|
if(caption_view==NULL)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
//--- Если индекс цикла равен требуемому индексу - устанавливаем флаг сортировки по возрастанию
|
||
|
|
if(i==index)
|
||
|
|
{
|
||
|
|
caption_view.SetSortMode(TABLE_SORT_MODE_ASC);
|
||
|
|
caption_view.Draw(false);
|
||
|
|
}
|
||
|
|
//--- Иначе - сбрасываем флаг сортировки
|
||
|
|
else
|
||
|
|
{
|
||
|
|
caption_view.SetSortMode(TABLE_SORT_MODE_NONE);
|
||
|
|
caption_view.Draw(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
this.Draw(true);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Получает заголовок столбца по индексу |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CColumnCaptionView *CTableHeaderView::GetColumnCaption(const uint index)
|
||
|
|
{
|
||
|
|
//--- Получаем область заголовка столбца по индексу
|
||
|
|
CBound *capt_bound=this.GetBoundAt(index);
|
||
|
|
if(capt_bound==NULL)
|
||
|
|
return NULL;
|
||
|
|
//--- Из области заголовка столбца возвращаем указатель на присоединённый объект заголовка столбца
|
||
|
|
return capt_bound.GetAssignedObj();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Получает заголовок столбца с флагом сортировки |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CColumnCaptionView *CTableHeaderView::GetSortedColumnCaption(void)
|
||
|
|
{
|
||
|
|
int total=this.m_list_bounds.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- Получаем область очередного заголовка столбца и
|
||
|
|
//--- из неё получаем присоединённый объект заголовка столбца
|
||
|
|
CColumnCaptionView *caption_view=this.GetColumnCaption(i);
|
||
|
|
|
||
|
|
//--- Если объект получен и у него установлен флаг сортировки - возвращаем указатель на него
|
||
|
|
if(caption_view!=NULL && caption_view.SortMode()!=TABLE_SORT_MODE_NONE)
|
||
|
|
return caption_view;
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Возвращает индекс сортированного столбца |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int CTableHeaderView::IndexSortedColumnCaption(void)
|
||
|
|
{
|
||
|
|
int total=this.m_list_bounds.Total();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- Получаем область очередного заголовка столбца и
|
||
|
|
//--- из неё получаем присоединённый объект заголовка столбца
|
||
|
|
CColumnCaptionView *caption_view=this.GetColumnCaption(i);
|
||
|
|
|
||
|
|
//--- Если объект получен и у него установлен флаг сортировки - возвращаем индекс области
|
||
|
|
if(caption_view!=NULL && caption_view.SortMode()!=TABLE_SORT_MODE_NONE)
|
||
|
|
return i;
|
||
|
|
}
|
||
|
|
return WRONG_VALUE;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Распечатывает в журнале |
|
||
|
|
//| назначенную модель заголовка таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableHeaderView::TableHeaderModelPrint(const bool detail,const bool as_table=false,const int cell_width=CELL_WIDTH_IN_CHARS)
|
||
|
|
{
|
||
|
|
if(this.m_table_header_model!=NULL)
|
||
|
|
this.m_table_header_model.Print(detail,as_table,cell_width);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableHeaderView::Обработчик пользовательского события элемента |
|
||
|
|
//| при щелчке на области объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableHeaderView::MousePressHandler(const int id,const long lparam,const double dparam,const string sparam)
|
||
|
|
{
|
||
|
|
//--- Получаем из sparam наименование объекта заголовка таблицы
|
||
|
|
int len=::StringLen(this.NameFG());
|
||
|
|
string header_str=::StringSubstr(sparam,0,len);
|
||
|
|
//--- Если извлечённое имя не совпадает с именем этого объекта - не наше событие, уходим
|
||
|
|
if(header_str!=this.NameFG())
|
||
|
|
return;
|
||
|
|
|
||
|
|
//--- Найдём в sparam индекс заголовка столбца
|
||
|
|
string capt_str=::StringSubstr(sparam,len+1);
|
||
|
|
string index_str=::StringSubstr(capt_str,5,capt_str.Length()-7);
|
||
|
|
//--- Не нашли индекс в строке - уходим
|
||
|
|
if(index_str=="")
|
||
|
|
return;
|
||
|
|
//--- Записываем индекс заголовка столбца
|
||
|
|
int index=(int)::StringToInteger(index_str);
|
||
|
|
|
||
|
|
//--- Получаем заголовок столбца по индексу
|
||
|
|
CColumnCaptionView *caption=this.GetColumnCaption(index);
|
||
|
|
if(caption==NULL)
|
||
|
|
return;
|
||
|
|
|
||
|
|
//--- Если заголовок не имеет флага сортировки - ставим флаг сортировки по возрастанию
|
||
|
|
if(caption.SortMode()==TABLE_SORT_MODE_NONE)
|
||
|
|
{
|
||
|
|
this.SetSortedColumnCaption(index);
|
||
|
|
}
|
||
|
|
//--- Отправляем пользовательское событие на график с индексом заголовка в lparam, режимом сортировки в dparam и именем объекта в sparam
|
||
|
|
//--- Так как в стандартном событии OBJECT_CLICK в lparam и dparam передаются координаты курсора, то здесь будем передавать отрицательные значения
|
||
|
|
::EventChartCustom(this.m_chart_id, (ushort)CHARTEVENT_OBJECT_CLICK, -(1000+index), -(1000+caption.SortMode()), this.NameFG());
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Класс визуального представления таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CTableView : public CPanel
|
||
|
|
{
|
||
|
|
protected:
|
||
|
|
//--- Получаемые данные таблицы
|
||
|
|
CTable *m_table_obj; // Указатель на объект таблицы (включает модели таблицы и заголовка)
|
||
|
|
CTableModel *m_table_model; // Указатель на модель таблицы (получаем из CTable)
|
||
|
|
CTableHeader *m_header_model; // Указатель на модель заголовка таблицы (получаем из CTable)
|
||
|
|
|
||
|
|
//--- Данные компонента View
|
||
|
|
CTableHeaderView *m_header_view; // Указатель на заголовок таблицы (View)
|
||
|
|
CPanel *m_table_area; // Панель для размещения строк таблицы
|
||
|
|
CContainer *m_table_area_container; // Контейнер для размещения панели со строками таблицы
|
||
|
|
|
||
|
|
//--- (1) Устанавливает, (2) возвращает модель таблицы
|
||
|
|
bool TableModelAssign(CTableModel *table_model);
|
||
|
|
CTableModel *GetTableModel(void) { return this.m_table_model; }
|
||
|
|
|
||
|
|
//--- (1) Устанавливает, (2) возвращает модель заголовка таблицы
|
||
|
|
bool HeaderModelAssign(CTableHeader *header_model);
|
||
|
|
CTableHeader *GetHeaderModel(void) { return this.m_header_model; }
|
||
|
|
|
||
|
|
//--- Создаёт из модели объект (1) заголовка, (2) таблицы, (3) обновляет изменённую таблицу
|
||
|
|
bool CreateHeader(void);
|
||
|
|
bool CreateTable(void);
|
||
|
|
bool UpdateTable(void);
|
||
|
|
|
||
|
|
public:
|
||
|
|
//--- (1) Устанавливает, (2) возвращает объект таблицы
|
||
|
|
bool TableObjectAssign(CTable *table_obj);
|
||
|
|
CTable *GetTableObj(void) { return this.m_table_obj; }
|
||
|
|
|
||
|
|
//--- Возвращает (1) заголовок, (2) область размещения таблицы, (3) контейнер области таблицы
|
||
|
|
CTableHeaderView *GetHeader(void) { return this.m_header_view; }
|
||
|
|
CPanel *GetTableArea(void) { return this.m_table_area; }
|
||
|
|
CContainer *GetTableAreaContainer(void) { return this.m_table_area_container; }
|
||
|
|
|
||
|
|
//--- Распечатывает в журнале назначенную модель (1) таблицы, (2) заголовка, (3) объекта таблицы
|
||
|
|
void TableModelPrint(const bool detail);
|
||
|
|
void HeaderModelPrint(const bool detail, const bool as_table=false, const int cell_width=CELL_WIDTH_IN_CHARS);
|
||
|
|
void TablePrint(const int column_width=CELL_WIDTH_IN_CHARS);
|
||
|
|
|
||
|
|
//--- Получает заголовок столбца (1) по индексу, (2) с флагом сортировки
|
||
|
|
CColumnCaptionView *GetColumnCaption(const uint index)
|
||
|
|
{ return(this.GetHeader()!=NULL ? this.GetHeader().GetColumnCaption(index) : NULL); }
|
||
|
|
CColumnCaptionView *GetSortedColumnCaption(void)
|
||
|
|
{ return(this.GetHeader()!=NULL ? this.GetHeader().GetSortedColumnCaption(): NULL); }
|
||
|
|
|
||
|
|
//--- Возвращает объект визуальгного представления указанной (1) строки, (2) ячейки
|
||
|
|
CTableRowView *GetRowView(const uint index)
|
||
|
|
{ return(this.GetTableArea()!=NULL ? this.GetTableArea().GetAttachedElementAt(index) : NULL); }
|
||
|
|
CTableCellView *GetCellView(const uint row,const uint col)
|
||
|
|
{ return(this.GetRowView(row)!=NULL ? this.GetRowView(row).GetCellView(col) : NULL); }
|
||
|
|
|
||
|
|
//--- Возвращает количество строк таблицы
|
||
|
|
int RowsTotal(void)
|
||
|
|
{ return(this.GetTableArea()!=NULL ? this.GetTableArea().AttachedElementsTotal() : 0); }
|
||
|
|
|
||
|
|
//--- Рисует внешний вид
|
||
|
|
virtual void Draw(const bool chart_redraw);
|
||
|
|
|
||
|
|
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
|
||
|
|
virtual int Compare(const CObject *node,const int mode=0)const { return CPanel::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_VIEW); }
|
||
|
|
|
||
|
|
//--- Обработчик пользовательского события элемента при щелчке на области объекта
|
||
|
|
virtual void MousePressHandler(const int id, const long lparam, const double dparam, const string sparam);
|
||
|
|
|
||
|
|
//--- Сортирует таблицу по значению столбца и направлению
|
||
|
|
bool Sort(const uint column,const ENUM_TABLE_SORT_MODE sort_mode);
|
||
|
|
|
||
|
|
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
|
||
|
|
void Init(void);
|
||
|
|
|
||
|
|
//--- Конструкторы/деструктор
|
||
|
|
CTableView(void);
|
||
|
|
CTableView(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);
|
||
|
|
~CTableView (void){}
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Конструктор по умолчанию. |
|
||
|
|
//| Строит элемент в главном окне текущего графика |
|
||
|
|
//| в координатах 0,0 с размерами по умолчанию |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableView::CTableView(void) : CPanel("TableView","",::ChartID(),0,0,0,DEF_PANEL_W,DEF_PANEL_H),
|
||
|
|
m_table_model(NULL),m_header_model(NULL),m_table_obj(NULL),m_header_view(NULL),m_table_area(NULL),m_table_area_container(NULL)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Конструктор параметрический. |
|
||
|
|
//| Строит элемент в указанном окне указанного графика |
|
||
|
|
//| с указанными текстом, координатами и размерами |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableView::CTableView(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_table_model(NULL),m_header_model(NULL),m_table_obj(NULL),m_header_view(NULL),m_table_area(NULL),m_table_area_container(NULL)
|
||
|
|
{
|
||
|
|
//--- Инициализация
|
||
|
|
this.Init();
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Инициализация |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableView::Init(void)
|
||
|
|
{
|
||
|
|
//--- Инициализация родительского объекта
|
||
|
|
CPanel::Init();
|
||
|
|
//--- Ширина рамки
|
||
|
|
this.SetBorderWidth(1);
|
||
|
|
//--- Создаём заголовок таблицы
|
||
|
|
this.m_header_view=this.InsertNewElement(ELEMENT_TYPE_TABLE_HEADER_VIEW,"","TableHeader",0,0,this.Width(),DEF_TABLE_HEADER_H);
|
||
|
|
if(this.m_header_view==NULL)
|
||
|
|
return;
|
||
|
|
this.m_header_view.SetBorderWidth(1);
|
||
|
|
|
||
|
|
//--- Создаём контейнер, в котором будет находиться панель строк таблицы
|
||
|
|
this.m_table_area_container=this.InsertNewElement(ELEMENT_TYPE_CONTAINER,"","TableAreaContainer",0,DEF_TABLE_HEADER_H,this.Width(),this.Height()-DEF_TABLE_HEADER_H);
|
||
|
|
if(this.m_table_area_container==NULL)
|
||
|
|
return;
|
||
|
|
this.m_table_area_container.SetBorderWidth(0);
|
||
|
|
this.m_table_area_container.SetScrollable(true);
|
||
|
|
|
||
|
|
//--- Присоединяем к контейнеру панель для хранения строк таблицы
|
||
|
|
int shift_y=0;
|
||
|
|
this.m_table_area=this.m_table_area_container.InsertNewElement(ELEMENT_TYPE_PANEL,"","TableAreaPanel",0,shift_y,this.m_table_area_container.Width(),this.m_table_area_container.Height()-shift_y);
|
||
|
|
if(m_table_area==NULL)
|
||
|
|
return;
|
||
|
|
this.m_table_area.SetBorderWidth(0);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Устанавливает модель таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableView::TableModelAssign(CTableModel *table_model)
|
||
|
|
{
|
||
|
|
if(table_model==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Empty object passed",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
this.m_table_model=table_model;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Устанавливает модель заголовка таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableView::HeaderModelAssign(CTableHeader *header_model)
|
||
|
|
{
|
||
|
|
if(header_model==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Empty object passed",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
this.m_header_model=header_model;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Устанавливает объект таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableView::TableObjectAssign(CTable *table_obj)
|
||
|
|
{
|
||
|
|
//--- Если передан пустой объект таблицы - сообщаем об этом и возвращаем false
|
||
|
|
if(table_obj==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Empty object passed",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
//--- Сохраняем указатель в переменную
|
||
|
|
this.m_table_obj=table_obj;
|
||
|
|
//--- Записываем результат назначения модели таблицы и модели заголовка
|
||
|
|
bool res=this.TableModelAssign(this.m_table_obj.GetTableModel());
|
||
|
|
res &=this.HeaderModelAssign(this.m_table_obj.GetTableHeader());
|
||
|
|
|
||
|
|
//--- Если не удалось назначить какую-либо модель - возвращаем false
|
||
|
|
if(!res)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Записываем результат создания заголовка таблицы из модели и таблицы из модели
|
||
|
|
res=this.CreateHeader();
|
||
|
|
res&=this.CreateTable();
|
||
|
|
|
||
|
|
//--- Возвращаем результат
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Создаёт из модели объект заголовка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableView::CreateHeader(void)
|
||
|
|
{
|
||
|
|
if(this.m_header_view==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Table header object not created",__FUNCTION__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return this.m_header_view.TableHeaderModelAssign(this.m_header_model);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Создаёт из модели объект таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableView::CreateTable(void)
|
||
|
|
{
|
||
|
|
if(this.m_table_area==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- В цикле создаём и присоединяем к элементу Panel (m_table_area) RowsTotal строк из элементов TableRowView
|
||
|
|
int total=(int)this.m_table_model.RowsTotal();
|
||
|
|
int y=1; // Смещение по вертикали
|
||
|
|
int table_height=0; // Рассчитываемая высота панели
|
||
|
|
CTableRowView *row=NULL;
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- Создаём и присоединяем к панели объект строки таблицы
|
||
|
|
row=this.m_table_area.InsertNewElement(ELEMENT_TYPE_TABLE_ROW_VIEW,"","TableRow"+(string)i,0,y+(row!=NULL ? row.Height()*i : 0),this.m_table_area.Width()-1,DEF_TABLE_ROW_H);
|
||
|
|
if(row==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Устанавливаем идентификатор строки
|
||
|
|
row.SetID(i);
|
||
|
|
//--- В зависимости от номера строки (чет/нечет) устанавливаем цвет её фона
|
||
|
|
if(row.ID()%2==0)
|
||
|
|
row.InitBackColorDefault(clrWhite);
|
||
|
|
else
|
||
|
|
row.InitBackColorDefault(C'242,242,242');
|
||
|
|
row.BackColorToDefault();
|
||
|
|
row.InitBackColorFocused(row.GetBackColorControl().NewColor(row.BackColor(),-4,-4,-4));
|
||
|
|
|
||
|
|
//--- Получаем модель строки из объекта таблицы
|
||
|
|
CTableRow *row_model=this.m_table_model.GetRow(i);
|
||
|
|
if(row_model==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Созданному объекту строки таблицы назначаем полученную модель строки
|
||
|
|
row.TableRowModelAssign(row_model);
|
||
|
|
//--- Рассчитываем новое значение высоты панели
|
||
|
|
table_height+=row.Height();
|
||
|
|
}
|
||
|
|
//--- Возвращаем результат изменения размера панели на рассчитанное в цикле значение
|
||
|
|
return this.m_table_area.ResizeH(table_height+y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Обновляет изменённую таблицу |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CTableView::UpdateTable(void)
|
||
|
|
{
|
||
|
|
if(this.m_table_area==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
int total_model=(int)this.m_table_model.RowsTotal(); // Количество строк в модели
|
||
|
|
int total_view =this.m_table_area.AttachedElementsTotal(); // Количество строк в визуальном представлении
|
||
|
|
int diff=total_model-total_view; // Разница в количестве строк двух компонентов
|
||
|
|
int y=1; // Смещение по вертикали
|
||
|
|
int table_height=0; // Рассчитываемая высота панели
|
||
|
|
CTableRowView *row=NULL; // Указатель на объект визуального представления строки
|
||
|
|
|
||
|
|
//--- Если в модели больше строк, чем в визуальном представлении - создадим недостающие строки в визуальном предаставлении в конце списка
|
||
|
|
if(diff>0)
|
||
|
|
{
|
||
|
|
//--- Получаем последнюю строку визуального представления таблицы (на основе её координат будут размещены добавляемые строки)
|
||
|
|
row=this.m_table_area.GetAttachedElementAt(total_view-1);
|
||
|
|
//--- В цикле по количеству недостающих строк
|
||
|
|
for(int i=total_view;i<total_view+diff;i++)
|
||
|
|
{
|
||
|
|
//--- создаём и присоединяем к панели diff количество объектов визуального представления строки таблицы
|
||
|
|
row=this.m_table_area.InsertNewElement(ELEMENT_TYPE_TABLE_ROW_VIEW,"","TableRow"+(string)i,0,y+(row!=NULL ? row.Height()*i : 0),this.m_table_area.Width()-1,DEF_TABLE_ROW_H);
|
||
|
|
if(row==NULL)
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- Если в визуальном представлении больше строк, чем в модели - удалим лишние строки в визуальном предаставлении в конце списка
|
||
|
|
if(diff<0)
|
||
|
|
{
|
||
|
|
CListElm *list=this.m_table_area.GetListAttachedElements();
|
||
|
|
if(list==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
int start=total_view-1;
|
||
|
|
int end=start-diff;
|
||
|
|
bool res=true;
|
||
|
|
for(int i=start;i>end;i--)
|
||
|
|
res &=list.Delete(i);
|
||
|
|
if(!res)
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- В цикле по списку строк модели таблицы
|
||
|
|
for(int i=0;i<total_model;i++)
|
||
|
|
{
|
||
|
|
//--- получаем из списка панели строк очередной объект визуального представления строки таблицы
|
||
|
|
row=this.m_table_area.GetAttachedElementAt(i);
|
||
|
|
if(row==NULL)
|
||
|
|
return false;
|
||
|
|
//--- Проверим тип объекта
|
||
|
|
if(row.Type()!=ELEMENT_TYPE_TABLE_ROW_VIEW)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
//--- Устанавливаем идентификатор строки
|
||
|
|
row.SetID(i);
|
||
|
|
//--- В зависимости от номера строки (чет/нечет) устанавливаем цвет её фона
|
||
|
|
if(row.ID()%2==0)
|
||
|
|
row.InitBackColorDefault(clrWhite);
|
||
|
|
else
|
||
|
|
row.InitBackColorDefault(C'242,242,242');
|
||
|
|
row.BackColorToDefault();
|
||
|
|
row.InitBackColorFocused(row.GetBackColorControl().NewColor(row.BackColor(),-4,-4,-4));
|
||
|
|
|
||
|
|
//--- Получаем модель строки из объекта таблицы
|
||
|
|
CTableRow *row_model=this.m_table_model.GetRow(i);
|
||
|
|
if(row_model==NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
//--- Обновляем ячейки объекта строки таблицы по модели строки
|
||
|
|
row.TableRowModelUpdate(row_model);
|
||
|
|
//--- Рассчитываем новое значение высоты панели
|
||
|
|
table_height+=row.Height();
|
||
|
|
}
|
||
|
|
//--- Возвращаем результат изменения размера панели на рассчитанное в цикле значение
|
||
|
|
return this.m_table_area.ResizeH(table_height+y);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Рисует внешний вид |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableView::Draw(const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Рисуем заголовок и строки таблицы
|
||
|
|
this.m_header_view.Draw(false);
|
||
|
|
this.m_table_area_container.Draw(false);
|
||
|
|
//--- Если указано - обновляем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Распечатывает в журнале назначенную модель таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableView::TableModelPrint(const bool detail)
|
||
|
|
{
|
||
|
|
if(this.m_table_model!=NULL)
|
||
|
|
this.m_table_model.Print(detail);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Распечатывает в журнале назначенную модель заголовка |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableView::HeaderModelPrint(const bool detail,const bool as_table=false,const int column_width=CELL_WIDTH_IN_CHARS)
|
||
|
|
{
|
||
|
|
if(this.m_header_model!=NULL)
|
||
|
|
this.m_header_model.Print(detail,as_table,column_width);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Распечатывает в журнале назначенный объект таблицы |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableView::TablePrint(const int column_width=CELL_WIDTH_IN_CHARS)
|
||
|
|
{
|
||
|
|
if(this.m_table_obj!=NULL)
|
||
|
|
this.m_table_obj.Print(column_width);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CTableView::Обработчик пользовательского события элемента |
|
||
|
|
//| при щелчке на области объекта |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableView::MousePressHandler(const int id,const long lparam,const double dparam,const string sparam)
|
||
|
|
{
|
||
|
|
if(id==CHARTEVENT_OBJECT_CLICK && lparam>=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<typename T>
|
||
|
|
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<typename T>
|
||
|
|
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<typename T>
|
||
|
|
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<typename T>
|
||
|
|
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<total;i++)
|
||
|
|
{
|
||
|
|
//--- получаем из очередной строки таблицы объект визуального представление ячейки в указанном столбце
|
||
|
|
CTableCellView *cell_view=this.GetCellView(table,i,col);
|
||
|
|
if(cell_view==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s::%s: Error. Failed to get CTableCellView object (row %d, col %u)",source,__FUNCTION__,i,col);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
//--- Получаем модель соответствующей ячейки из модели строки
|
||
|
|
CTableCell *cell_model=table_model.GetCell(i,col);
|
||
|
|
if(cell_model==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s::%s: Error. Failed to get CTableCell object (row %d, col %u)",source,__FUNCTION__,i,col);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- В объект визуального представление ячейки записываем значение из модели ячейки
|
||
|
|
cell_view.SetText(cell_model.Value());
|
||
|
|
//--- Если указано - перерисовываем визуальное представление ячейки
|
||
|
|
if(cells_redraw)
|
||
|
|
cell_view.Draw(false);
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Устанавливает точность в указанном столбце (Model + View) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableControl::ColumnSetDigits(const uint table,const uint col,const int digits,const bool cells_redraw,const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Получаем модель таблицы
|
||
|
|
CTable *table_model=this.GetTable(table);
|
||
|
|
if(table_model==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to get CTable object",__FUNCTION__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
//--- Устанавливаем Digits для указанного столбца в модели таблицы
|
||
|
|
table_model.ColumnSetDigits(col,digits);
|
||
|
|
|
||
|
|
//--- Обновляем отображение данных столбца и, если указано, перерисовываем график
|
||
|
|
if(this.ColumnUpdate(__FUNCTION__,table_model,table,col,cells_redraw) && chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Устанавливает флаги отображения времени |
|
||
|
|
//| в указанном столбце (Model + View) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableControl::ColumnSetTimeFlags(const uint table,const uint col,const uint flags,const bool cells_redraw,const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Получаем модель таблицы
|
||
|
|
CTable *table_model=this.GetTable(table);
|
||
|
|
if(table_model==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to get CTable object",__FUNCTION__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
//--- Устанавливаем флаги отображения времени для указанного столбца в модели таблицы
|
||
|
|
table_model.ColumnSetTimeFlags(col,flags);
|
||
|
|
|
||
|
|
//--- Обновляем отображение данных столбца и, если указано, перерисовываем график
|
||
|
|
if(this.ColumnUpdate(__FUNCTION__,table_model,table,col,cells_redraw) && chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Устанавливает флаг отображения имён цвета |
|
||
|
|
//| в указанном столбце (Model + View) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableControl::ColumnSetColorNamesFlag(const uint table,const uint col,const bool flag,const bool cells_redraw,const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Получаем модель таблицы
|
||
|
|
CTable *table_model=this.GetTable(table);
|
||
|
|
if(table_model==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to get CTable object",__FUNCTION__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
//--- Устанавливаем флаги отображения времени для указанного столбца в модели таблицы
|
||
|
|
table_model.ColumnSetColorNamesFlag(col,flag);
|
||
|
|
|
||
|
|
//--- Обновляем отображение данных столбца и, если указано, перерисовываем график
|
||
|
|
if(this.ColumnUpdate(__FUNCTION__,table_model,table,col,cells_redraw) && chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Устанавливает тип данных в указанном столбце ( (Model + View)) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableControl::ColumnSetDatatype(const uint table,const uint col,const ENUM_DATATYPE type,const bool cells_redraw,const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Получаем модель таблицы
|
||
|
|
CTable *table_model=this.GetTable(table);
|
||
|
|
if(table_model==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to get CTable object",__FUNCTION__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
//--- Устанавливаем тип данных для указанного столбца в модели таблицы
|
||
|
|
table_model.ColumnSetDatatype(col,type);
|
||
|
|
|
||
|
|
//--- Обновляем отображение данных столбца и, если указано, перерисовываем график
|
||
|
|
if(this.ColumnUpdate(__FUNCTION__,table_model,table,col,cells_redraw) && chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Устанавливает точку привязки текста в указанном столбце (View) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void CTableControl::ColumnSetTextAnchor(const uint table,const uint col,const ENUM_ANCHOR_POINT anchor,const bool cells_redraw,const bool chart_redraw)
|
||
|
|
{
|
||
|
|
//--- Получаем визуальное представление таблицы
|
||
|
|
CTableView *table_view=this.GetTableView(table);
|
||
|
|
if(table_view==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to get CTableView object",__FUNCTION__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
//--- В цикле по всем строкам таблицы
|
||
|
|
int total=table_view.RowsTotal();
|
||
|
|
for(int i=0;i<total;i++)
|
||
|
|
{
|
||
|
|
//--- получаем очередной объект визуального представления ячейки
|
||
|
|
//--- и вписываем в объект новую точку привязки
|
||
|
|
CTableCellView *cell_view=this.GetCellView(table,i,col);
|
||
|
|
if(cell_view!=NULL && cell_view.TextAnchor()!=anchor)
|
||
|
|
cell_view.SetTextAnchor(anchor,cells_redraw,false);
|
||
|
|
}
|
||
|
|
//--- Если указано - обновляем график
|
||
|
|
if(chart_redraw)
|
||
|
|
::ChartRedraw(this.m_chart_id);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Возвращает строковое значение указанной ячейки (Model) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
string CTableControl::CellValueAt(const uint table,const uint row,const uint col)
|
||
|
|
{
|
||
|
|
CTable *table_model=this.GetTable(table);
|
||
|
|
return(table_model!=NULL ? table_model.CellValueAt(row,col) : ::StringFormat("%s: Error. Failed to get table model",__FUNCTION__));
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Возвращает указанную строку таблицы (View) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableRowView *CTableControl::GetRowView(const uint table,const uint index)
|
||
|
|
{
|
||
|
|
CTableView *table_view=this.GetTableView(table);
|
||
|
|
if(table_view==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to get CTableView object",__FUNCTION__);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
return table_view.GetRowView(index);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Возвращает указанную ячейку таблицы (View) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
CTableCellView *CTableControl::GetCellView(const uint table,const uint row,const uint col)
|
||
|
|
{
|
||
|
|
CTableView *table_view=this.GetTableView(table);
|
||
|
|
if(table_view==NULL)
|
||
|
|
{
|
||
|
|
::PrintFormat("%s: Error. Failed to get CTableView object",__FUNCTION__);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
return table_view.GetCellView(row,col);
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|