2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
//| Controls.mqh |
2026-03-29 12:59:40 +07:00
//| Copyright 2025, MetaQuotes Ltd. |
2026-03-28 03:09:22 +07:00
//| https://www.mql5.com |
//+------------------------------------------------------------------+
# property copyright " Copyright 2025, MetaQuotes Ltd. "
# property link " https://www.mql5.com "
//+------------------------------------------------------------------+
//| Включаемые библиотеки |
//+------------------------------------------------------------------+
# include "Base.mqh"
//+------------------------------------------------------------------+
//| Макроподстановки |
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
# define DEF_LABEL_W 50 / / Ширина текстовой метки по умолчанию
# define DEF_LABEL_H 16 / / Высота текстовой метки по умолчанию
# define DEF_BUTTON_W 60 / / Ширина кнопки по умолчанию
# define DEF_BUTTON_H 16 / / Высота кнопки по умолчанию
2026-03-29 13:06:34 +07:00
# define DEF_TABLE_ROW_H 16 / / Высота строки таблицы по умолчанию
# define DEF_TABLE_HEADER_H 20 / / Высота заголовка таблицы по умолчанию
2026-03-29 15:55:22 +07:00
# define DEF_TABLE_ROWS_HEADER_W 24 / / Минимальная ширина заголовков строк таблицы
2026-03-29 15:13:53 +07:00
# define DEF_TABLE_COLUMN_MIN_W 12 / / Минимальная ширина колонки таблицы
2026-03-28 12:12:49 +07:00
# define DEF_PANEL_W 80 / / Ширина панели по умолчанию
# define DEF_PANEL_H 80 / / Высота панели по умолчанию
2026-03-28 12:36:14 +07:00
# define DEF_PANEL_MIN_W 60 / / Минимальная ширина панели
# define DEF_PANEL_MIN_H 60 / / Минимальная высота панели
2026-03-28 12:12:49 +07:00
# define DEF_SCROLLBAR_TH 13 / / Толщина полосы прокрутки по умолчанию
# define DEF_THUMB_MIN_SIZE 8 / / Минимальная толщина ползунка полосы прокрутки
# define DEF_AUTOREPEAT_DELAY 500 / / Задержка перед запуском автоповтора
# define DEF_AUTOREPEAT_INTERVAL 100 / / Частота автоповторов
2026-03-28 03:09:22 +07:00
2026-03-29 15:13:53 +07:00
# 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 " / / Наименование подсказки " Стрелка вертикального смещения "
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
//| Перечисления |
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
enum ENUM_ELEMENT_SORT_BY // Сравниваемые свойства
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
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 , // Сравнение по группе элемента
2026-03-28 03:09:22 +07:00
} ;
2026-03-29 15:13:53 +07:00
enum ENUM_TABLE_SORT_MODE // Режимы сортировки столбцов таблиц
{
TABLE_SORT_MODE_NONE , // Сортировка отсутствует
TABLE_SORT_MODE_ASC , // Сортировка по возрастанию
TABLE_SORT_MODE_DESC , // Сортировка по убыванию
} ;
2026-03-28 12:36:14 +07:00
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)
2026-03-29 15:13:53 +07:00
HINT_TYPE_ARROW_SHIFT_HORZ , // Стрелка горизонтального смещения
HINT_TYPE_ARROW_SHIFT_VERT , // Стрелка вертикального смещения
2026-03-28 12:36:14 +07:00
} ;
2026-03-29 15:55:22 +07:00
enum ENUM_ROWS_HIGHLIGHT_MODE // Режимы подсветки строк/ячеек таблицы
{
ROWS_HIGHLIGHT_MODE_CELLS , // Подсвечивать отдельные ячейки (режим ячеек)
ROWS_HIGHLIGHT_MODE_ROW , // Подсвечивать всю строку целиком (режим строки)
} ;
2026-03-28 12:36:14 +07:00
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
//| Функции |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Классы |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| Класс связанного списка графических элементов |
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
class CListElm : public CList
2026-03-28 12:12:49 +07:00
{
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 ) ;
} ;
//+------------------------------------------------------------------+
//| Загрузка списка из файла |
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
bool CListElm : : Load ( const int file_handle )
2026-03-28 12:12:49 +07:00
{
//--- Переменные
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 ;
}
//+------------------------------------------------------------------+
//| Метод создания элемента списка |
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
CObject * CListElm : : CreateElement ( void )
2026-03-28 12:12:49 +07:00
{
//--- В зависимости от типа объекта в m_element_type, создаём новый объект
switch ( this . m_element_type )
{
2026-03-29 15:13:53 +07:00
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)
2026-03-29 15:55:22 +07:00
case ELEMENT_TYPE_TABLE_CAPTION_VIEW : return new CCaptionView ( ) ; // Базовый объект заголовка (View)
2026-03-29 15:13:53 +07:00
case ELEMENT_TYPE_TABLE_COLUMN_CAPTION_VIEW : return new CColumnCaptionView ( ) ; // Заголовок столбца таблицы (View)
2026-03-29 15:55:22 +07:00
case ELEMENT_TYPE_TABLE_ROW_CAPTION_VIEW : return new CRowCaptionView ( ) ; // Заголовок строки таблицы (View)
2026-03-29 15:13:53 +07:00
case ELEMENT_TYPE_TABLE_HEADER_VIEW : return new CTableHeaderView ( ) ; // Заголовок таблицы (View)
2026-03-29 15:55:22 +07:00
case ELEMENT_TYPE_TABLE_ROWS_HEADER_VIEW : return new CTableRowsHeaderView ( ) ; // Вертикальный заголовок таблицы (View)
2026-03-29 15:13:53 +07:00
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 ;
2026-03-28 12:12:49 +07:00
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-28 03:09:22 +07:00
//| Класс рисования изображений |
//+------------------------------------------------------------------+
class CImagePainter : public CBaseObj
{
protected :
CCanvas * m_canvas ; // Указатель на канвас, где рисуем
CBound m_bound ; // Координаты и границы изображения
uchar m_alpha ; // Прозрачность
//--- Проверяет валидность холста и корректность размеров
2026-03-29 15:13:53 +07:00
bool CheckBound ( const string source ) ;
2026-03-28 03:09:22 +07:00
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 ) ;
2026-03-28 12:36:14 +07:00
//--- Рисует (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 ) ;
2026-03-29 15:13:53 +07:00
//--- Рисует стрелку смещения 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 ) ;
2026-03-28 03:09:22 +07:00
//--- Рисует (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 ) ;
2026-03-28 12:12:49 +07:00
//--- Рисует рамку группы элементов
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 ) ;
2026-03-28 03:09:22 +07:00
2026-03-29 15:55:22 +07:00
//--- Рисует закрашенный треугольник в (1) левом-верхнем, (2) левом-нижнем, (3) правом-верхнем, (4) правом-нижнем углу
bool TriangleLT ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true ) ;
bool TriangleLB ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true ) ;
bool TriangleRT ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true ) ;
bool TriangleRB ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true ) ;
2026-03-28 03:09:22 +07:00
//--- Виртуальные методы (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
{
2026-03-28 12:12:49 +07:00
if ( node = = NULL )
return -1 ;
2026-03-28 03:09:22 +07:00
const CImagePainter * obj = node ;
switch ( mode )
{
2026-03-28 12:12:49 +07:00
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 ) ;
2026-03-28 03:09:22 +07:00
}
}
//+------------------------------------------------------------------+
//|CImagePainter::Проверяет валидность холста и корректность размеров|
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
bool CImagePainter : : CheckBound ( const string source )
2026-03-28 03:09:22 +07:00
{
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 )
{
2026-03-29 15:13:53 +07:00
: : 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 ( ) ) ;
2026-03-28 03:09:22 +07:00
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 03:09:22 +07:00
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 03:09:22 +07:00
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 03:09:22 +07:00
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 03:09:22 +07:00
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 03:09:22 +07:00
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 ;
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| 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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 12:36:14 +07:00
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 12:36:14 +07:00
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 ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 ;
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| 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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 12:36:14 +07:00
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 12:36:14 +07:00
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 ;
}
//+------------------------------------------------------------------+
2026-03-28 03:09:22 +07:00
//| 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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 03:09:22 +07:00
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 03:09:22 +07:00
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 03:09:22 +07:00
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 ; // Радиус
2026-03-28 12:12:49 +07:00
if ( r < 2 )
r = 2 ;
2026-03-28 03:09:22 +07:00
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 03:09:22 +07:00
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 ;
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| Рисует рамку группы элементов |
//+------------------------------------------------------------------+
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
2026-03-29 15:13:53 +07:00
if ( ! this . CheckBound ( __FUNCTION__ ) )
2026-03-28 12:12:49 +07:00
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 ;
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| Рисует закрашенный треугольник в левом-верхнем углу |
//+------------------------------------------------------------------+
bool CImagePainter : : TriangleLT ( 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 ;
int y1 = y + h ;
int x2 = x1 ;
int y2 = y ;
int x3 = x2 + w ;
int y3 = y2 ;
//--- Рисуем треугольник
this . m_canvas . FillTriangle ( x1 , y1 , x2 , y2 , x3 , y3 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Рисует закрашенный треугольник в левом-нижнем углу |
//+------------------------------------------------------------------+
bool CImagePainter : : TriangleLB ( 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 ;
int y1 = y ;
int x2 = x1 + w ;
int y2 = y1 + h ;
int x3 = x1 ;
int y3 = y2 ;
//--- Рисуем треугольник
this . m_canvas . FillTriangle ( x1 , y1 , x2 , y2 , x3 , y3 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Рисует закрашенный треугольник в правом-верхнем углу |
//+------------------------------------------------------------------+
bool CImagePainter : : TriangleRT ( 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 ;
int y1 = y ;
int x2 = x1 + w ;
int y2 = y ;
int x3 = x2 ;
int y3 = y2 + h ;
//--- Рисуем треугольник
this . m_canvas . FillTriangle ( x1 , y1 , x2 , y2 , x3 , y3 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| Рисует закрашенный треугольник в правом-нижнем углу |
//+------------------------------------------------------------------+
bool CImagePainter : : TriangleRB ( 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 + w ;
int y1 = y ;
int x2 = x1 ;
int y2 = y + h ;
int x3 = x ;
int y3 = y2 ;
//--- Рисуем треугольник
this . m_canvas . FillTriangle ( x1 , y1 , x2 , y2 , x3 , y3 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
2026-03-28 03:09:22 +07:00
//| 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 ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| Базовый класс графического элемента |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
class CElementBase : public CCanvasBase
2026-03-28 03:09:22 +07:00
{
protected :
CImagePainter m_painter ; // Класс рисования
2026-03-29 13:06:34 +07:00
CListElm m_list_hints ; // Список подсказок
2026-03-28 12:12:49 +07:00
int m_group ; // Группа элементов
2026-03-28 12:36:14 +07:00
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) удаляет из списка объекты-подсказки со стрелками
2026-03-29 15:13:53 +07:00
virtual bool AddHintsArrowed ( void ) ;
2026-03-28 12:36:14 +07:00
bool DeleteHintsArrowed ( void ) ;
//--- Отображает курсор изменения размеров
2026-03-29 15:13:53 +07:00
virtual bool ShowCursorHint ( const ENUM_CURSOR_REGION edge , int x , int y ) ;
2026-03-28 12:36:14 +07:00
//--- Обработчик перетаскивания граней и углов элемента
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 ) ;
2026-03-28 12:12:49 +07:00
public :
2026-03-29 13:06:34 +07:00
//--- Возвращает себя
CElementBase * GetObject ( void ) { return & this ; }
2026-03-28 12:36:14 +07:00
//--- Возвращает указатель на (1) класс рисования, (2) список подсказок
2026-03-28 12:12:49 +07:00
CImagePainter * Painter ( void ) { return & this . m_painter ; }
2026-03-29 13:06:34 +07:00
CListElm * GetListHints ( void ) { return & this . m_list_hints ; }
2026-03-28 12:36:14 +07:00
//--- Создаёт и добавляет (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 ) ;
2026-03-28 12:12:49 +07:00
//--- (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 ; }
2026-03-28 12:36:14 +07:00
//--- Устанавливает флаг возможности изменения размеров
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 ; }
2026-03-28 12:12:49 +07:00
//--- Возвращает описание объекта
virtual string Description ( void ) ;
2026-03-28 12:36:14 +07:00
//--- Обработчик изменения размеров (Resize)
virtual void OnResizeZoneEvent ( const int id , const long lparam , const double dparam , const string sparam ) ;
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
2026-03-28 12:12:49 +07:00
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 ) ; }
//--- Конструкторы/деструктор
2026-03-28 12:36:14 +07:00
CElementBase ( void ) { this . m_painter . CanvasAssign ( this . GetForeground ( ) ) ; this . m_visible_in_container = true ; }
2026-03-28 12:12:49 +07:00
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 ) ;
2026-03-29 15:13:53 +07:00
~ CElementBase ( void ) { this . m_list_hints . Clear ( ) ; }
2026-03-28 12:12:49 +07:00
} ;
2026-03-29 13:06:34 +07:00
//+-----------------------------------------------------------------------+
//| CElementBase::Конструктор параметрический. Строит элемент в указанном |
//| окне указанного графика с указанными текстом, координатами и размерами|
//+-----------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
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 )
{
//--- Объекту рисования назначаем канвас переднего плана и
2026-03-28 12:36:14 +07:00
//--- обнуляем координаты и размеры, что делает его неактивным,
//--- устанавливаем флаг видимости элемента в контейнере
2026-03-28 12:12:49 +07:00
this . m_painter . CanvasAssign ( this . GetForeground ( ) ) ;
this . m_painter . SetXY ( 0 , 0 ) ;
this . m_painter . SetSize ( 0 , 0 ) ;
2026-03-28 12:36:14 +07:00
this . m_visible_in_container = true ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| 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 ) ;
2026-03-29 15:13:53 +07:00
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 ( ) ) ;
2026-03-28 12:12:49 +07:00
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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| CElementBase::Устанавливает флаг возможности изменения размеров |
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
void CElementBase : : SetResizable ( const bool flag )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
//--- В родительский объект записываем флаг
CCanvasBase : : SetResizable ( flag ) ;
//--- Если флаг передан как true - создаём для курсора четыре подсказки со стрелками,
if ( flag )
this . AddHintsArrowed ( ) ;
//--- иначе - удаляем подсказки со стрелками для курсора
else
this . DeleteHintsArrowed ( ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| CElementBase::Возвращает указатель на подсказку по индексу |
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
CVisualHint * CElementBase : : GetHintAt ( const int index )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
return this . m_list_hints . GetNodeAtIndex ( index ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| CElementBase::Возвращает указатель на подсказку по идентификатору|
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
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 ;
}
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//|CElementBase:: Возвращает указатель на подсказку по наименованию |
//+------------------------------------------------------------------+
CVisualHint * CElementBase : : GetHint ( const string name )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
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 ;
}
2026-03-29 15:13:53 +07:00
//--- Запоминаем метод сортировки списка
int sort_mode = this . m_list_hints . SortMode ( ) ;
2026-03-28 12:36:14 +07:00
//--- Устанавливаем списку флаг сортировки по идентификатору
this . m_list_hints .Sort ( ELEMENT_SORT_BY_ID ) ;
2026-03-29 15:13:53 +07:00
//--- Если такого элемента нет в списке,
2026-03-28 12:36:14 +07:00
if ( this . m_list_hints . Search ( obj ) = = NULL )
2026-03-29 15:13:53 +07:00
{
//--- возвращаем списку изначальную сортировку и возвращаем результат его добавления в список
this . m_list_hints .Sort ( sort_mode ) ;
2026-03-28 12:36:14 +07:00
return ( this . m_list_hints . Add ( obj ) > -1 ) ;
2026-03-29 15:13:53 +07:00
}
//--- Возвращаем списку изначальную сортировку
this . m_list_hints .Sort ( sort_mode ) ;
2026-03-28 12:36:14 +07:00
//--- Элемент с таким идентификатором уже есть в списке - возвращаем 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 ) ;
2026-03-28 03:09:22 +07:00
2026-03-28 12:36:14 +07:00
//--- Возвращаем указатель на созданный объект
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 ;
2026-03-28 03:09:22 +07:00
2026-03-28 12:36:14 +07:00
//--- Рассчитываем координаты объекта ниже и правее правого нижнего угла элемента
int x = this . Right ( ) + 1 ;
int y = this . Bottom ( ) + 1 ;
2026-03-28 03:09:22 +07:00
2026-03-28 12:36:14 +07:00
//--- Создаём новый объект-подсказку
CVisualHint * obj = this . CreateNewHint ( type , obj_name , user_name , obj_total , x , y , w , h ) ;
2026-03-28 03:09:22 +07:00
2026-03-28 12:36:14 +07:00
//--- Если новый объект не создан - возвращаем NULL
if ( obj = = NULL )
return NULL ;
2026-03-28 03:09:22 +07:00
2026-03-28 12:36:14 +07:00
//--- Устанавливаем пределы изображения, контейнер и z-order
obj . SetImageBound ( 0 , 0 , this . Width ( ) , this . Height ( ) ) ;
obj . SetContainerObj ( & this ) ;
obj . ObjectSetZOrder ( this . ObjectZOrder ( ) + 1 ) ;
2026-03-28 12:12:49 +07:00
2026-03-28 12:36:14 +07:00
//--- Если созданный элемент не добавлен в список - сообщаем об этом, удаляем созданный элемент и возвращаем 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 ;
}
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| CElementBase::Добавляет существующий объект-подсказку в список |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
CVisualHint * CElementBase : : AddHint ( CVisualHint * obj , const int dx , const int dy )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:36:14 +07:00
//--- Если передан объект не с типом подсказки - возвращаем 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 ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| CElementBase::Добавляет в список объекты-подсказки со стрелками |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
bool CElementBase : : AddHintsArrowed ( void )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:36:14 +07:00
//--- Массивы наименований и типов подсказок
2026-03-29 15:13:53 +07:00
string array [ 4 ] = { DEF_HINT_NAME_HORZ , DEF_HINT_NAME_VERT , DEF_HINT_NAME_NWSE , DEF_HINT_NAME_NESW } ;
2026-03-28 12:36:14 +07:00
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 ;
2026-03-28 03:09:22 +07:00
}
2026-03-28 12:36:14 +07:00
//+------------------------------------------------------------------+
//| CElementBase::Удаляет из списка объекты-подсказки со стрелками |
//+------------------------------------------------------------------+
bool CElementBase : : DeleteHintsArrowed ( void )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
//--- В цикле по списку объектов-подсказок
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 ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| CElementBase::Создаёт и добавляет новый объект-подсказку в список|
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
CVisualHint * CElementBase : : InsertNewTooltip ( const ENUM_HINT_TYPE type , const string user_name , const int w , const int h )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:36:14 +07:00
//--- Если тип подсказки не тултип - сообщаем об этом и возвращаем 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 ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| CElementBase::Добавляет ранее созданный объект-подсказку в список|
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
CVisualHint * CElementBase : : InsertTooltip ( CVisualHint * obj , const int dx , const int dy )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:36:14 +07:00
//--- Если передан пустой или невалидный указатель на объект - возвращаем NULL
if ( : : CheckPointer ( obj ) = = POINTER_INVALID )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:36:14 +07:00
: : 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 ) ;
2026-03-29 15:13:53 +07:00
hint = this . GetHint ( DEF_HINT_NAME_HORZ ) ;
2026-03-28 12:36:14 +07:00
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 ) ;
2026-03-29 15:13:53 +07:00
hint = this . GetHint ( DEF_HINT_NAME_VERT ) ;
2026-03-28 12:36:14 +07:00
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 ) ;
2026-03-29 15:13:53 +07:00
hint = this . GetHint ( DEF_HINT_NAME_NWSE ) ;
2026-03-28 12:36:14 +07:00
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 ) ;
2026-03-29 15:13:53 +07:00
hint = this . GetHint ( DEF_HINT_NAME_NESW ) ;
2026-03-28 12:36:14 +07:00
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 ;
2026-03-29 15:13:53 +07:00
2026-03-28 12:36:14 +07:00
//--- Если курсор за границами изменения размеров или только что наведён на зону взаимодействия
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 ;
//--- Получаем указатель на подсказку
2026-03-29 15:13:53 +07:00
CVisualHint * hint = this . GetHint ( DEF_HINT_NAME_HORZ ) ;
2026-03-28 12:36:14 +07:00
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 ;
//--- Получаем указатель на подсказку
2026-03-29 15:13:53 +07:00
CVisualHint * hint = this . GetHint ( DEF_HINT_NAME_VERT ) ;
2026-03-28 12:36:14 +07:00
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 ;
//--- Получаем указатель на подсказку
2026-03-29 15:13:53 +07:00
CVisualHint * hint = this . GetHint ( DEF_HINT_NAME_HORZ ) ;
2026-03-28 12:36:14 +07:00
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 ;
//--- Получаем указатель на подсказку
2026-03-29 15:13:53 +07:00
CVisualHint * hint = this . GetHint ( DEF_HINT_NAME_VERT ) ;
2026-03-28 12:36:14 +07:00
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 ;
//--- Получаем указатель на подсказку
2026-03-29 15:13:53 +07:00
CVisualHint * hint = this . GetHint ( DEF_HINT_NAME_NWSE ) ;
2026-03-28 12:36:14 +07:00
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 ;
//--- Получаем указатель на подсказку
2026-03-29 15:13:53 +07:00
CVisualHint * hint = this . GetHint ( DEF_HINT_NAME_NESW ) ;
2026-03-28 12:36:14 +07:00
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 ;
//--- Получаем указатель на подсказку
2026-03-29 15:13:53 +07:00
CVisualHint * hint = this . GetHint ( DEF_HINT_NAME_NESW ) ;
2026-03-28 12:36:14 +07:00
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 ;
//--- Получаем указатель на подсказку
2026-03-29 15:13:53 +07:00
CVisualHint * hint = this . GetHint ( DEF_HINT_NAME_NWSE ) ;
2026-03-28 12:36:14 +07:00
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 [ ] ; // Прошлый текст
2026-03-29 13:06:34 +07:00
int m_text_x ; // Координата X текста (смещение относительно левой границы объекта)
int m_text_y ; // Координата Y текста (смещение относительно верхней границы объекта)
2026-03-28 12:36:14 +07:00
//--- (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 ; }
//--- Выводит текст
2026-03-29 13:06:34 +07:00
virtual void DrawText ( const int dx , const int dy , const string text , const bool chart_redraw ) ;
2026-03-28 12:36:14 +07:00
//--- Рисует внешний вид
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::Конструктор параметрический. Строит метку в указанном окне|
2026-03-29 13:06:34 +07:00
//| указанного графика с указанными текстом, координатами и размерами |
2026-03-28 12:36:14 +07:00
//+-------------------------------------------------------------------+
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 ) ;
2026-03-28 12:12:49 +07:00
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 ) ;
2026-03-28 03:09:22 +07:00
}
}
//+------------------------------------------------------------------+
//| 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 )
{
//--- Сохраняем данные родительского объекта
2026-03-28 12:12:49 +07:00
if ( ! CElementBase : : Save ( file_handle ) )
2026-03-28 03:09:22 +07:00
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 )
{
//--- Загружаем данные родительского объекта
2026-03-28 12:12:49 +07:00
if ( ! CElementBase : : Load ( file_handle ) )
2026-03-28 03:09:22 +07:00
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 ) ; }
2026-03-28 12:12:49 +07:00
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
virtual void InitColors ( void ) { }
//--- Обработчик события таймера
virtual void TimerEventHandler ( void ) ;
2026-03-28 03:09:22 +07:00
//--- Конструкторы/деструктор
CButton ( void ) ;
2026-03-28 12:12:49 +07:00
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 ) ;
2026-03-28 03:09:22 +07:00
~ CButton ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CButton::Конструктор по умолчанию. Строит кнопку в главном окне |
//| текущего графика в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
CButton : : CButton ( void ) : CLabel ( " Button " , " Button " , : : ChartID ( ) , 0 , 0 , 0 , DEF_BUTTON_W , DEF_BUTTON_H )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+---------------------------------------------------------------------+
//| CButton::Конструктор параметрический. Строит кнопку в указанном окне|
2026-03-29 13:06:34 +07:00
//| указанного графика с указанными текстом, координатами и размерами |
2026-03-28 03:09:22 +07:00
//+---------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
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 )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Устанавливаем состояние по умолчанию
2026-03-28 03:09:22 +07:00
this . SetState ( ELEMENT_STATE_DEF ) ;
2026-03-28 12:12:49 +07:00
//--- Фон и передний план - непрозрачные
2026-03-28 03:09:22 +07:00
this . SetAlpha ( 255 ) ;
2026-03-28 12:12:49 +07:00
//--- Смещение текста от левого края кнопки по умолчанию
this . m_text_x = 2 ;
//--- Автоповтор нажатий отключен
this . m_autorepeat_flag = false ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| CButton::Сравнение двух объектов |
//+------------------------------------------------------------------+
int CButton : : Compare ( const CObject * node , const int mode = 0 ) const
{
2026-03-28 12:12:49 +07:00
return CLabel : : Compare ( node , mode ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| Обработчик события таймера |
//+------------------------------------------------------------------+
void CButton : : TimerEventHandler ( void )
{
if ( this . m_autorepeat_flag )
this . m_autorepeat . Process ( ) ;
}
//+------------------------------------------------------------------+
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
//| Класс двухпозиционной кнопки |
//+------------------------------------------------------------------+
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 ) ; }
2026-03-28 12:12:49 +07:00
//--- Обработчик событий нажатий кнопок мышки (Press)
virtual void OnPressEvent ( const int id , const long lparam , const double dparam , const string sparam ) ;
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
2026-03-28 03:09:22 +07:00
virtual void InitColors ( void ) ;
//--- Конструкторы/деструктор
CButtonTriggered ( void ) ;
2026-03-28 12:12:49 +07:00
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 ) ;
2026-03-28 03:09:22 +07:00
~ CButtonTriggered ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CButtonTriggered::Конструктор по умолчанию. |
//| Строит кнопку в главном окне текущего графика |
//| в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
CButtonTriggered : : CButtonTriggered ( void ) : CButton ( " Button " , " Button " , : : ChartID ( ) , 0 , 0 , 0 , DEF_BUTTON_W , DEF_BUTTON_H )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| CButtonTriggered::Конструктор параметрический. |
//| Строит кнопку в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
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 )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| CButtonTriggered::Инициализация |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
void CButtonTriggered ::Init ( const string text )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализируем цвета по умолчанию
this . InitColors ( ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| CButtonTriggered::Сравнение двух объектов |
//+------------------------------------------------------------------+
int CButtonTriggered : : Compare ( const CObject * node , const int mode = 0 ) const
{
return CButton : : Compare ( node , mode ) ;
}
//+------------------------------------------------------------------+
2026-03-28 03:09:22 +07:00
//| 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 ) ; }
2026-03-28 12:12:49 +07:00
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
virtual void InitColors ( void ) { }
2026-03-28 03:09:22 +07:00
//--- Конструкторы/деструктор
CButtonArrowUp ( void ) ;
2026-03-28 12:12:49 +07:00
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 ) ;
2026-03-28 03:09:22 +07:00
~ CButtonArrowUp ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CButtonArrowUp::Конструктор по умолчанию. |
//| Строит кнопку в главном окне текущего графика |
//| в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
CButtonArrowUp : : CButtonArrowUp ( void ) : CButton ( " Arrow Up Button " , " " , : : ChartID ( ) , 0 , 0 , 0 , DEF_BUTTON_W , DEF_BUTTON_H )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| CButtonArrowUp::Конструктор параметрический. |
//| Строит кнопку в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
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 )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализируем цвета по умолчанию
2026-03-28 03:09:22 +07:00
this . InitColors ( ) ;
2026-03-28 12:12:49 +07:00
//--- Устанавливаем смещение и размеры области изображенеия
2026-03-28 03:09:22 +07:00
this . SetImageBound ( 1 , 1 , this . Height ( ) -2 , this . Height ( ) -2 ) ;
2026-03-28 12:12:49 +07:00
//--- Инициализируем счётчики автоповтора
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 ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| 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 ) ; }
2026-03-28 12:12:49 +07:00
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
virtual void InitColors ( void ) { }
2026-03-28 03:09:22 +07:00
//--- Конструкторы/деструктор
CButtonArrowDown ( void ) ;
2026-03-28 12:12:49 +07:00
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 ) ;
2026-03-28 03:09:22 +07:00
~ CButtonArrowDown ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CButtonArrowDown::Конструктор по умолчанию. |
//| Строит кнопку в главном окне текущего графика |
//| в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
CButtonArrowDown : : CButtonArrowDown ( void ) : CButton ( " Arrow Up Button " , " " , : : ChartID ( ) , 0 , 0 , 0 , DEF_BUTTON_W , DEF_BUTTON_H )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| CButtonArrowDown::Конструктор параметрический. |
//| Строит кнопку в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
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 )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализируем цвета по умолчанию
2026-03-28 03:09:22 +07:00
this . InitColors ( ) ;
2026-03-28 12:12:49 +07:00
//--- Устанавливаем смещение и размеры области изображенеия
2026-03-28 03:09:22 +07:00
this . SetImageBound ( 1 , 1 , this . Height ( ) -2 , this . Height ( ) -2 ) ;
2026-03-28 12:12:49 +07:00
//--- Инициализируем счётчики автоповтора
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 ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| 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 ) ; }
2026-03-28 12:12:49 +07:00
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
virtual void InitColors ( void ) { }
2026-03-28 03:09:22 +07:00
//--- Конструкторы/деструктор
CButtonArrowLeft ( void ) ;
2026-03-28 12:12:49 +07:00
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 ) ;
2026-03-28 03:09:22 +07:00
~ CButtonArrowLeft ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CButtonArrowLeft::Конструктор по умолчанию. |
//| Строит кнопку в главном окне текущего графика |
//| в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
CButtonArrowLeft : : CButtonArrowLeft ( void ) : CButton ( " Arrow Up Button " , " " , : : ChartID ( ) , 0 , 0 , 0 , DEF_BUTTON_W , DEF_BUTTON_H )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| CButtonArrowLeft::Конструктор параметрический. |
//| Строит кнопку в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
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 )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| 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::Рисует внешний вид |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
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 ) ; }
2026-03-28 12:12:49 +07:00
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
virtual void InitColors ( void ) { }
2026-03-28 03:09:22 +07:00
//--- Конструкторы/деструктор
CButtonArrowRight ( void ) ;
2026-03-28 12:12:49 +07:00
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 ) ;
2026-03-28 03:09:22 +07:00
~ CButtonArrowRight ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CButtonArrowRight::Конструктор по умолчанию. |
//| Строит кнопку в главном окне текущего графика |
//| в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
CButtonArrowRight : : CButtonArrowRight ( void ) : CButton ( " Arrow Up Button " , " " , : : ChartID ( ) , 0 , 0 , 0 , DEF_BUTTON_W , DEF_BUTTON_H )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| CButtonArrowRight::Конструктор параметрический. |
//| Строит кнопку в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
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 )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализируем цвета по умолчанию
2026-03-28 03:09:22 +07:00
this . InitColors ( ) ;
2026-03-28 12:12:49 +07:00
//--- Устанавливаем смещение и размеры области изображенеия
2026-03-28 03:09:22 +07:00
this . SetImageBound ( 1 , 1 , this . Height ( ) -2 , this . Height ( ) -2 ) ;
2026-03-28 12:12:49 +07:00
//--- Инициализируем счётчики автоповтора
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 ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| 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 ) ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| Класс подсказки |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
class CVisualHint : public CButton
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:36:14 +07:00
protected :
ENUM_HINT_TYPE m_hint_type ; // Тип подсказки
//--- Рисует (1) тултип, (2) горизонтальную, (3) вертикальную стрелку,
2026-03-29 15:13:53 +07:00
//--- стрелки (4) сверху-лево --- низ-право, (5) снизу-лево --- верх-право,
//--- стрелки смещения по (6) горизонтали, (7) вертикали
2026-03-28 12:36:14 +07:00
void DrawTooltip ( void ) ;
void DrawArrHorz ( void ) ;
void DrawArrVert ( void ) ;
void DrawArrNWSE ( void ) ;
void DrawArrNESW ( void ) ;
2026-03-29 15:13:53 +07:00
void DrawArrShiftHorz ( void ) ;
void DrawArrShiftVert ( void ) ;
2026-03-28 12:36:14 +07:00
//--- Инициализация цветов для типа подсказки (1) Tooltip, (2) стрелки
void InitColorsTooltip ( void ) ;
void InitColorsArrowed ( void ) ;
2026-03-28 03:09:22 +07:00
public :
2026-03-28 12:36:14 +07:00
//--- (1) Устанавливает, (2) возвращает тип подсказки
void SetHintType ( const ENUM_HINT_TYPE type ) ;
ENUM_HINT_TYPE HintType ( void ) const { return this . m_hint_type ; }
2026-03-28 03:09:22 +07:00
//--- Рисует внешний вид
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 ) ; }
2026-03-28 12:36:14 +07:00
virtual int Type ( void ) const { return ( ELEMENT_TYPE_HINT ) ; }
2026-03-28 12:12:49 +07:00
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
2026-03-28 03:09:22 +07:00
virtual void InitColors ( void ) ;
//--- Конструкторы/деструктор
2026-03-28 12:36:14 +07:00
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 ) { }
2026-03-28 03:09:22 +07:00
} ;
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| CVisualHint::Конструктор по умолчанию. |
//| Строит элемент в главном окне текущего графика |
2026-03-28 03:09:22 +07:00
//| в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
CVisualHint : : CVisualHint ( void ) : CButton ( " HintObject " , " " , : : ChartID ( ) , 0 , 0 , 0 , DEF_BUTTON_W , DEF_BUTTON_H )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| CVisualHint::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
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 )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| 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 )
{
2026-03-29 15:13:53 +07:00
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 ;
2026-03-28 12:36:14 +07:00
}
//--- Устанавливаем смещение и размеры области изображенеия,
//--- инициализируем цвета по типу подсказки
this . SetImageBound ( 0 , 0 , this . Width ( ) , this . Height ( ) ) ;
this . InitColors ( ) ;
}
//+------------------------------------------------------------------+
//| CVisualHint::Рисует внешний вид |
//+------------------------------------------------------------------+
void CVisualHint : : Draw ( const bool chart_redraw )
{
//--- В зависимости от типа подсказки вызываем соответствующий метод рисования
switch ( this . m_hint_type )
{
2026-03-29 15:13:53 +07:00
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 ;
2026-03-28 12:36:14 +07:00
}
//--- Если указано - обновляем график
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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//+------------------------------------------------------------------+
//| Класс элемента управления 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 с размерами по умолчанию |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
CCheckBox : : CCheckBox ( void ) : CButtonTriggered ( " CheckBox " , " CheckBox " , : : ChartID ( ) , 0 , 0 , 0 , DEF_BUTTON_W , DEF_BUTTON_H )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| CCheckBox::Конструктор параметрический. |
2026-03-28 12:12:49 +07:00
//| Строит элемент в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
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 )
2026-03-28 03:09:22 +07:00
{
//--- Устанавливаем цвета по умолчанию, прозрачность для фона и переднего плана,
//--- и координаты и границы области рисунка значка кнопки
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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| CCheckBox::Сравнение двух объектов |
//+------------------------------------------------------------------+
int CCheckBox : : Compare ( const CObject * node , const int mode = 0 ) const
{
return CButtonTriggered : : Compare ( node , mode ) ;
}
//+------------------------------------------------------------------+
2026-03-28 03:09:22 +07:00
//| 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 ) ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| Класс элемента управления Radio Button |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
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 ) ; }
2026-03-28 12:12:49 +07:00
//--- Инициализация (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 ) ;
2026-03-28 03:09:22 +07:00
//--- Конструкторы/деструктор
CRadioButton ( void ) ;
2026-03-28 12:12:49 +07:00
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 ) ;
2026-03-28 03:09:22 +07:00
~ CRadioButton ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CRadioButton::Конструктор по умолчанию. |
2026-03-28 12:12:49 +07:00
//| Строит элемент в главном окне текущего графика |
2026-03-28 03:09:22 +07:00
//| в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
CRadioButton : : CRadioButton ( void ) : CCheckBox ( " RadioButton " , " " , : : ChartID ( ) , 0 , 0 , 0 , DEF_BUTTON_H , DEF_BUTTON_H )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
//--- Инициализация
this .Init ( " " ) ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| CRadioButton::Конструктор параметрический. |
2026-03-28 12:12:49 +07:00
//| Строит элемент в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
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 )
2026-03-28 03:09:22 +07:00
{
2026-03-28 12:12:49 +07:00
return ;
2026-03-28 03:09:22 +07:00
}
//+------------------------------------------------------------------+
//| 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 ) ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| Класс панели |
//+------------------------------------------------------------------+
class CPanel : public CLabel
{
private :
CElementBase m_temp_elm ; // Временный объект для поиска элементов
CBound m_temp_bound ; // Временный объект для поиска областей
protected :
2026-03-29 13:06:34 +07:00
CListElm m_list_elm ; // Список прикреплённых элементов
CListElm m_list_bounds ; // Список областей
2026-03-28 12:12:49 +07:00
//--- Добавляет новый элемент в список
bool AddNewElement ( CElementBase * element ) ;
public :
//--- Возвращает указатель на список (1) прикреплённых элементов, (2) областей
2026-03-29 13:06:34 +07:00
CListElm * GetListAttachedElements ( void ) { return & this . m_list_elm ; }
CListElm * GetListBounds ( void ) { return & this . m_list_bounds ; }
2026-03-28 12:36:14 +07:00
//--- Возвращает прикреплённый элемент по (1) индексу в списке, (2) идентификатору, (3) назначенному имени объекта
2026-03-28 12:12:49 +07:00
CElementBase * GetAttachedElementAt ( const uint index ) { return this . m_list_elm . GetNodeAtIndex ( index ) ; }
CElementBase * GetAttachedElementByID ( const int id ) ;
CElementBase * GetAttachedElementByName ( const string name ) ;
2026-03-29 15:55:22 +07:00
//--- Возвращает количество (1) областей, (2) присоединённых элементов,
int BoundsTotal ( void ) const { return this . m_list_bounds . Total ( ) ; }
2026-03-29 15:13:53 +07:00
int AttachedElementsTotal ( void ) const { return this . m_list_elm . Total ( ) ; }
2026-03-28 12:12:49 +07:00
//--- Возвращает область по (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 ) ;
2026-03-29 15:13:53 +07:00
//--- Удаляет указанный элемент
bool DeleteElement ( const int index ) { return this . m_list_elm . Delete ( index ) ; }
2026-03-28 12:12:49 +07:00
2026-03-29 15:13:53 +07:00
//--- (1) Создаёт и добавляет в список новую область, (2) удаляет указанную область
2026-03-28 12:12:49 +07:00
CBound * InsertNewBound ( const string name , const int dx , const int dy , const int w , const int h ) ;
2026-03-29 15:13:53 +07:00
bool DeleteBound ( const int index ) { return this . m_list_bounds . Delete ( index ) ; }
2026-03-28 12:12:49 +07:00
2026-03-29 15:13:53 +07:00
//--- (1) Назначает объект на указанную область, (2) отменяет назначение объекта с указанной области
bool AssignObjectToBound ( const int bound , CBaseObj * object ) ;
bool UnassignObjectFromBound ( const int bound ) ;
2026-03-28 12:36:14 +07:00
//--- Изменяет размеры объекта
virtual bool ResizeW ( const int w ) ;
virtual bool ResizeH ( const int h ) ;
virtual bool Resize ( const int w , const int h ) ;
2026-03-28 12:12:49 +07:00
//--- Рисует внешний вид
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 ) ;
2026-03-28 12:36:14 +07:00
//--- Устанавливает одновременно координаты и размеры элемента
virtual bool MoveXYWidthResize ( const int x , const int y , const int w , const int h ) ;
2026-03-28 12:12:49 +07:00
//--- (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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| 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 ) ;
}
2026-03-29 13:06:34 +07:00
//--- Получаем указатель на базовый элемент и, если он есть, и его тип - контейнер,
//--- проверяем отношение размеров текущего элемента относительно размеров контейнера
//--- для отображения полос прокрутки в контейнере при необходимости
2026-03-29 15:55:22 +07:00
if ( this . GetContainer ( ) ! = NULL & & this . GetContainer ( ) . Type ( ) = = ELEMENT_TYPE_CONTAINER )
2026-03-29 15:13:53 +07:00
{
2026-03-29 15:55:22 +07:00
CContainer * base = this . GetContainer ( ) ;
base . CheckElementSizes ( & this ) ;
2026-03-29 15:13:53 +07:00
}
2026-03-29 13:06:34 +07:00
//--- В цикле по присоединённым элементам обрезаем каждый элемент по границам контейнера
int total = this . m_list_elm . Total ( ) ;
for ( int i = 0 ; i < total ; i + + )
{
CElementBase * elm = this . GetAttachedElementAt ( i ) ;
if ( elm ! = NULL )
elm . ObjectTrim ( ) ;
}
//--- Всё успешно
2026-03-28 12:36:14 +07:00
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 ) ;
}
2026-03-29 13:06:34 +07:00
//--- Получаем указатель на базовый элемент и, если он есть, и его тип - контейнер,
//--- проверяем отношение размеров текущего элемента относительно размеров контейнера
//--- для отображения полос прокрутки в контейнере при необходимости
2026-03-29 15:55:22 +07:00
if ( this . GetContainer ( ) ! = NULL & & this . GetContainer ( ) . Type ( ) = = ELEMENT_TYPE_CONTAINER )
{
CContainer * base = this . GetContainer ( ) ;
2026-03-29 13:06:34 +07:00
base . CheckElementSizes ( & this ) ;
2026-03-29 15:55:22 +07:00
}
2026-03-29 13:06:34 +07:00
//--- В цикле по присоединённым элементам обрезаем каждый элемент по границам контейнера
int total = this . m_list_elm . Total ( ) ;
for ( int i = 0 ; i < total ; i + + )
{
CElementBase * elm = this . GetAttachedElementAt ( i ) ;
if ( elm ! = NULL )
elm . ObjectTrim ( ) ;
}
//--- Всё успешно
2026-03-28 12:36:14 +07:00
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 ) ;
}
2026-03-29 13:06:34 +07:00
//--- Получаем указатель на базовый элемент и, если он есть, и его тип - контейнер,
//--- проверяем отношение размеров текущего элемента относительно размеров контейнера
//--- для отображения полос прокрутки в контейнере при необходимости
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 ( ) ;
}
//--- Всё успешно
2026-03-28 12:36:14 +07:00
return true ;
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| CPanel::Рисует внешний вид |
//+------------------------------------------------------------------+
void CPanel : : Draw ( const bool chart_redraw )
{
2026-03-28 12:36:14 +07:00
//--- Заливаем объект цветом фона
2026-03-28 12:12:49 +07:00
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 ) ) ;
2026-03-29 13:06:34 +07:00
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 ) ;
2026-03-28 12:12:49 +07:00
//--- Обновляем канвас фона без перерисовки графика
this . m_background . Update ( false ) ;
//--- Рисуем элементы списка
for ( int i = 0 ; i < this . m_list_elm . Total ( ) ; i + + )
{
CElementBase * elm = this . GetAttachedElementAt ( i ) ;
2026-03-28 12:36:14 +07:00
if ( elm ! = NULL & & elm . Type ( ) ! = ELEMENT_TYPE_SCROLLBAR_H & & elm . Type ( ) ! = ELEMENT_TYPE_SCROLLBAR_V )
2026-03-28 12:12:49 +07:00
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 ;
}
2026-03-29 15:13:53 +07:00
//--- Запоминаем метод сортировки списка
int sort_mode = this . m_list_elm . SortMode ( ) ;
2026-03-28 12:12:49 +07:00
//--- Устанавливаем списку флаг сортировки по идентификатору
this . m_list_elm .Sort ( ELEMENT_SORT_BY_ID ) ;
2026-03-29 15:13:53 +07:00
//--- Если такого элемента нет в списке,
2026-03-28 12:12:49 +07:00
if ( this . m_list_elm . Search ( element ) = = NULL )
2026-03-29 15:13:53 +07:00
{
//--- возвращаем списку изначальную сортировку и возвращаем результат его добавления в список
this . m_list_elm .Sort ( sort_mode ) ;
2026-03-28 12:12:49 +07:00
return ( this . m_list_elm . Add ( element ) > -1 ) ;
2026-03-29 15:13:53 +07:00
}
//--- Возвращаем списку изначальную сортировку
this . m_list_elm .Sort ( sort_mode ) ;
2026-03-28 12:12:49 +07:00
//--- Элемент с таким идентификатором уже есть в списке - возвращаем 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 )
{
2026-03-29 15:13:53 +07:00
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 ; // Объект визуального представления строки таблицы
2026-03-29 15:55:22 +07:00
case ELEMENT_TYPE_TABLE_CAPTION_VIEW : element = new CCaptionView ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Базовый объект заголовка (View)
2026-03-29 15:13:53 +07:00
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 ; // Объект визуального представления заголовка столбца таблицы
2026-03-29 15:55:22 +07:00
case ELEMENT_TYPE_TABLE_ROW_CAPTION_VIEW : element = new CRowCaptionView ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Объект визуального представления заголовка строки таблицы
2026-03-29 15:13:53 +07:00
case ELEMENT_TYPE_TABLE_HEADER_VIEW : element = new CTableHeaderView ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Объект визуального представления заголовка таблицы
2026-03-29 15:55:22 +07:00
case ELEMENT_TYPE_TABLE_ROWS_HEADER_VIEW : element = new CTableRowsHeaderView ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Объект визуального представления заголовка строк таблицы
2026-03-29 15:13:53 +07:00
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 ;
2026-03-28 12:12:49 +07:00
}
2026-03-29 13:06:34 +07:00
2026-03-28 12:12:49 +07:00
//--- Если новый элемент не создан - сообщаем об этом и возвращаем 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 ;
//--- Если горизонтальная полоса прокрутки видима,
2026-03-28 12:36:14 +07:00
if ( container_obj . ScrollBarHorzIsVisible ( ) )
2026-03-28 12:12:49 +07:00
{
//--- получаем указатель на горизонтальный скроллбар и переносим его на передний план
CScrollBarH * sbh = container_obj . GetScrollBarH ( ) ;
if ( sbh ! = NULL )
sbh . BringToTop ( false ) ;
}
//--- Если вертикальная полоса прокрутки видима,
2026-03-28 12:36:14 +07:00
if ( container_obj . ScrollBarVertIsVisible ( ) )
2026-03-28 12:12:49 +07:00
{
//--- получаем указатель на вертикальный скроллбар и переносим его на передний план
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 ) ;
2026-03-29 15:13:53 +07:00
//--- Запоминаем метод сортировки списка
int sort_mode = this . m_list_bounds . SortMode ( ) ;
2026-03-29 13:06:34 +07:00
//--- Устанавливаем списку флаг сортировки по наименованию
this . m_list_bounds .Sort ( ELEMENT_SORT_BY_NAME ) ;
2026-03-28 12:12:49 +07:00
if ( this . m_list_bounds . Search ( & this . m_temp_bound ) ! = NULL )
{
2026-03-29 15:13:53 +07:00
//--- Возвращаем списку изначальную сортировку, сообщаем, что такой объект уже существует и возвращаем NULL
this . m_list_bounds .Sort ( sort_mode ) ;
2026-03-28 12:12:49 +07:00
: : PrintFormat ( " %s: Error. An area named \" %s \" is already in the list " , __FUNCTION__ , name ) ;
return NULL ;
}
2026-03-29 15:13:53 +07:00
//--- Возвращаем списку изначальную сортировку
this . m_list_bounds .Sort ( sort_mode ) ;
2026-03-28 12:12:49 +07:00
//--- Создаём новый объект-область; при неудаче - сообщаем об этом и возвращаем NULL
CBound * bound = new CBound ( dx , dy , w , h ) ;
if ( bound = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to create CBound object " , __FUNCTION__ ) ;
return NULL ;
}
2026-03-29 15:13:53 +07:00
//--- Устанавливаем имя области и идентификатор, и возвращаем указатель на объект
bound . SetName ( name ) ;
bound . SetID ( this . m_list_bounds . Total ( ) ) ;
2026-03-28 12:12:49 +07:00
//--- Если новый объект не удалось добавить в список - сообщаем об этом, удаляем объект и возвращаем 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 ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 ;
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| Выводит в журнал описание объекта |
//+------------------------------------------------------------------+
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 )
2026-03-28 12:36:14 +07:00
res & = elm . Move ( elm . X ( ) + delta_x , elm . Y ( ) + delta_y ) ;
2026-03-28 12:12:49 +07:00
}
//--- Возвращаем результат перемещения всех привязанных элементов
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 ;
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| 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 ;
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| 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 )
{
2026-03-28 12:36:14 +07:00
//--- Если объект уже видимый, или не должен отображаться в контейнере - уходим
if ( ! this . m_hidden | | ! this . m_visible_in_container )
2026-03-28 12:12:49 +07:00
return ;
//--- Отображаем панель
CCanvasBase : : Show ( false ) ;
//--- Отображаем прикреплённые объекты
for ( int i = 0 ; i < this . m_list_elm . Total ( ) ; i + + )
{
CElementBase * elm = this . GetAttachedElementAt ( i ) ;
if ( elm ! = NULL )
2026-03-28 12:36:14 +07:00
{
if ( elm . Type ( ) = = ELEMENT_TYPE_SCROLLBAR_H | | elm . Type ( ) = = ELEMENT_TYPE_SCROLLBAR_V )
continue ;
2026-03-28 12:12:49 +07:00
elm . Show ( false ) ;
2026-03-28 12:36:14 +07:00
}
2026-03-28 12:12:49 +07:00
}
//--- Если указано - перерисовываем график
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 )
2026-03-28 12:36:14 +07:00
{
if ( elm . Type ( ) = = ELEMENT_TYPE_SCROLLBAR_H | | elm . Type ( ) = = ELEMENT_TYPE_SCROLLBAR_V )
continue ;
2026-03-29 13:06:34 +07:00
elm . ObjectTrim ( ) ;
2026-03-29 15:13:53 +07:00
elm . BringToTop ( false ) ;
2026-03-28 12:36:14 +07:00
}
2026-03-28 12:12:49 +07:00
}
//--- Если указано - перерисовываем график
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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
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 ) ;
2026-03-28 12:36:14 +07:00
//--- Элемент не обрезается по границам контейнера
this . m_trim_flag = false ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| 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 ( ) ;
2026-03-29 15:13:53 +07:00
//--- Получаем имя главного объекта в иерархии по значению в sparam
string array_names [ ] ;
string name_main = ( GetElementNames ( sparam , " _ " , array_names ) > 0 ? array_names [ 0 ] : " " ) ;
//--- Если главный объект в иерархии не наш - уходим
if ( : : StringFind ( this . NameFG ( ) , name_main ) ! = 0 )
return ;
2026-03-28 12:12:49 +07:00
//--- Если для ползунка не установлен флаг перемещаемости, либо указатель на базовый объект не получен - уходим
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 ( ) ) ;
//--- Иначе, если ползунок в пределах своей области - смещаем его на величину смещения
2026-03-28 12:36:14 +07:00
else
{
this . ShiftX ( dx ) ;
}
2026-03-28 12:12:49 +07:00
//--- Рассчитываем позицию ползунка
int thumb_pos = this . X ( ) - base_left ;
2026-03-28 12:36:14 +07:00
//--- Получаем координаты курсора
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 ) ;
2026-03-28 12:12:49 +07:00
//--- Отправляем пользовательское событие на график с позицией ползунка в 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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
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 ) ;
2026-03-28 12:36:14 +07:00
//--- Элемент не обрезается по границам контейнера
this . m_trim_flag = false ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| 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 ( ) ;
2026-03-29 15:13:53 +07:00
//--- Получаем имя главного объекта в иерархии по значению в sparam
string array_names [ ] ;
string name_main = ( GetElementNames ( sparam , " _ " , array_names ) > 0 ? array_names [ 0 ] : " " ) ;
//--- Если главный объект в иерархии не наш - уходим
if ( : : StringFind ( this . NameFG ( ) , name_main ) ! = 0 )
return ;
2026-03-28 12:12:49 +07:00
//--- Если для ползунка не установлен флаг перемещаемости, либо указатель на базовый объект не получен - уходим
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 ( ) ) ;
//--- Иначе, если ползунок в пределах своей области - смещаем его на величину смещения
2026-03-28 12:36:14 +07:00
else
{
this . ShiftY ( dy ) ;
}
2026-03-28 12:12:49 +07:00
//--- Рассчитываем позицию ползунка
int thumb_pos = this . Y ( ) - base_top ;
2026-03-28 12:36:14 +07:00
//--- Получаем координаты курсора
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 ) ;
2026-03-28 12:12:49 +07:00
//--- Отправляем пользовательское событие на график с позицией ползунка в 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 ; // Ползунок скроллбара
2026-03-28 12:36:14 +07:00
2026-03-28 12:12:49 +07:00
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 ;
2026-03-28 12:36:14 +07:00
//--- Устанавливает позицию ползунка
bool SetThumbPosition ( const int pos ) const { return ( this . m_thumb ! = NULL ? this . m_thumb . MoveX ( pos ) : false ) ; }
2026-03-28 12:12:49 +07:00
//--- Изменяет размер ползунка
bool SetThumbSize ( const uint size ) const { return ( this . m_thumb ! = NULL ? this . m_thumb . ResizeW ( size ) : false ) ; }
//--- Изменяет ширину объекта
virtual bool ResizeW ( const int size ) ;
2026-03-28 12:36:14 +07:00
//--- Устанавливает флаг видимости в контейнере
virtual void SetVisibleInContainer ( const bool flag ) ;
2026-03-29 13:06:34 +07:00
//--- Устанавливает флаг обрезки по границам контейнера
virtual void SetTrimmered ( const bool flag ) ;
2026-03-28 12:36:14 +07:00
2026-03-28 12:12:49 +07:00
//--- Рисует внешний вид
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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
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 ) ;
2026-03-28 12:36:14 +07:00
//--- Запрещаем самостоятельную перерисовку графика
2026-03-28 12:12:49 +07:00
this . m_thumb . SetChartRedrawFlag ( false ) ;
2026-03-29 13:06:34 +07:00
//--- Изначально в контейнере не отображается и не обрезается по его границам
this . SetVisibleInContainer ( false ) ;
this . SetTrimmered ( false ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| 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
{
2026-03-29 13:06:34 +07:00
int pos = ( this . m_thumb ! = NULL ? this . m_thumb . X ( ) - this . TrackBegin ( ) - this . X ( ) : 0 ) ;
return ( pos < 0 ? 0 : pos ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| 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 ;
2026-03-28 12:36:14 +07:00
//--- Устанавливает позицию ползунка
bool SetThumbPosition ( const int pos ) const { return ( this . m_thumb ! = NULL ? this . m_thumb . MoveY ( pos ) : false ) ; }
2026-03-28 12:12:49 +07:00
//--- Изменяет размер ползунка
bool SetThumbSize ( const uint size ) const { return ( this . m_thumb ! = NULL ? this . m_thumb . ResizeH ( size ) : false ) ; }
//--- Изменяет высоту объекта
virtual bool ResizeH ( const int size ) ;
2026-03-28 12:36:14 +07:00
//--- Устанавливает флаг видимости в контейнере
virtual void SetVisibleInContainer ( const bool flag ) ;
2026-03-29 13:06:34 +07:00
//--- Устанавливает флаг обрезки по границам контейнера
virtual void SetTrimmered ( const bool flag ) ;
2026-03-28 12:36:14 +07:00
2026-03-28 12:12:49 +07:00
//--- Рисует внешний вид
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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
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 ) ;
2026-03-29 13:06:34 +07:00
//--- Изначально в контейнере не отображается и не обрезается по его границам
this . SetVisibleInContainer ( false ) ;
this . SetTrimmered ( false ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| 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
{
2026-03-29 13:06:34 +07:00
int pos = ( this . m_thumb ! = NULL ? this . m_thumb . Y ( ) - this . TrackBegin ( ) - this . Y ( ) : 0 ) ;
return ( pos < 0 ? 0 : pos ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| 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 ; // Флаг видимости вертикальной полосы прокрутки
2026-03-28 12:36:14 +07:00
int m_init_border_size_top ; // Изначальный размер рамки сверху
int m_init_border_size_bottom ; // Изначальный размер рамки снизу
int m_init_border_size_left ; // Изначальный размер рамки слева
int m_init_border_size_right ; // Изначальный размер рамки справа
2026-03-28 12:12:49 +07:00
//--- Возвращает тип элемента, отправившего событие
ENUM_ELEMENT_TYPE GetEventElementType ( const string name ) ;
protected :
CScrollBarH * m_scrollbar_h ; // Указатель на горизонтальную полосу прокрутки
CScrollBarV * m_scrollbar_v ; // Указатель на вертикальную полосу прокрутки
2026-03-28 12:36:14 +07:00
//--- Обработчик перетаскивания граней и углов элемента
virtual void ResizeActionDragHandler ( const int x , const int y ) ;
2026-03-28 12:12:49 +07:00
2026-03-29 13:06:34 +07:00
public :
2026-03-28 12:12:49 +07:00
//--- Проверяет размеры элемента для отображения полос прокрутки
void CheckElementSizes ( CElementBase * element ) ;
2026-03-29 13:06:34 +07:00
protected :
2026-03-28 12:12:49 +07:00
//--- Рассчитывает и возвращает размер (1) ползунка, (2) полный, (3) рабочий размер трека горизонтального скроллбара
2026-03-28 12:36:14 +07:00
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 ( ) ) ; }
2026-03-28 12:12:49 +07:00
//--- Рассчитывает и возвращает размер (1) ползунка, (2) полный, (3) рабочий размер трека вертикального скроллбара
2026-03-28 12:36:14 +07:00
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 ( ) ) ; }
2026-03-28 12:12:49 +07:00
//--- Размер видимой области содержимого по (1) горизонтали, (2) вертикали
2026-03-28 12:36:14 +07:00
int ContentVisibleHorz ( void ) const { return int ( this . Width ( ) - this . BorderWidthLeft ( ) - this . BorderWidthRight ( ) ) ; }
int ContentVisibleVert ( void ) const { return int ( this . Height ( ) - this . BorderWidthTop ( ) - this . BorderWidthBottom ( ) ) ; }
2026-03-28 12:12:49 +07:00
//--- Полный размер содержимого по (1) горизонтали, (2) вертикали
2026-03-28 12:36:14 +07:00
int ContentSizeHorz ( void ) ;
int ContentSizeVert ( void ) ;
2026-03-28 12:12:49 +07:00
//--- Позиция содержимого по (1) горизонтали, (2) вертикали
2026-03-28 12:36:14 +07:00
int ContentPositionHorz ( void ) ;
int ContentPositionVert ( void ) ;
2026-03-28 12:12:49 +07:00
//--- Рассчитывает и возвращает величину смещения содержимого по (1) горизонтали, (2) вертикали в зависимости от положения ползунка
2026-03-28 12:36:14 +07:00
int CalculateContentOffsetHorz ( const uint thumb_position ) ;
int CalculateContentOffsetVert ( const uint thumb_position ) ;
2026-03-28 12:12:49 +07:00
//--- Рассчитывает и возвращает величину смещения ползунка по (1) горизонтали, (2) вертикали в зависимости от положения контента
2026-03-28 12:36:14 +07:00
int CalculateThumbOffsetHorz ( const uint content_position ) ;
int CalculateThumbOffsetVert ( const uint content_position ) ;
2026-03-28 12:12:49 +07:00
//--- Смещает содержимое по (1) горизонтали, (2) вертикали на указанное значение
2026-03-28 12:36:14 +07:00
bool ContentShiftHorz ( const int value ) ;
bool ContentShiftVert ( const int value ) ;
2026-03-28 12:12:49 +07:00
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) вертикального скроллбара
2026-03-28 12:36:14 +07:00
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 ) ; }
2026-03-28 12:12:49 +07:00
//--- Создаёт и добавляет (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 ) ;
2026-03-28 12:36:14 +07:00
//--- (1) Отображает объект на всех периодах графика, (2) помещает объект на передний план
virtual void Show ( const bool chart_redraw ) ;
virtual void BringToTop ( const bool chart_redraw ) ;
2026-03-28 12:12:49 +07:00
//--- Рисует внешний вид
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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
2026-03-29 13:06:34 +07:00
//| с указанными текстом, координатами и размерами |
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
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 ) ;
2026-03-28 12:36:14 +07:00
//--- Запоминаем установленную ширину рамки с каждой стороны
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 ( ) ;
2026-03-28 12:12:49 +07:00
//--- Создаём горизонтальный скроллбар
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 ;
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| CContainer::Рисует внешний вид |
//+------------------------------------------------------------------+
void CContainer : : Draw ( const bool chart_redraw )
{
//--- Рисуем внешний вид
CPanel : : Draw ( false ) ;
2026-03-28 12:36:14 +07:00
2026-03-28 12:12:49 +07:00
//--- Если прокрутка разрешена
if ( this . m_scroll_flag )
{
//--- Если оба скроллбара видимы
if ( this . m_visible_scrollbar_h & & this . m_visible_scrollbar_v )
{
2026-03-28 12:36:14 +07:00
//--- Получаем указатель на горизонтальную полосу прокрутки и берём цвет её фона
2026-03-28 12:12:49 +07:00
CScrollBarH * scroll_bar = this . GetScrollBarH ( ) ;
color clr = ( scroll_bar ! = NULL ? scroll_bar . BackColor ( ) : clrWhiteSmoke ) ;
//--- Устанавливаем координаты, в которых будет нарисован закрашенный прямоугольник
2026-03-28 12:36:14 +07:00
int x1 = this . Width ( ) - DEF_SCROLLBAR_TH -1 ;
int y1 = this . Height ( ) - DEF_SCROLLBAR_TH -1 ;
2026-03-28 12:12:49 +07:00
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 \n To add multiple elements, use the panel " , __FUNCTION__ ) ;
return NULL ;
}
//--- Создаём и добавляем новый элемент при помощи метода родительского класса
//--- Элемент помещается в координаты 0,0 независимо от указанных в параметрах
2026-03-29 13:06:34 +07:00
CElementBase * elm = CPanel : : InsertNewElement ( type , text , user_name , dx , dy , w , h ) ;
2026-03-28 12:12:49 +07:00
//--- Проверяем размеры элемента для отображения полос прокрутки
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 \n To 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 )
{
2026-03-28 12:36:14 +07:00
//--- Если передан пустой элемент, или прокрутка запрещена, или скроллбары не созданы - уходим
if ( element = = NULL | | ! this . m_scroll_flag | | this . m_scrollbar_h = = NULL | | this . m_scrollbar_v = = NULL )
2026-03-28 12:12:49 +07:00
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 ;
//--- Если ширина элемента больше ширины видимой области контейнера -
//--- устанавливаем флаг отображения горизонтальной полосы прокрутки
2026-03-28 12:36:14 +07:00
//--- и флаг отображения в контейнере
if ( element . Width ( ) > this . ContentVisibleHorz ( ) )
{
2026-03-28 12:12:49 +07:00
this . m_visible_scrollbar_h = true ;
2026-03-28 12:36:14 +07:00
this . m_scrollbar_h . SetVisibleInContainer ( true ) ;
}
2026-03-28 12:12:49 +07:00
//--- Если высота элемента больше высоты видимой области контейнера -
//--- устанавливаем флаг отображения вертикальной полосы прокрутки
2026-03-28 12:36:14 +07:00
//--- и флаг отображения в контейнере
if ( element . Height ( ) > this . ContentVisibleVert ( ) )
{
2026-03-28 12:12:49 +07:00
this . m_visible_scrollbar_v = true ;
2026-03-28 12:36:14 +07:00
this . m_scrollbar_v . SetVisibleInContainer ( true ) ;
}
2026-03-28 12:12:49 +07:00
//--- Если обе полосы прокрутки должны быть отображены
if ( this . m_visible_scrollbar_h & & this . m_visible_scrollbar_v )
{
2026-03-28 12:36:14 +07:00
//--- Корректируем размер обеих полос прокрутки на толщину скроллбара и
//--- устанавливаем размеры ползунков под новые размеры треков
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 ( ) ) ;
2026-03-28 12:12:49 +07:00
}
2026-03-28 12:36:14 +07:00
2026-03-28 12:12:49 +07:00
//--- Если горизонтальная полоса прокрутки должна быть показана
if ( this . m_visible_scrollbar_h )
{
//--- Уменьшаем размер видимого окна контейнера снизу на толщину полосы прокрутки + 1 пиксель
this . SetBorderWidthBottom ( this . m_scrollbar_h . Height ( ) + 1 ) ;
//--- Корректируем размер ползунка под новый размер полосы прокрутки и
//--- переносим скроллбар на передний план, делая его при этом видимым
2026-03-28 12:36:14 +07:00
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 ) ;
2026-03-28 12:12:49 +07:00
this . m_scrollbar_h . BringToTop ( false ) ;
}
2026-03-28 12:36:14 +07:00
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 ( ) ) ;
}
2026-03-28 12:12:49 +07:00
//--- Если вертикальная полоса прокрутки должна быть показана
if ( this . m_visible_scrollbar_v )
{
//--- Уменьшаем размер видимого окна контейнера справа на толщину полосы прокрутки + 1 пиксель
this . SetBorderWidthRight ( this . m_scrollbar_v . Width ( ) + 1 ) ;
//--- Корректируем размер ползунка под новый размер полосы прокрутки и
//--- переносим скроллбар на передний план, делая его при этом видимым
2026-03-28 12:36:14 +07:00
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 ) ;
2026-03-28 12:12:49 +07:00
this . m_scrollbar_v . BringToTop ( false ) ;
}
2026-03-28 12:36:14 +07:00
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 ( ) ) ;
}
2026-03-28 12:12:49 +07:00
//--- Если любая из полос прокрутки видима - обрезаем привязанный элемент по новым размерам видимой области
if ( this . m_visible_scrollbar_h | | this . m_visible_scrollbar_v )
{
2026-03-28 12:36:14 +07:00
element . ObjectTrim ( ) ;
2026-03-28 12:12:49 +07:00
}
}
//+-------------------------------------------------------------------+
//|CContainer::Рассчитывает размер ползунка горизонтального скроллбара|
//+-------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
int CContainer : : ThumbSizeHorz ( void )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
if ( elm = = NULL | | elm . Width ( ) = = 0 | | this . TrackLengthHorz ( ) = = 0 )
2026-03-28 12:12:49 +07:00
return 0 ;
2026-03-28 12:36:14 +07:00
return int ( : : round ( : : fmax ( ( ( double ) this . ContentVisibleHorz ( ) / ( double ) elm . Width ( ) ) * ( double ) this . TrackLengthHorz ( ) , DEF_THUMB_MIN_SIZE ) ) ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| CContainer::Рассчитывает размер ползунка вертикального скроллбара|
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
int CContainer : : ThumbSizeVert ( void )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
if ( elm = = NULL | | elm . Height ( ) = = 0 | | this . TrackLengthVert ( ) = = 0 )
2026-03-28 12:12:49 +07:00
return 0 ;
2026-03-28 12:36:14 +07:00
return int ( : : round ( : : fmax ( ( ( double ) this . ContentVisibleVert ( ) / ( double ) elm . Height ( ) ) * ( double ) this . TrackLengthVert ( ) , DEF_THUMB_MIN_SIZE ) ) ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| CContainer::Полный размер содержимого по горизонтали |
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
int CContainer : : ContentSizeHorz ( void )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
return ( elm ! = NULL ? elm . Width ( ) : 0 ) ;
}
//+------------------------------------------------------------------+
//| CContainer::Полный размер содержимого по вертикали |
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
int CContainer : : ContentSizeVert ( void )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
return ( elm ! = NULL ? elm . Height ( ) : 0 ) ;
}
//+--------------------------------------------------------------------+
//|CContainer::Возвращает позицию содержимого контейнера по горизонтали|
//+--------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
int CContainer : : ContentPositionHorz ( void )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
return ( elm ! = NULL ? elm . X ( ) - this . X ( ) : 0 ) ;
}
//+------------------------------------------------------------------+
//|CContainer::Возвращает позицию содержимого контейнера по вертикали|
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
int CContainer : : ContentPositionVert ( void )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
return ( elm ! = NULL ? elm . Y ( ) - this . Y ( ) : 0 ) ;
}
//+------------------------------------------------------------------+
//| CContainer::Рассчитывает и возвращает величину смещения |
//| содержимого контейнера по горизонтали по положению ползунка |
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
int CContainer : : CalculateContentOffsetHorz ( const uint thumb_position )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
int effective_track_length = this . TrackEffectiveLengthHorz ( ) ;
2026-03-28 12:12:49 +07:00
if ( elm = = NULL | | effective_track_length = = 0 )
return 0 ;
2026-03-28 12:36:14 +07:00
return ( int ) : : round ( ( ( double ) thumb_position / ( double ) effective_track_length ) * ( ( double ) elm . Width ( ) - ( double ) this . ContentVisibleHorz ( ) ) ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| CContainer::Рассчитывает и возвращает величину смещения |
//| содержимого контейнера по вертикали по положению ползунка |
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
int CContainer : : CalculateContentOffsetVert ( const uint thumb_position )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
int effective_track_length = this . TrackEffectiveLengthVert ( ) ;
2026-03-28 12:12:49 +07:00
if ( elm = = NULL | | effective_track_length = = 0 )
return 0 ;
2026-03-28 12:36:14 +07:00
return ( int ) : : round ( ( ( double ) thumb_position / ( double ) effective_track_length ) * ( ( double ) elm . Height ( ) - ( double ) this . ContentVisibleVert ( ) ) ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| CContainer::Рассчитывает и возвращает величину смещения ползунка |
//| по горизонтали в зависимости от положения контента |
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
int CContainer : : CalculateThumbOffsetHorz ( const uint content_position )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
if ( elm = = NULL )
return 0 ;
2026-03-28 12:36:14 +07:00
int value = elm . Width ( ) - this . ContentVisibleHorz ( ) ;
2026-03-28 12:12:49 +07:00
if ( value = = 0 )
return 0 ;
2026-03-28 12:36:14 +07:00
return ( int ) : : round ( ( ( double ) content_position / ( double ) value ) * ( ( double ) this . TrackEffectiveLengthHorz ( ) - ( double ) this . ThumbSizeHorz ( ) ) ) ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| CContainer::Рассчитывает и возвращает величину смещения ползунка |
//| по вертикали в зависимости от положения контента |
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
int CContainer : : CalculateThumbOffsetVert ( const uint content_position )
2026-03-28 12:12:49 +07:00
{
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
if ( elm = = NULL )
return 0 ;
2026-03-28 12:36:14 +07:00
int value = elm . Height ( ) - this . ContentVisibleVert ( ) ;
2026-03-28 12:12:49 +07:00
if ( value = = 0 )
return 0 ;
2026-03-28 12:36:14 +07:00
return ( int ) : : round ( ( ( double ) content_position / ( double ) value ) * ( ( double ) this . TrackEffectiveLengthVert ( ) - ( double ) this . ThumbSizeVert ( ) ) ) ;
2026-03-28 12:12:49 +07:00
}
//+-------------------------------------------------------------------+
//|CContainer::Смещает содержимое по горизонтали на указанное значение|
//+-------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
bool CContainer : : ContentShiftHorz ( const int value )
2026-03-28 12:12:49 +07:00
{
//--- Получаем указатель на содержимое контейнера
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
if ( elm = = NULL )
return false ;
2026-03-29 15:13:53 +07:00
2026-03-29 15:55:22 +07:00
//--- Рассчитываем величину смещения по положению ползунка
int content_offset = this . CalculateContentOffsetHorz ( value ) ;
2026-03-29 15:13:53 +07:00
//--- Для элемента CTableView получаем заголовок таблицы
2026-03-29 15:55:22 +07:00
bool res = true ;
2026-03-29 15:13:53 +07:00
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 ( ) ;
2026-03-29 15:55:22 +07:00
//--- Сдвигаем заголовок
if ( table_header ! = NULL )
res & = table_header . MoveX ( this . X ( ) - content_offset ) ;
2026-03-29 15:13:53 +07:00
}
}
2026-03-28 12:12:49 +07:00
//--- Возвращаем результат сдвига содержимого на рассчитанную величину
2026-03-29 15:13:53 +07:00
res & = elm . MoveX ( this . X ( ) - content_offset ) ;
return res ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| CContainer::Смещает содержимое по вертикали на указанное значение|
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
bool CContainer : : ContentShiftVert ( const int value )
2026-03-28 12:12:49 +07:00
{
//--- Получаем указатель на содержимое контейнера
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
if ( elm = = NULL )
return false ;
2026-03-29 15:55:22 +07:00
2026-03-28 12:12:49 +07:00
//--- Рассчитываем величину смещения по положению ползунка
2026-03-28 12:36:14 +07:00
int content_offset = this . CalculateContentOffsetVert ( value ) ;
2026-03-29 15:55:22 +07:00
//--- Для элемента CTableView получаем вертикальный заголовок таблицы
bool res = true ;
CElementBase * elm_container = elm . GetContainer ( ) ;
CTableRowsHeaderView * 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 . GetRowsHeader ( ) ;
//--- Сдвигаем заголовок
if ( table_header ! = NULL )
res & = table_header . MoveY ( this . Y ( ) - content_offset ) ;
}
}
2026-03-28 12:12:49 +07:00
//--- Возвращаем результат сдвига содержимого на рассчитанную величину
2026-03-29 15:55:22 +07:00
res & = elm . MoveY ( this . Y ( ) - content_offset ) ;
return res ;
2026-03-28 12:12:49 +07:00
}
//+------------------------------------------------------------------+
//| Возвращает тип элемента, отправившего событие |
//+------------------------------------------------------------------+
ENUM_ELEMENT_TYPE CContainer : : GetEventElementType ( const string name )
{
//--- Получаем имена всех элементов в иерархии (при ошибке - возвращаем -1)
string names [ ] = { } ;
int total = GetElementNames ( name , " _ " , names ) ;
if ( total = = WRONG_VALUE )
return WRONG_VALUE ;
2026-03-29 15:13:53 +07:00
//--- Найдём в массиве наименование контейнера, ближайшее к имени элемента с событием
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 )
2026-03-28 12:12:49 +07:00
return WRONG_VALUE ;
2026-03-29 15:13:53 +07:00
//--- Если в имени элемента нет подстроки с именем базового элемента, то это не наше событие - уходим
string base_name = names [ cntr_index ] ;
if ( : : StringFind ( this . NameFG ( ) , base_name ) = = WRONG_VALUE )
return WRONG_VALUE ;
2026-03-28 12:12:49 +07:00
//--- События, пришедшие не от скроллбаров, пропускаем
2026-03-29 15:13:53 +07:00
string check_name = : : StringSubstr ( names [ cntr_index + 1 ] , 0 , 4 ) ;
2026-03-28 12:12:49 +07:00
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 ;
//--- Получаем указатель на содержимое контейнера
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
//--- Получаем тип элемента, от которого пришло событие
ENUM_ELEMENT_TYPE type = this . GetEventElementType ( sparam ) ;
//--- Если не удалось получить тип элемента или указатель на содержимое - уходим
if ( type = = WRONG_VALUE | | elm = = NULL )
return ;
//--- Если событие ползунка горизонтального скроллбара - сдвигаем содержимое по горизонтали
if ( type = = ELEMENT_TYPE_SCROLLBAR_THUMB_H )
2026-03-28 12:36:14 +07:00
res = this . ContentShiftHorz ( ( int ) lparam ) ;
2026-03-28 12:12:49 +07:00
//--- Если событие ползунка вертикального скроллбара - сдвигаем содержимое по вертикали
if ( type = = ELEMENT_TYPE_SCROLLBAR_THUMB_V )
2026-03-28 12:36:14 +07:00
res = this . ContentShiftVert ( ( int ) lparam ) ;
2026-03-28 12:12:49 +07:00
//--- Если содержимое успешно сдвинуто - обновляем график
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 ;
//--- Получаем указатель на содержимое контейнера
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
//--- Получаем тип элемента, от которого пришло событие
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 ) ;
//--- Проверяем делитель на нулевое значение
2026-03-28 12:36:14 +07:00
if ( this . ContentSizeHorz ( ) - this . ContentVisibleHorz ( ) = = 0 )
2026-03-28 12:12:49 +07:00
return ;
//--- Рассчитываем смещение ползунка, пропорциональное смещению содержимого на один экран
2026-03-28 12:36:14 +07:00
int thumb_shift = ( int ) : : round ( direction * ( ( double ) this . ContentVisibleHorz ( ) / double ( this . ContentSizeHorz ( ) - this . ContentVisibleHorz ( ) ) ) * ( double ) this . TrackEffectiveLengthHorz ( ) ) ;
2026-03-28 12:12:49 +07:00
//--- вызываем обработчик прокрутки объекта ползунка для смещения ползунка в направлении смещения
thumb . OnWheelEvent ( id , thumb_shift , 0 , this . NameFG ( ) ) ;
//--- Записываем результат смещения содержимого контейнера
2026-03-28 12:36:14 +07:00
res = this . ContentShiftHorz ( thumb_shift ) ;
2026-03-28 12:12:49 +07:00
}
//--- Если событие щелчка по вертикальному скроллбару (между ползунком и кнопками прокрутки),
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 ) ;
//--- Проверяем делитель на нулевое значение
2026-03-28 12:36:14 +07:00
if ( this . ContentSizeVert ( ) - this . ContentVisibleVert ( ) = = 0 )
2026-03-28 12:12:49 +07:00
return ;
//--- Рассчитываем смещение ползунка, пропорциональное смещению содержимого на один экран
2026-03-28 12:36:14 +07:00
int thumb_shift = ( int ) : : round ( direction * ( ( double ) this . ContentVisibleVert ( ) / double ( this . ContentSizeVert ( ) - this . ContentVisibleVert ( ) ) ) * ( double ) this . TrackEffectiveLengthVert ( ) ) ;
2026-03-28 12:12:49 +07:00
//--- вызываем обработчик прокрутки объекта ползунка для смещения ползунка в направлении смещения
thumb . OnWheelEvent ( id , thumb_shift , 0 , this . NameFG ( ) ) ;
//--- Записываем результат смещения содержимого контейнера
2026-03-28 12:36:14 +07:00
res = this . ContentShiftVert ( thumb_shift ) ;
2026-03-28 12:12:49 +07:00
}
//--- Если всё успешно - обновляем график
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 ;
//--- Получаем указатель на содержимое контейнера
2026-03-28 12:36:14 +07:00
CElementBase * elm = this . GetAttachedElement ( ) ;
2026-03-28 12:12:49 +07:00
//--- Получаем тип элемента, от которого пришло событие
ENUM_ELEMENT_TYPE type = this . GetEventElementType ( sparam ) ;
//--- Если не удалось получить указатель на содержимое, или тип элемента - уходим
if ( type = = WRONG_VALUE | | elm = = NULL )
return ;
//--- Если событие ползунка горизонтального скроллбара - сдвигаем содержимое по горизонтали
if ( type = = ELEMENT_TYPE_SCROLLBAR_THUMB_H )
2026-03-28 12:36:14 +07:00
res = this . ContentShiftHorz ( ( int ) lparam ) ;
2026-03-28 12:12:49 +07:00
//--- Если событие ползунка вертикального скроллбара - сдвигаем содержимое по вертикали
if ( type = = ELEMENT_TYPE_SCROLLBAR_THUMB_V )
2026-03-28 12:36:14 +07:00
res = this . ContentShiftVert ( ( int ) lparam ) ;
2026-03-28 12:12:49 +07:00
//--- Если содержимое успешно сдвинуто - обновляем график
if ( res )
: : ChartRedraw ( this . m_chart_id ) ;
}
//+------------------------------------------------------------------+
2026-03-28 12:36:14 +07:00
//| 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 ) ;
}
2026-03-28 12:12:49 +07:00
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//+------------------------------------------------------------------+
//| Класс визуального представления ячейки таблицы |
//+------------------------------------------------------------------+
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 [ ] ; // Текст
2026-03-29 15:13:53 +07:00
color m_fore_color ; // Цвет переднего плана
2026-03-29 15:55:22 +07:00
color m_back_color ; // Цвет заднего плана
2026-03-29 13:06:34 +07:00
//--- Возвращает смещения начальных координат рисования на холсте относительно канваса и координат базового элемента
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 текста в зависимости от точки привязки
2026-03-29 15:13:53 +07:00
bool GetTextCoordsByAnchor ( int & x , int & y , int & dir_x , int dir_y ) ;
//--- Возвращает указатель на контейнер панели строк таблицы
CContainer * GetRowsPanelContainer ( void ) ;
2026-03-29 13:06:34 +07:00
public :
2026-03-29 15:13:53 +07:00
//--- Возвращает указатель на назначенный канвас (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 ) ;
2026-03-29 13:06:34 +07:00
//--- (1) Устанавливает, (2) возвращает текст ячейки
void SetText ( const string text ) { : : StringToShortArray ( text , this . m_text ) ; }
string Text ( void ) const { return : : ShortArrayToString ( this . m_text ) ; }
2026-03-29 15:13:53 +07:00
//--- (1) Устанавливает, (2) возвращает цвет текста ячейки
void SetForeColor ( const color clr ) { this . m_fore_color = clr ; }
color ForeColor ( void ) const { return this . m_fore_color ; }
2026-03-29 15:55:22 +07:00
//--- (1) Устанавливает, (2) возвращает цвет фона ячейки
void SetBackColor ( const color clr ) { this . m_back_color = clr ; }
color BackColor ( void ) const { return this . m_back_color ; }
2026-03-29 13:06:34 +07:00
//--- Устанавливает идентификатор
2026-03-29 15:55:22 +07:00
virtual void SetID ( const int id ) { this . m_id = id ; }
2026-03-29 13:06:34 +07:00
//--- (1) Устанавливает, (2) возвращает индекс ячейки
2026-03-29 15:55:22 +07:00
void SetIndex ( const int index ) { this . m_index = index ; }
2026-03-29 13:06:34 +07:00
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 ) ;
2026-03-29 15:13:53 +07:00
virtual int Type ( void ) const { return ( ELEMENT_TYPE_TABLE_CELL_VIEW ) ; }
2026-03-29 13:06:34 +07:00
//--- Инициализация объекта класса
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 ) ;
2026-03-29 15:55:22 +07:00
this . SetIndex ( -1 ) ;
this . SetName ( " TableCellView " ) ;
2026-03-29 13:06:34 +07:00
}
//+------------------------------------------------------------------+
//| 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 ) ;
2026-03-29 15:55:22 +07:00
this . SetIndex ( -1 ) ;
2026-03-29 13:06:34 +07:00
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 ) ;
2026-03-29 15:13:53 +07:00
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 ( ) ) ;
2026-03-29 13:06:34 +07:00
}
//+------------------------------------------------------------------+
//| 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 ( ) ;
2026-03-29 15:13:53 +07:00
this . m_fore_color = this . m_element_base . ForeColor ( ) ;
2026-03-29 15:55:22 +07:00
this . m_back_color = this . m_element_base . BackColor ( ) ;
2026-03-29 13:06:34 +07:00
}
//+------------------------------------------------------------------+
//| 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 текста |
//| в зависимости от точки привязки |
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
bool CTableCellView : : GetTextCoordsByAnchor ( int & x , int & y , int & dir_x , int dir_y )
2026-03-29 13:06:34 +07:00
{
//--- Получаем размеры текста в ячейке
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 ;
2026-03-29 15:13:53 +07:00
dir_x = 1 ;
dir_y = 1 ;
2026-03-29 13:06:34 +07:00
break ;
//--- Точка привязки в левом нижнем углу
case ANCHOR_LEFT_LOWER :
x = 0 ;
y = this . Height ( ) - text_h ;
2026-03-29 15:13:53 +07:00
dir_x = 1 ;
dir_y = -1 ;
2026-03-29 13:06:34 +07:00
break ;
//--- Точка привязки снизу по центру
case ANCHOR_LOWER :
x = ( this . Width ( ) - text_w ) / 2 ;
y = this . Height ( ) - text_h ;
2026-03-29 15:13:53 +07:00
dir_x = 1 ;
dir_y = -1 ;
2026-03-29 13:06:34 +07:00
break ;
//--- Точка привязки в правом нижнем углу
case ANCHOR_RIGHT_LOWER :
x = this . Width ( ) - text_w ;
y = this . Height ( ) - text_h ;
2026-03-29 15:13:53 +07:00
dir_x = -1 ;
dir_y = -1 ;
2026-03-29 13:06:34 +07:00
break ;
//--- Точка привязки справа по центру
case ANCHOR_RIGHT :
x = this . Width ( ) - text_w ;
y = ( this . Height ( ) - text_h ) / 2 ;
2026-03-29 15:13:53 +07:00
dir_x = -1 ;
dir_y = 1 ;
2026-03-29 13:06:34 +07:00
break ;
//--- Точка привязки в правом верхнем углу
case ANCHOR_RIGHT_UPPER :
x = this . Width ( ) - text_w ;
y = 0 ;
2026-03-29 15:13:53 +07:00
dir_x = -1 ;
dir_y = 1 ;
2026-03-29 13:06:34 +07:00
break ;
//--- Точка привязки сверху по центру
case ANCHOR_UPPER :
x = ( this . Width ( ) - text_w ) / 2 ;
y = 0 ;
2026-03-29 15:13:53 +07:00
dir_x = 1 ;
dir_y = 1 ;
2026-03-29 13:06:34 +07:00
break ;
//--- Точка привязки строго по центру объекта
case ANCHOR_CENTER :
x = ( this . Width ( ) - text_w ) / 2 ;
y = ( this . Height ( ) - text_h ) / 2 ;
2026-03-29 15:13:53 +07:00
dir_x = 1 ;
dir_y = 1 ;
2026-03-29 13:06:34 +07:00
break ;
//--- Точка привязки в левом верхнем углу
//---ANCHOR_LEFT_UPPER
default :
x = 0 ;
y = 0 ;
2026-03-29 15:13:53 +07:00
dir_x = 1 ;
dir_y = 1 ;
2026-03-29 13:06:34 +07:00
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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 ( ) ) ;
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| CTableCellView::Рисует внешний вид |
//+------------------------------------------------------------------+
void CTableCellView : : Draw ( const bool chart_redraw )
{
2026-03-29 15:13:53 +07:00
//--- Если ячейка за пределами контейнера строк таблицы - уходим
if ( this . IsOutOfContainer ( ) )
return ;
//--- Получаем координаты текста и направление смещения в зависимости от точки привязки
2026-03-29 13:06:34 +07:00
int text_x = 0 , text_y = 0 ;
2026-03-29 15:13:53 +07:00
int dir_horz = 0 , dir_vert = 0 ;
if ( ! this . GetTextCoordsByAnchor ( text_x , text_y , dir_horz , dir_vert ) )
2026-03-29 13:06:34 +07:00
return ;
//--- Корректируем координаты текста
int x = this . AdjX ( this . X ( ) + text_x ) ;
int y = this . AdjY ( this . Y ( ) + text_y ) ;
//--- Устанавливаем координаты разделительной линии
int x1 = this . AdjX ( this . X ( ) ) ;
int y1 = this . AdjY ( this . Y ( ) ) ;
2026-03-29 15:55:22 +07:00
int x2 = this . AdjX ( this . X ( ) ) ;
2026-03-29 13:06:34 +07:00
int y2 = this . AdjY ( this . Bottom ( ) ) ;
2026-03-29 15:55:22 +07:00
2026-03-29 15:13:53 +07:00
//--- Выводим текст на канвасе переднего плана с учётом направления смещения без обновления графика
this . DrawText ( x + this . m_text_x * dir_horz , y + this . m_text_y * dir_vert , this . Text ( ) , false ) ;
2026-03-29 13:06:34 +07:00
2026-03-29 15:55:22 +07:00
//--- Устанавливаем координаты прямоугольной заливки
x1 = this . AdjX ( this . X ( ) ) ;
y1 = this . AdjY ( this . Y ( ) ) ;
x2 = this . AdjX ( this . Right ( ) ) ;
y2 = this . AdjY ( this . Bottom ( ) -1 ) ;
this . m_background . FillRectangle ( x1 , y1 , x2 , y2 , : : ColorToARGB ( this . BackColor ( ) , this . m_element_base . AlphaBG ( ) ) ) ;
2026-03-29 13:06:34 +07:00
//--- Если это не крайняя справа ячейка - рисуем у ячейки справа вертикальную разделительную полосу
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 ) ;
//--- Выводим установленный текст на канвасе переднего плана
2026-03-29 15:13:53 +07:00
this . m_foreground . TextOut ( dx , dy , this . Text ( ) , : : ColorToARGB ( this . ForeColor ( ) , this . m_element_base . AlphaFG ( ) ) ) ;
2026-03-29 13:06:34 +07:00
//--- Если текст выходит за правую границу области ячейки
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 ) ;
2026-03-29 15:13:53 +07:00
this . m_foreground . TextOut ( this . AdjX ( this . Right ( ) ) - w , this . AdjY ( dy ) , " ... " , : : ColorToARGB ( this . ForeColor ( ) , this . m_element_base . AlphaFG ( ) ) ) ;
2026-03-29 13:06:34 +07:00
}
}
//--- Обновляем канвас переднего плана с указанным флагом перерисовки графика
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 ;
//--- Загружаем номер ячейки
2026-03-29 15:55:22 +07:00
this . m_index = : : FileReadInteger ( file_handle , INT_VALUE ) ;
2026-03-29 13:06:34 +07:00
//--- Загружаем точку привязки текста
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 ; // Индекс в списке строк
2026-03-29 15:55:22 +07:00
ENUM_ROWS_HIGHLIGHT_MODE m_highlight_mode ; // Режим подсветки строк
2026-03-29 13:06:34 +07:00
//--- Создаёт и добавляет в список новый объект представления ячейки
CTableCellView * InsertNewCellView ( const int index , const string text , const int dx , const int dy , const int w , const int h ) ;
2026-03-29 15:13:53 +07:00
//--- Удаляет указанную область строки и ячейку с соответствующим индексом
bool BoundCellDelete ( const int index ) ;
2026-03-29 15:55:22 +07:00
//--- Возвращает визуальное представление (1) таблицы, заголовка (2) столбцов, (3) строк
CTableView * GetTableView ( void ) ;
CTableHeaderView * GetHeaderView ( void ) ;
CTableRowsHeaderView * GetRowsHeaderView ( void ) ;
//--- Устанавливает выбранным указанный заголовок (1) столбца, (2) строки
void SetColumnCaptionSelected ( const uint index ) ;
void SetRowCaptionSelected ( const uint index ) ;
//--- Снимает выделение со всех заголовков (1) столбца, (2) строки
void SetAllColumnCaptionsUnselected ( const int exclude = -1 ) ;
void SetAllRowCaptionsUnselected ( const int exclude = -1 ) ;
2026-03-29 13:06:34 +07:00
public :
2026-03-29 15:55:22 +07:00
//--- Возвращает (1) список, (2) количество ячеек, (3) ячейку, заголовок (4) столбца, (5) строки
2026-03-29 15:13:53 +07:00
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 ) ; }
2026-03-29 15:55:22 +07:00
CColumnCaptionView * GetColumnCaption ( const uint index ) ;
CRowCaptionView * GetRowCaption ( const uint index ) ;
2026-03-29 13:06:34 +07:00
//--- Устанавливает идентификатор
2026-03-29 15:55:22 +07:00
virtual void SetID ( const int id ) { this . m_id = id ; }
2026-03-29 13:06:34 +07:00
//--- (1) Устанавливает, (2) возвращает индекс строки
2026-03-29 15:55:22 +07:00
void SetIndex ( const int index ) { this . m_index = index ; }
2026-03-29 15:13:53 +07:00
int Index ( void ) const { return this . m_index ; }
2026-03-29 13:06:34 +07:00
//--- (1) Устанавливает, (2) возвращает модель строки
bool TableRowModelAssign ( CTableRow * row_model ) ;
2026-03-29 15:13:53 +07:00
CTableRow * GetTableRowModel ( void ) { return this . m_table_row_model ; }
//--- Обновляет сторку с обновлённой моделью
bool TableRowModelUpdate ( CTableRow * row_model ) ;
2026-03-29 15:55:22 +07:00
//--- (1) Устанавливает, (2) возвращает режим подсветки строки
void SetHighlightMode ( const ENUM_ROWS_HIGHLIGHT_MODE mode ) { this . m_highlight_mode = mode ; }
ENUM_ROWS_HIGHLIGHT_MODE HighlightMode ( void ) const { return this . m_highlight_mode ; }
2026-03-29 15:13:53 +07:00
//--- Перерассчитывает области ячеек
bool RecalculateBounds ( CListElm * list_bounds ) ;
2026-03-29 13:06:34 +07:00
//--- Распечатывает в журнале назначенную модель строки
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) тип объекта
2026-03-29 15:13:53 +07:00
virtual int Compare ( const CObject * node , const int mode = 0 ) const { return CLabel : : Compare ( node , mode ) ; }
2026-03-29 13:06:34 +07:00
virtual bool Save ( const int file_handle ) ;
virtual bool Load ( const int file_handle ) ;
2026-03-29 15:13:53 +07:00
virtual int Type ( void ) const { return ( ELEMENT_TYPE_TABLE_ROW_VIEW ) ; }
2026-03-29 13:06:34 +07:00
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( void ) ;
virtual void InitColors ( void ) ;
2026-03-29 15:55:22 +07:00
//--- Обработчики событий (1) наведения курсора (Focus), (2) нажатий кнопок мышки (Press),
virtual void OnFocusEvent ( const int id , const long lparam , const double dparam , const string sparam ) ;
virtual void OnPressEvent ( const int id , const long lparam , const double dparam , const string sparam ) ;
2026-03-29 13:06:34 +07:00
//--- Конструкторы/деструктор
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 ) ;
2026-03-29 15:13:53 +07:00
~ CTableRowView ( void ) { this . m_list_cells . Clear ( ) ; }
2026-03-29 13:06:34 +07:00
} ;
//+------------------------------------------------------------------+
//| CTableRowView::Конструктор по умолчанию. Строит объект в главном |
//| окне текущего графика в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
CTableRowView : : CTableRowView ( void ) : CPanel ( " TableRow " , " " , : : ChartID ( ) , 0 , 0 , 0 , DEF_PANEL_W , DEF_TABLE_ROW_H ) , m_index ( -1 ) , m_highlight_mode ( ROWS_HIGHLIGHT_MODE_ROW )
2026-03-29 13:06:34 +07:00
{
//--- Инициализация
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 ) :
2026-03-29 15:55:22 +07:00
CPanel ( object_name , text , chart_id , wnd , x , y , w , h ) , m_index ( -1 ) , m_highlight_mode ( ROWS_HIGHLIGHT_MODE_ROW )
2026-03-29 13:06:34 +07:00
{
//--- Инициализация
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 ) ;
2026-03-29 15:13:53 +07:00
//--- Запоминаем метод сортировки списка
int sort_mode = this . m_list_cells . SortMode ( ) ;
2026-03-29 13:06:34 +07:00
//--- Устанавливаем списку флаг сортировки по идентификатору
this . m_list_cells .Sort ( ELEMENT_SORT_BY_ID ) ;
if ( this . m_list_cells . Search ( & this . m_temp_cell ) ! = NULL )
{
2026-03-29 15:13:53 +07:00
//--- Возвращаем списку изначальную сортировку, сообщаем, что такой объект уже существует и возвращаем NULL
this . m_list_cells .Sort ( sort_mode ) ;
2026-03-29 13:06:34 +07:00
: : PrintFormat ( " %s: Error. The TableCellView object with index %d is already in the list " , __FUNCTION__ , index ) ;
return NULL ;
}
2026-03-29 15:13:53 +07:00
//--- Возвращаем списку изначальную сортировку
this . m_list_cells .Sort ( sort_mode ) ;
//--- Создаём имя объекта ячейки
2026-03-29 13:06:34 +07:00
string name = " TableCellView " + ( string ) this . Index ( ) + " x " + ( string ) index ;
//--- Создаём новый объект TableCellView; при неудаче - сообщаем об этом и возвращаем NULL
2026-03-29 15:13:53 +07:00
CTableCellView * cell_view = new CTableCellView ( index , name , text , dx , dy , w , h ) ;
2026-03-29 13:06:34 +07:00
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 ;
}
2026-03-29 15:13:53 +07:00
//--- Назначаем базовый элемент (строку) и возвращаем указатель на объект
cell_view . RowAssign ( & this ) ;
2026-03-29 13:06:34 +07:00
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 ;
}
2026-03-29 15:13:53 +07:00
//--- Сохраняем указатель на переданную модель строки
2026-03-29 13:06:34 +07:00
this . m_table_row_model = row_model ;
2026-03-29 15:13:53 +07:00
//--- рассчитываем ширину ячейки по ширине панели строк
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 ) ;
2026-03-29 13:06:34 +07:00
//--- В цикле по количеству ячеек в модели строки
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 ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| CTableRowView::Рисует внешний вид |
//+------------------------------------------------------------------+
void CTableRowView : : Draw ( const bool chart_redraw )
{
2026-03-29 15:13:53 +07:00
//--- Если строка за пределами контейнера - уходим
if ( this . IsOutOfContainer ( ) )
return ;
2026-03-29 13:06:34 +07:00
//--- Заливаем объект цветом фона, рисуем линию строки и обновляем канвас фона
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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 ;
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| CTableRowView::Возвращает визуальное представление таблицы |
//+------------------------------------------------------------------+
CTableView * CTableRowView : : GetTableView ( void )
{
CTableView * obj = NULL ;
//--- Получаем панель со строками таблицы
CElementBase * base0 = this . GetContainer ( ) ;
if ( base0 = = NULL )
return NULL ;
//--- Получаем контейнер панели строк таблицы
CElementBase * base1 = base0 . GetContainer ( ) ;
if ( base1 = = NULL )
return NULL ;
//--- Получаем объект визуального представления таблицы
CElementBase * base2 = base1 . GetContainer ( ) ;
if ( base2 ! = NULL & & base2 . Type ( ) = = ELEMENT_TYPE_TABLE_VIEW )
{
obj = base2 ;
return obj ;
}
return NULL ;
}
//+------------------------------------------------------------------+
//| CTableRowView::Возвращает визуальное представление |
//| заголовка столбцов |
//+------------------------------------------------------------------+
CTableHeaderView * CTableRowView : : GetHeaderView ( void )
{
CTableView * table = this . GetTableView ( ) ;
return ( table ! = NULL ? table . GetHeader ( ) : NULL ) ;
}
//+------------------------------------------------------------------+
//|CTableRowView::Возвращает визуальное представление заголовка строк|
//+------------------------------------------------------------------+
CTableRowsHeaderView * CTableRowView : : GetRowsHeaderView ( void )
{
CTableView * table = this . GetTableView ( ) ;
return ( table ! = NULL ? table . GetRowsHeader ( ) : NULL ) ;
}
//+------------------------------------------------------------------+
//| CTableRowView::Возвращает заголовок столбца |
//+------------------------------------------------------------------+
CColumnCaptionView * CTableRowView : : GetColumnCaption ( const uint index )
{
CTableHeaderView * header = this . GetHeaderView ( ) ;
return ( header ! = NULL ? header . GetColumnCaption ( index ) : NULL ) ;
}
//+------------------------------------------------------------------+
//| CTableRowView::Возвращает заголовок строки |
//+------------------------------------------------------------------+
CRowCaptionView * CTableRowView : : GetRowCaption ( const uint index )
{
CTableRowsHeaderView * header = this . GetRowsHeaderView ( ) ;
return ( header ! = NULL ? header . GetRowCaption ( index ) : NULL ) ;
}
//+------------------------------------------------------------------+
//|CTableRowView::Устанавливает выбранным указанный заголовок столбца|
//+------------------------------------------------------------------+
void CTableRowView : : SetColumnCaptionSelected ( const uint index )
{
CColumnCaptionView * capt = this . GetColumnCaption ( index ) ;
if ( capt = = NULL | | capt . State ( ) = = ELEMENT_STATE_ACT )
return ;
capt . SetState ( ELEMENT_STATE_ACT ) ;
capt . GetBackground ( ) . FillRectangle ( 0 , capt . Height ( ) -2 , capt . Width ( ) -1 , capt . Height ( ) -1 , ColorToARGB ( clrCadetBlue ) ) ;
capt . GetBackground ( ) . Update ( false ) ;
}
//+------------------------------------------------------------------+
//| CTableRowView::Устанавливает выбранным указанный заголовок строки|
//+------------------------------------------------------------------+
void CTableRowView : : SetRowCaptionSelected ( const uint index )
{
CRowCaptionView * capt = this . GetRowCaption ( index ) ;
if ( capt = = NULL | | capt . State ( ) = = ELEMENT_STATE_ACT )
return ;
capt . SetState ( ELEMENT_STATE_ACT ) ;
capt . GetBackground ( ) . FillRectangle ( capt . Width ( ) -2 , 2 , capt . Width ( ) -1 , capt . Height ( ) -0 , ColorToARGB ( clrCadetBlue ) ) ;
capt . GetBackground ( ) . Update ( false ) ;
}
//+------------------------------------------------------------------+
//| CTableRowView::Снимает выделение со всех заголовков столбца |
//+------------------------------------------------------------------+
void CTableRowView : : SetAllColumnCaptionsUnselected ( const int exclude = -1 )
{
CTableHeaderView * header = this . GetHeaderView ( ) ;
if ( header = = NULL )
return ;
int total = header . BoundsTotal ( ) ;
for ( int i = 0 ; i < total ; i + + )
{
CColumnCaptionView * capt = this . GetColumnCaption ( i ) ;
if ( capt = = NULL | | ( exclude > -1 & & i = = exclude ) )
continue ;
if ( capt . State ( ) ! = ELEMENT_STATE_DEF )
{
capt . SetState ( ELEMENT_STATE_DEF ) ;
capt . Draw ( false ) ;
}
}
}
//+------------------------------------------------------------------+
//| CTableRowView::Снимает выделение со всех заголовков строки |
//+------------------------------------------------------------------+
void CTableRowView : : SetAllRowCaptionsUnselected ( const int exclude = -1 )
{
CTableRowsHeaderView * header = this . GetRowsHeaderView ( ) ;
if ( header = = NULL )
return ;
int total = header . BoundsTotal ( ) ;
for ( int i = 0 ; i < total ; i + + )
{
CRowCaptionView * capt = this . GetRowCaption ( i ) ;
if ( capt = = NULL | | ( exclude > -1 & & capt . ID ( ) = = exclude ) )
continue ;
if ( capt . State ( ) ! = ELEMENT_STATE_DEF )
{
capt . SetState ( ELEMENT_STATE_DEF ) ;
capt . Draw ( false ) ;
}
}
}
//+------------------------------------------------------------------+
//| CTableRowView::Обработчик наведения курсора |
//+------------------------------------------------------------------+
void CTableRowView : : OnFocusEvent ( const int id , const long lparam , const double dparam , const string sparam )
{
//--- Если обрабатывается целиком строка - вызываем обработчик событий родительского класса
if ( this . m_highlight_mode = = ROWS_HIGHLIGHT_MODE_ROW )
{
CCanvasBase : : OnFocusEvent ( id , lparam , dparam , sparam ) ;
return ;
}
//--- Получаем координаты курсора
int x = int ( lparam - this . X ( ) ) ;
int y = int ( dparam - this . m_wnd_y - this . Y ( ) ) ;
//--- В цикле по областям ячеек строки
int total = this . m_list_bounds . Total ( ) ;
for ( int i = 0 ; i < total ; i + + )
{
//--- получаем очередную область
CBound * bound = this . GetBoundAt ( i ) ;
if ( bound = = NULL )
continue ;
//--- Из текущей области получаем назначенный на неё элемент
CBaseObj * obj = bound . GetAssignedObj ( ) ;
CTableCellView * cell = NULL ;
//--- Если полученный элемент не является ячейкой таблицы - идём дальше
if ( obj = = NULL | | obj . Type ( ) ! = ELEMENT_TYPE_TABLE_CELL_VIEW )
continue ;
//--- Это ячейка таблицы. Определяем её координаты в таблице (строка/столбец)
cell = obj ;
int row = this . ID ( ) ;
int col = obj . ID ( ) ;
//--- Получаем соответствующие заголовки строки и столбца
CColumnCaptionView * col_capt = this . GetColumnCaption ( col ) ;
CRowCaptionView * row_capt = this . GetRowCaption ( row ) ;
if ( col_capt = = NULL | | row_capt = = NULL )
continue ;
//--- Если курсор находится на области ячейки
if ( bound . Contains ( x , y ) )
{
//--- Устанавливаем заголовок столбца и строки выбранными,
this . SetColumnCaptionSelected ( i ) ;
this . SetRowCaptionSelected ( this . ID ( ) ) ;
//--- со всех заголовков строк, кроме текущего, снимаем флаг выбранного заголовка
this . SetAllRowCaptionsUnselected ( this . ID ( ) ) ;
}
//--- Если курсор за пределами области ячейки
else
{
//--- Если заголовок выбран,
if ( col_capt . State ( ) ! = ELEMENT_STATE_DEF )
{
//--- снимаем с него выделение и перерисовываем объект не выбранным
col_capt . SetState ( ELEMENT_STATE_DEF ) ;
col_capt . Draw ( false ) ;
}
}
}
}
//+------------------------------------------------------------------+
//| CTableRowView::Обработчик нажатия на объект |
//+------------------------------------------------------------------+
void CTableRowView : : OnPressEvent ( const int id , const long lparam , const double dparam , const string sparam )
{
//--- Если обрабатывается целиком строка - вызываем обработчик событий родительского класса
if ( this . m_highlight_mode = = ROWS_HIGHLIGHT_MODE_ROW )
{
CCanvasBase : : OnPressEvent ( id , lparam , dparam , sparam ) ;
return ;
}
//--- В цикле по всем областям строки
int total = this . m_list_bounds . Total ( ) ;
for ( int i = 0 ; i < total ; i + + )
{
//--- получаем очередную область
CBound * bound = this . GetBoundAt ( i ) ;
if ( bound = = NULL )
continue ;
//--- Получаем координаты курсора и
int x = int ( lparam - this . X ( ) ) ;
int y = int ( dparam - this . m_wnd_y - this . Y ( ) ) ;
//--- проверяем, что курсор находится внутри области
if ( bound . Contains ( x , y ) )
{
//--- Получаем из области прикреплённый объект (ячейка)
CBaseObj * obj = bound . GetAssignedObj ( ) ;
if ( obj ! = NULL )
{
//--- Записываем адрес ячейки в таблице (строка/столбец)
int row = this . ID ( ) ;
int col = obj . ID ( ) ;
//--- На основе идентификаторов строки и столбца получаем указатели на соответствующие заголовки
CRowCaptionView * row_capt = this . GetRowCaption ( row ) ;
CColumnCaptionView * col_capt = this . GetColumnCaption ( col ) ;
if ( row_capt = = NULL | | col_capt = = NULL )
return ;
//--- Создаём текстовое значение для пользовательского события из имени строки и текстов заголовков
string sprm = obj . Name ( ) + " ; " + row_capt . Text ( ) + " ; " + col_capt . Text ( ) ;
//--- Посылаем пользовательское событие щелчка по объекту с координатами строки и столбца и текстом
: : EventChartCustom ( this . m_chart_id , CHARTEVENT_OBJECT_CLICK , row , col , sprm ) ;
}
}
}
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| 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 ;
2026-03-29 15:55:22 +07:00
//--- Сохраняем режим подсветки
if ( : : FileWriteInteger ( file_handle , this . m_highlight_mode , INT_VALUE ) ! = INT_VALUE )
return false ;
2026-03-29 13:06:34 +07:00
//--- Всё успешно
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 ;
//--- Загружаем номер строки
2026-03-29 15:55:22 +07:00
this . m_index = ( int ) : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем режим подсветки
this . m_highlight_mode = ( ENUM_ROWS_HIGHLIGHT_MODE ) : : FileReadInteger ( file_handle , INT_VALUE ) ;
2026-03-29 13:06:34 +07:00
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| Абстрактный класс визуального представления заголовка |
2026-03-29 13:06:34 +07:00
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
class CCaptionView : public CButton
2026-03-29 13:06:34 +07:00
{
protected :
2026-03-29 15:13:53 +07:00
CBound * m_bound_node ; // Указатель на область заголовка
2026-03-29 15:55:22 +07:00
int m_index ; // Индекс в списке строк
2026-03-29 13:06:34 +07:00
public :
//--- Устанавливает идентификатор
2026-03-29 15:55:22 +07:00
virtual void SetID ( const int id ) { this . m_id = id ; }
//--- (1) Устанавливает, (2) возвращает индекс строки
void SetIndex ( const int index ) { this . m_index = index ; }
2026-03-29 13:06:34 +07:00
int Index ( void ) const { return this . m_index ; }
2026-03-29 15:55:22 +07:00
2026-03-29 15:13:53 +07:00
//--- (1) Назначает, (2) возвращает область заголовка, которой назначен объект
void AssignBoundNode ( CBound * bound ) { this . m_bound_node = bound ; }
CBound * GetBoundNode ( void ) { return this . m_bound_node ; }
2026-03-29 15:55:22 +07:00
//--- Рисует (1) внешний вид, (2) стрелку направления сортировки
virtual void Draw ( const bool chart_redraw ) ;
2026-03-29 15:13:53 +07:00
2026-03-29 15:55:22 +07:00
//--- Виртуальные методы (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_CAPTION_VIEW ) ; }
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
virtual void InitColors ( void ) ;
2026-03-29 13:06:34 +07:00
2026-03-29 15:55:22 +07:00
//--- Возвращает описание объекта
virtual string Description ( void ) ;
2026-03-29 15:13:53 +07:00
2026-03-29 15:55:22 +07:00
//--- Конструкторы/деструктор
CCaptionView ( void ) ;
CCaptionView ( 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 ) ;
~ CCaptionView ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CCaptionView::Конструктор по умолчанию. Строит объект |
//| в главном окне текущего графика в координатах 0,0 |
//| с размерами по умолчанию |
//+------------------------------------------------------------------+
CCaptionView : : CCaptionView ( void ) : CButton ( " Caption " , " Caption " , : : ChartID ( ) , 0 , 0 , 0 , DEF_PANEL_W , DEF_TABLE_ROW_H ) , m_index ( 0 )
{
//--- Инициализация
this .Init ( " Caption " ) ;
this . SetID ( 0 ) ;
this . SetIndex ( -1 ) ;
this . SetName ( " Caption " ) ;
}
//+------------------------------------------------------------------+
//| CCaptionView::Конструктор параметрический. |
//| Строит объект в указанном окне указанного графика с |
//| указанными текстом, координатами и размерами |
//+------------------------------------------------------------------+
CCaptionView : : CCaptionView ( 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 )
{
//--- Инициализация
this .Init ( text ) ;
this . SetID ( 0 ) ;
this . SetIndex ( -1 ) ;
}
//+------------------------------------------------------------------+
//| CCaptionView::Инициализация |
//+------------------------------------------------------------------+
void CCaptionView ::Init ( const string text )
{
//--- Смещения текста по умолчанию
this . m_text_x = 4 ;
this . m_text_y = 2 ;
//--- Устанавливаем цвета различных состояний
this . InitColors ( ) ;
//--- Возможно изменять размеры
this . SetResizable ( false ) ;
this . SetMovable ( false ) ;
this . SetImageBound ( this . ObjectWidth ( ) -14 , 4 , 8 , 11 ) ;
}
//+------------------------------------------------------------------+
//| CCaptionView::Инициализация цветов объекта по умолчанию |
//+------------------------------------------------------------------+
void CCaptionView : : InitColors ( void )
{
//--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона
this . InitBackColors ( C ' 230 , 230 , 230 ' , C ' 159 , 213 , 183 ' , this . GetBackColorControl ( ) . NewColor ( C ' 159 , 213 , 183 ' , -6 , -6 , -6 ) , clrSilver ) ;
this . InitBackColorsAct ( C ' 230 , 230 , 230 ' , C ' 159 , 213 , 183 ' , this . GetBackColorControl ( ) . NewColor ( C ' 159 , 213 , 183 ' , -6 , -6 , -6 ) , clrSilver ) ;
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 ) ;
}
//+------------------------------------------------------------------+
//| CCaptionView::Рисует внешний вид |
//+------------------------------------------------------------------+
void CCaptionView : : 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 ) ;
//--- Если указано - обновляем график
if ( chart_redraw )
: : ChartRedraw ( this . m_chart_id ) ;
}
//+------------------------------------------------------------------+
//| CCaptionView::Возвращает описание объекта |
//+------------------------------------------------------------------+
string CCaptionView : : 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 " , ElementDescription ( ( ENUM_ELEMENT_TYPE ) this . Type ( ) ) , name , this . ID ( ) , this . X ( ) , this . Y ( ) , this . Width ( ) , this . Height ( ) ) ;
}
//+------------------------------------------------------------------+
//| CCaptionView::Сохранение в файл |
//+------------------------------------------------------------------+
bool CCaptionView : : 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 ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//| CCaptionView::Загрузка из файла |
//+------------------------------------------------------------------+
bool CCaptionView : : Load ( const int file_handle )
{
//--- Загружаем данные родительского объекта
if ( ! CButton : : Load ( file_handle ) )
return false ;
//--- Загружаем номер заголовка
this . m_index = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс визуального представления заголовка столбца таблицы |
//+------------------------------------------------------------------+
class CColumnCaptionView : public CCaptionView
{
protected :
CColumnCaption * m_column_caption_model ; // Указатель на модель заголовка столбца
ENUM_TABLE_SORT_MODE m_sort_mode ; // Режим сортировки столбца таблицы
bool m_sortable ; // Флаг управления сортировкой
//--- Добавляет в список объекты-подсказки со стрелками
virtual bool AddHintsArrowed ( void ) ;
//--- Отображает курсор изменения размеров
virtual bool ShowCursorHint ( const ENUM_CURSOR_REGION edge , int x , int y ) ;
public :
//--- (1) Назначает, (2) возвращает модель заголовка столбца
bool ColumnCaptionModelAssign ( CColumnCaption * caption_model ) ;
CColumnCaption * ColumnCaptionModel ( void ) { return this . m_column_caption_model ; }
//--- Распечатывает в журнале назначенную модель заголовка столбца
void ColumnCaptionModelPrint ( void ) ;
//--- (1) Устанавливает, (2) возвращает флаг возможности сортировки
void SetSortableFlag ( const bool flag )
{
this . m_sortable = flag ;
this . SetSortMode ( flag ? TABLE_SORT_MODE_ASC : TABLE_SORT_MODE_NONE ) ;
}
bool IsSortabe ( void ) const { return this . m_sortable ; }
//--- (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 :
2026-03-29 15:13:53 +07:00
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) тип объекта
2026-03-29 13:06:34 +07:00
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 ) ;
2026-03-29 15:13:53 +07:00
virtual int Type ( void ) const { return ( ELEMENT_TYPE_TABLE_COLUMN_CAPTION_VIEW ) ; }
2026-03-29 13:06:34 +07:00
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
2026-03-29 15:55:22 +07:00
//virtual void InitColors(void);
2026-03-29 13:06:34 +07:00
//--- Возвращает описание объекта
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 |
//| с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
CColumnCaptionView : : CColumnCaptionView ( void ) : CCaptionView ( " ColumnCaption " , " Caption " , : : ChartID ( ) , 0 , 0 , 0 , DEF_PANEL_W , DEF_TABLE_ROW_H ) , m_sort_mode ( TABLE_SORT_MODE_NONE ) , m_sortable ( true )
2026-03-29 13:06:34 +07:00
{
//--- Инициализация
this .Init ( " Caption " ) ;
this . SetID ( 0 ) ;
2026-03-29 15:55:22 +07:00
this . SetIndex ( -1 ) ;
2026-03-29 13:06:34 +07:00
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 ) :
2026-03-29 15:55:22 +07:00
CCaptionView ( object_name , text , chart_id , wnd , x , y , w , h ) , m_sort_mode ( TABLE_SORT_MODE_NONE ) , m_sortable ( true )
2026-03-29 13:06:34 +07:00
{
//--- Инициализация
this .Init ( text ) ;
this . SetID ( 0 ) ;
2026-03-29 15:55:22 +07:00
this . SetIndex ( -1 ) ;
2026-03-29 13:06:34 +07:00
}
//+------------------------------------------------------------------+
//| CColumnCaptionView::Инициализация |
//+------------------------------------------------------------------+
void CColumnCaptionView ::Init ( const string text )
{
2026-03-29 15:55:22 +07:00
//--- Инициализация родительского объекта
CCaptionView ::Init ( text ) ;
2026-03-29 15:13:53 +07:00
//--- Возможно изменять размеры
this . SetResizable ( true ) ;
this . SetMovable ( false ) ;
2026-03-29 13:06:34 +07:00
}
//+------------------------------------------------------------------+
//| CColumnCaptionView::Рисует внешний вид |
//+------------------------------------------------------------------+
void CColumnCaptionView : : Draw ( const bool chart_redraw )
{
2026-03-29 15:13:53 +07:00
//--- Если объект за пределами своего контейнера - уходим
if ( this . IsOutOfContainer ( ) )
return ;
//--- Заливаем объект цветом фона, рисуем слева светлую вертикальную линию, справа - тёмную
2026-03-29 13:06:34 +07:00
this .Fill ( this . BackColor ( ) , false ) ;
color clr_dark = this . BorderColor ( ) ; // "Тёмный цвет"
2026-03-29 15:55:22 +07:00
color clr_light = this . GetBackColorControl ( ) . NewColor ( this . BorderColor ( ) , 20 , 20 , 20 ) ; // "Светлый цвет"
2026-03-29 13:06:34 +07:00
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 ( ) ) ) ; // Линия справа
2026-03-29 15:55:22 +07:00
2026-03-29 13:06:34 +07:00
//--- Выводим текст заголовка
CLabel : : Draw ( false ) ;
2026-03-29 15:13:53 +07:00
//--- Рисуем стрелки направления сортировки
this . DrawSortModeArrow ( ) ;
2026-03-29 15:55:22 +07:00
//--- обновляем канвас фона
this . m_background . Update ( false ) ;
2026-03-29 13:06:34 +07:00
//--- Если указано - обновляем график
if ( chart_redraw )
: : ChartRedraw ( this . m_chart_id ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 ;
}
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| CColumnCaptionView::Возвращает описание объекта |
//+------------------------------------------------------------------+
string CColumnCaptionView : : Description ( void )
{
string nm = this . Name ( ) ;
string name = ( nm ! = " " ? : : StringFormat ( " \" %s \" " , nm ) : nm ) ;
2026-03-29 15:13:53 +07:00
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 ) ;
2026-03-29 13:06:34 +07:00
}
//+------------------------------------------------------------------+
//| 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 ( ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 ;
//--- Меняем стрелку направления сортировки на обратную и вызываем обработчик щелчка мышки
2026-03-29 15:55:22 +07:00
if ( this . m_sortable )
this . SetSortModeReverse ( ) ;
2026-03-29 15:13:53 +07:00
CCanvasBase : : OnPressEvent ( id , lparam , dparam , sparam ) ;
2026-03-29 15:55:22 +07:00
: : EventChartCustom ( this . m_chart_id , CHARTEVENT_OBJECT_CLICK , this . ID ( ) , - ( 10000 + this . SortMode ( ) ) , this . NameFG ( ) ) ;
2026-03-29 15:13:53 +07:00
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| 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 ;
2026-03-29 15:13:53 +07:00
//--- Сохраняем направление сортировки
if ( : : FileWriteInteger ( file_handle , this . m_sort_mode , INT_VALUE ) ! = INT_VALUE )
return false ;
2026-03-29 15:55:22 +07:00
//--- Сохраняем флаг управления сортировкой
if ( : : FileWriteInteger ( file_handle , this . m_sortable , INT_VALUE ) ! = INT_VALUE )
return false ;
2026-03-29 13:06:34 +07:00
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//| CColumnCaptionView::Загрузка из файла |
//+------------------------------------------------------------------+
bool CColumnCaptionView : : Load ( const int file_handle )
{
//--- Загружаем данные родительского объекта
if ( ! CButton : : Load ( file_handle ) )
return false ;
//--- Загружаем номер заголовка
2026-03-29 15:55:22 +07:00
this . m_index = : : FileReadInteger ( file_handle , INT_VALUE ) ;
2026-03-29 15:13:53 +07:00
//--- Загружаем направление сортировки
2026-03-29 15:55:22 +07:00
this . m_sort_mode = ( ENUM_TABLE_SORT_MODE ) : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем флаг управления сортировкой
this . m_sortable = ( bool ) : : FileReadInteger ( file_handle , INT_VALUE ) ;
2026-03-29 13:06:34 +07:00
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| Класс визуального представления заголовка строки таблицы |
2026-03-29 13:06:34 +07:00
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
class CRowCaptionView : public CCaptionView
2026-03-29 13:06:34 +07:00
{
protected :
public :
//--- Рисует внешний вид
virtual void Draw ( const bool chart_redraw ) ;
2026-03-29 15:13:53 +07:00
2026-03-29 15:55:22 +07:00
public :
2026-03-29 13:06:34 +07:00
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
2026-03-29 15:55:22 +07:00
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_ROW_CAPTION_VIEW ) ; }
2026-03-29 13:06:34 +07:00
2026-03-29 15:55:22 +07:00
//--- Инициализация объекта класса
void Init ( const string text ) ;
//--- Возвращает описание объекта
virtual string Description ( void ) ;
2026-03-29 13:06:34 +07:00
//--- Конструкторы/деструктор
2026-03-29 15:55:22 +07:00
CRowCaptionView ( void ) ;
CRowCaptionView ( 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 ) ;
~ CRowCaptionView ( void ) { }
2026-03-29 13:06:34 +07:00
} ;
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| CRowCaptionView::Конструктор по умолчанию. Строит объект |
//| в главном окне текущего графика в координатах 0,0 |
2026-03-29 13:06:34 +07:00
//| с размерами по умолчанию |
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
CRowCaptionView : : CRowCaptionView ( void ) : CCaptionView ( " RowCaption " , " Caption " , : : ChartID ( ) , 0 , 0 , 0 , DEF_PANEL_W , DEF_TABLE_ROW_H )
2026-03-29 13:06:34 +07:00
{
//--- Инициализация
2026-03-29 15:55:22 +07:00
this .Init ( " Caption " ) ;
this . SetID ( 0 ) ;
this . SetIndex ( -1 ) ;
this . SetName ( " RowCaption " ) ;
this . SetTextShiftH ( 8 ) ;
2026-03-29 13:06:34 +07:00
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| CRowCaptionView::Конструктор параметрический. |
//| Строит объект в указанном окне указанного графика с |
//| указанными текстом, координатами и размерами |
2026-03-29 13:06:34 +07:00
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
CRowCaptionView : : CRowCaptionView ( 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 ) :
CCaptionView ( object_name , text , chart_id , wnd , x , y , w , h )
2026-03-29 13:06:34 +07:00
{
//--- Инициализация
2026-03-29 15:55:22 +07:00
this .Init ( text ) ;
this . SetID ( 0 ) ;
this . SetIndex ( -1 ) ;
this . SetTextShiftH ( 8 ) ;
2026-03-29 13:06:34 +07:00
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| CRowCaptionView::Инициализация |
2026-03-29 13:06:34 +07:00
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
void CRowCaptionView ::Init ( const string text )
2026-03-29 13:06:34 +07:00
{
//--- Инициализация родительского объекта
2026-03-29 15:55:22 +07:00
CCaptionView ::Init ( text ) ;
//--- Размеры не изменяемые
this . SetResizable ( false ) ;
this . SetMovable ( false ) ;
2026-03-29 13:06:34 +07:00
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| CRowCaptionView::Рисует внешний вид |
2026-03-29 13:06:34 +07:00
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
void CRowCaptionView : : Draw ( const bool chart_redraw )
2026-03-29 13:06:34 +07:00
{
2026-03-29 15:55:22 +07:00
//--- Если объект за пределами своего контейнера - уходим
if ( this . IsOutOfContainer ( ) )
return ;
//--- Заливаем объект цветом фона, рисуем слева светлую вертикальную линию, справа - тёмную
this .Fill ( this . BackColor ( ) , false ) ;
this . m_background . Rectangle ( this . AdjX ( 2 ) , 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 ) ;
}
//+------------------------------------------------------------------+
//| CRowCaptionView::Возвращает описание объекта |
//+------------------------------------------------------------------+
string CRowCaptionView : : 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 " , ElementDescription ( ( ENUM_ELEMENT_TYPE ) this . Type ( ) ) , name , this . ID ( ) , this . X ( ) , this . Y ( ) , this . Width ( ) , this . Height ( ) ) ;
}
//+------------------------------------------------------------------+
//| CRowCaptionView::Сохранение в файл |
//+------------------------------------------------------------------+
bool CRowCaptionView : : 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 ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//| CRowCaptionView::Загрузка из файла |
//+------------------------------------------------------------------+
bool CRowCaptionView : : Load ( const int file_handle )
{
//--- Загружаем данные родительского объекта
if ( ! CButton : : Load ( file_handle ) )
return false ;
//--- Загружаем номер заголовка
this . m_index = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс визуального представления заголовка таблицы |
//+------------------------------------------------------------------+
class CTableHeaderView : public CPanel
{
protected :
CColumnCaptionView m_temp_caption ; // Временный объект заголовка столбца для поиска
CTableHeader * m_table_header_model ; // Указатель на модель заголовка таблицы
bool m_sortable ; // Флаг управления сортировкой
//--- Создаёт и добавляет в список новый объект представления заголовка столбца
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 ) ;
//--- (1) Устанавливает, (2) возвращает флаг возможности сортировки
void SetSortableFlag ( const bool flag ) ;
bool IsSortabe ( void ) const { return this . m_sortable ; }
//--- Устанавливает заголовку столбца флаг сортировки
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 ) , m_sortable ( true )
{
//--- Инициализация
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 ) , m_sortable ( true )
{
//--- Инициализация
this .Init ( ) ;
}
//+------------------------------------------------------------------+
//| CTableHeaderView::Инициализация |
//+------------------------------------------------------------------+
void CTableHeaderView ::Init ( void )
{
//--- Инициализация родительского объекта
CPanel ::Init ( ) ;
//--- Цвет фона - непрозрачный
this . SetAlphaBG ( 255 ) ;
//--- Ширина рамки
this . SetBorderWidth ( 1 ) ;
}
//+------------------------------------------------------------------+
//| CTableHeaderView::Инициализация цветов объекта по умолчанию |
//+------------------------------------------------------------------+
void CTableHeaderView : : InitColors ( void )
{
//--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона
2026-03-29 13:06:34 +07:00
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 ( ) ;
2026-03-29 15:13:53 +07:00
CColumnCaptionView * caption_view = this . InsertNewElement ( ELEMENT_TYPE_TABLE_COLUMN_CAPTION_VIEW , text , user_name , x , y , w , h ) ;
2026-03-29 13:06:34 +07:00
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 ;
2026-03-29 15:13:53 +07:00
int caption_w = ( int ) : : fmax ( : : round ( ( double ) this . Width ( ) / ( double ) total ) , DEF_TABLE_COLUMN_MIN_W ) ;
2026-03-29 13:06:34 +07:00
//--- В цикле по количеству заголовков столбцов в модели заголовка таблицы
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 ;
2026-03-29 15:13:53 +07:00
caption_bound . SetID ( i ) ;
2026-03-29 13:06:34 +07:00
//--- Создаём новый объект визуального представления заголовка столбца
CColumnCaptionView * caption_view = this . InsertNewColumnCaptionView ( caption_model . Value ( ) , x , 0 , caption_w , this . Height ( ) ) ;
if ( caption_view = = NULL )
return false ;
2026-03-29 15:55:22 +07:00
caption_view . SetIndex ( i ) ;
2026-03-29 13:06:34 +07:00
//--- На текущую область заголовка столбца назначаем соответствующий объект визуального представления заголовка столбца
caption_bound . AssignObject ( caption_view ) ;
2026-03-29 15:13:53 +07:00
caption_view . AssignBoundNode ( caption_bound ) ;
//--- Для самого первого заголовка устанавливаем флаг сортировки по возрастанию
2026-03-29 15:55:22 +07:00
if ( i = = 0 & & caption_view . IsSortabe ( ) )
2026-03-29 15:13:53 +07:00
caption_view . SetSortMode ( TABLE_SORT_MODE_ASC ) ;
2026-03-29 13:06:34 +07:00
}
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 ( ) ) ;
2026-03-29 15:55:22 +07:00
2026-03-29 15:13:53 +07:00
//--- Этот блок кода - часть мероприятий по поиску и устранению артефактов при перетаскивании заголовков
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)
2026-03-29 15:55:22 +07:00
CPanel * obj = this . GetContainer ( ) ;
if ( obj = = NULL )
return false ;
CTableView * table_view = obj . GetContainer ( ) ;
2026-03-29 15:13:53 +07:00
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 ;
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| 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 )
2026-03-29 15:13:53 +07:00
{
2026-03-29 13:06:34 +07:00
caption_view . Draw ( false ) ;
2026-03-29 15:13:53 +07:00
}
2026-03-29 13:06:34 +07:00
}
//--- Если указано - обновляем график
if ( chart_redraw )
: : ChartRedraw ( this . m_chart_id ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| CTableHeaderView::Устанавливает флаг возможности сортировки |
//+------------------------------------------------------------------+
void CTableHeaderView : : SetSortableFlag ( const bool flag )
{
//--- Записываем значение флага
this . m_sortable = flag ;
//--- В цикле по количеству заголовков столбцов
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 . SetSortableFlag ( flag ) ;
}
//--- Если сортируемая таблица - ставим нулевой столбец сортированным по возрастанию
if ( this . m_sortable )
this . SetSortedColumnCaption ( 0 ) ;
//--- Перерисовываем заголовок
this . Draw ( true ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| CTableHeaderView::Устанавливает заголовку столбца флаг сортировки|
//+------------------------------------------------------------------+
void CTableHeaderView : : SetSortedColumnCaption ( const uint index )
{
int total = this . m_list_bounds . Total ( ) ;
for ( int i = 0 ; i < total ; i + + )
{
2026-03-29 15:55:22 +07:00
//--- Получаем очередной объект заголовка столбца
2026-03-29 15:13:53 +07:00
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 ) ;
}
}
2026-03-29 15:55:22 +07:00
//--- Перерисовываем заголовок
2026-03-29 15:13:53 +07:00
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 + + )
{
2026-03-29 15:55:22 +07:00
//--- Получаем область очередного заголовка столбца и
//--- из неё получаем присоединённый объект заголовка столбца
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 , 6 , capt_str .Length ( ) -8 ) ;
//--- Первый символ перед "FG" (последняя цифра искомого индекса)
int pos = ( int ) capt_str .Length ( ) -3 ;
int end = pos ;
//--- Ищем все цифры слева до первой "не цифры"
while ( ! : : IsStopped ( ) & & pos > = 0 & & capt_str .GetChar ( pos ) > = ' 0 ' & & capt_str .GetChar ( pos ) < = ' 9 ' )
pos - - ;
//--- Начало цифр искомого индекса
int start = pos + 1 ;
//--- Если цифры индекса не найдены - уходим
if ( start > end )
return ;
//--- Получаем индекс из строки
index_str = StringSubstr ( capt_str , start , end - start + 1 ) ;
//--- Записываем индекс заголовка столбца
int index = ( int ) : : StringToInteger ( index_str ) ;
//--- Получаем заголовок столбца по индексу
CColumnCaptionView * caption = this . GetColumnCaption ( index ) ;
if ( caption = = NULL )
return ;
//--- Если заголовок не имеет флага сортировки - ставим флаг сортировки по возрастанию
if ( caption . IsSortabe ( ) & & 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 , - ( 10000 + index ) , - ( 10000 + caption . SortMode ( ) ) , this . NameFG ( ) ) ;
: : ChartRedraw ( this . m_chart_id ) ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс визуального представления заголовка строк таблицы |
//+------------------------------------------------------------------+
class CTableRowsHeaderView : public CPanel
{
protected :
CRowCaptionView m_temp_caption ; // Временный объект заголовка строки для поиска
string m_table_row_columns [ ] ; // Массив заголовков строк таблицы
//--- Создаёт и добавляет в список новый объект представления заголовка строки
CRowCaptionView * InsertNewRowCaptionView ( const string text , const int x , const int y , const int w , const int h ) ;
public :
//--- (1) Устанавливает массив заголовков строк таблицы
bool TableRowCaptionsAssign ( string & captions_array [ ] ) ;
//--- Перерассчитывает области заголовков
bool RecalculateBounds ( CBound * bound , int new_width ) ;
//--- Распечатывает в журнале назначенную модель заголовка таблицы
void TableRowHeaderModelPrint ( void ) { : : ArrayPrint ( this . m_table_row_columns ) ; }
//--- Рисует внешний вид
virtual void Draw ( const bool chart_redraw ) ;
//--- Получает заголовок строки по индексу
CRowCaptionView * GetRowCaption ( const uint index ) ;
//--- Виртуальные методы (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_ROWS_HEADER_VIEW ) ; }
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( void ) ;
virtual void InitColors ( void ) ;
//--- Конструкторы/деструктор
CTableRowsHeaderView ( void ) ;
CTableRowsHeaderView ( 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 ) ;
~ CTableRowsHeaderView ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CTableRowsHeaderView::Конструктор по умолчанию. Строит объект в |
//| главном окне текущего графика в координатах 0,0 |
//| с размерами по умолчанию |
//+------------------------------------------------------------------+
CTableRowsHeaderView : : CTableRowsHeaderView ( void ) : CPanel ( " TableRowHeader " , " " , : : ChartID ( ) , 0 , 0 , 0 , DEF_PANEL_W , DEF_TABLE_ROW_H )
{
//--- Инициализация
this .Init ( ) ;
}
//+------------------------------------------------------------------+
//| CTableRowsHeaderView::Конструктор параметрический. Строит объект |
//| в указанном окне указанного графика с указанными текстом, |
//| координатами и размерами |
//+------------------------------------------------------------------+
CTableRowsHeaderView : : CTableRowsHeaderView ( 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 ( ) ;
}
//+------------------------------------------------------------------+
//| CTableRowsHeaderView::Инициализация |
//+------------------------------------------------------------------+
void CTableRowsHeaderView ::Init ( void )
{
//--- Инициализация родительского объекта
CPanel ::Init ( ) ;
//--- Цвет фона - непрозрачный
this . SetAlphaBG ( 255 ) ;
//--- Ширина рамки
this . SetBorderWidth ( 1 ) ;
}
//+------------------------------------------------------------------+
//| CTableRowsHeaderView::Инициализация цветов объекта по умолчанию |
//+------------------------------------------------------------------+
void CTableRowsHeaderView : : InitColors ( void )
{
//--- Инициализируем цвета заднего плана для обычного и активированного состояний и делаем его текущим цветом фона
this . InitBackColors ( C ' 230 , 230 , 230 ' , C ' 230 , 230 , 230 ' , C ' 230 , 230 , 230 ' , clrWhiteSmoke ) ;
this . InitBackColorsAct ( C ' 230 , 230 , 230 ' , C ' 230 , 230 , 230 ' , C ' 230 , 230 , 230 ' , 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 ) ;
}
//+------------------------------------------------------------------+
//| CTableRowsHeaderView::Создаёт и добавляет в список |
//| новый объект представления заголовка строки |
//+------------------------------------------------------------------+
CRowCaptionView * CTableRowsHeaderView : : InsertNewRowCaptionView ( const string text , const int x , const int y , const int w , const int h )
{
//--- Создаём наименование объекта и возвращаем результат создания нового заголовка столбца
string user_name = " RowCaptionView " + ( string ) this . m_list_elm . Total ( ) ;
CRowCaptionView * caption_view = this . InsertNewElement ( ELEMENT_TYPE_TABLE_ROW_CAPTION_VIEW , text , user_name , x , y , w , h ) ;
return ( caption_view ! = NULL ? caption_view : NULL ) ;
}
//+------------------------------------------------------------------+
//| CTableRowsHeaderView::Устанавливает вертикальный заголовок |
//+------------------------------------------------------------------+
bool CTableRowsHeaderView : : TableRowCaptionsAssign ( string & captions_array [ ] )
{
//--- Получаем указатель на объект таблицы (View)
CPanel * obj = this . GetContainer ( ) ;
if ( obj = = NULL )
return false ;
CTableView * table_view = obj . GetContainer ( ) ;
if ( table_view = = NULL )
return false ;
//--- Из объекта таблицы получаем указатель на панель со строками таблицы
CPanel * table_area = table_view . GetTableArea ( ) ;
if ( table_area = = NULL )
return false ;
//--- Получаем список строк таблицы
CListElm * list = table_area . GetListAttachedElements ( ) ;
int total_rows = list . Total ( ) ;
//--- Сохраняем переданный массив заголовков строк таблицы
: : ArrayCopy ( this . m_table_row_columns , captions_array ) ;
int total_captions = ( int ) this . m_table_row_columns .Size ( ) ;
//---
int total = : : fmax ( total_rows , total_captions ) ;
//--- Проходим в цикле по количеству создаваемых заголовков
for ( int i = 0 ; i < total ; i + + )
{
//--- получаем очередную строку
CTableRowView * row = table_area . GetAttachedElementAt ( i ) ;
if ( row = = NULL )
continue ;
//--- рассчитываем координату и создаём имя для области заголовка строки
int y = row . Height ( ) * i ;
string name = " CaptionBound " + ( string ) i ;
//--- Создаём новую область заголовка строки
CBound * caption_bound = this . InsertNewBound ( name , 0 , y , this . Width ( ) , row . Height ( ) ) ;
if ( caption_bound = = NULL )
return false ;
caption_bound . SetID ( row . ID ( ) ) ;
//--- Определяем текст для заголовка строки
//--- Если массив заголовков меньше, чем строк в таблице, то сначала заголовки будут иметь значения из массива, а затем - номера строк
//--- Если массив заголовков не имеет размера, то все строки будут озаглавлены порядковыми номерами
string text = ( this . m_table_row_columns .Size ( ) > 0 ? ( i < ( int ) this . m_table_row_columns .Size ( ) ? this . m_table_row_columns [ i ] : string ( i + 1 ) ) : string ( i + 1 ) ) ;
//--- Создаём новый объект визуального представления заголовка строки
CRowCaptionView * caption_view = this . InsertNewRowCaptionView ( text , 0 , y , this . Width ( ) , row . Height ( ) ) ;
if ( caption_view = = NULL )
return false ;
caption_view . SetIndex ( i ) ;
//--- На текущую область заголовка строки назначаем соответствующий объект визуального представления заголовка строки
caption_bound . AssignObject ( caption_view ) ;
caption_view . AssignBoundNode ( caption_bound ) ;
}
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//| CTableRowsHeaderView::Перерассчитывает области заголовков |
//+------------------------------------------------------------------+
bool CTableRowsHeaderView : : 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)
CPanel * obj = this . GetContainer ( ) ;
if ( obj = = NULL )
return false ;
CTableView * table_view = obj . 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 ) ;
}
2026-03-29 15:13:53 +07:00
}
2026-03-29 15:55:22 +07:00
//--- Перерисовываем все строки таблицы
table_area . Draw ( false ) ;
return true ;
2026-03-29 15:13:53 +07:00
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| CTableRowsHeaderView::Получает заголовок строки по индексу |
2026-03-29 13:06:34 +07:00
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
CRowCaptionView * CTableRowsHeaderView : : GetRowCaption ( const uint index )
2026-03-29 13:06:34 +07:00
{
2026-03-29 15:55:22 +07:00
//--- Получаем область заголовка строки по индексу
CBound * capt_bound = this . GetBoundAt ( index ) ;
if ( capt_bound = = NULL )
return NULL ;
//--- Из области заголовка строки возвращаем указатель на присоединённый объект заголовка строки
return capt_bound . GetAssignedObj ( ) ;
2026-03-29 13:06:34 +07:00
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| CTableRowsHeaderView::Рисует внешний вид |
2026-03-29 15:13:53 +07:00
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
void CTableRowsHeaderView : : Draw ( const bool chart_redraw )
2026-03-29 15:13:53 +07:00
{
2026-03-29 15:55:22 +07:00
//--- Заливаем объект цветом фона, рисуем линию строки и обновляем канвас фона
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 ) ;
2026-03-29 15:13:53 +07:00
2026-03-29 15:55:22 +07:00
//--- Рисуем заголовки строк
int total = this . m_list_bounds . Total ( ) ;
for ( int i = 0 ; i < total ; i + + )
2026-03-29 15:13:53 +07:00
{
2026-03-29 15:55:22 +07:00
//--- Получаем объект заголовка строки по индексу цикла
CRowCaptionView * caption_view = this . GetRowCaption ( i ) ;
//--- Рисуем визуальное представление заголовка строки
if ( caption_view ! = NULL )
{
caption_view . Draw ( false ) ;
}
2026-03-29 15:13:53 +07:00
}
2026-03-29 15:55:22 +07:00
//--- Если указано - обновляем график
if ( chart_redraw )
: : ChartRedraw ( this . m_chart_id ) ;
2026-03-29 15:13:53 +07:00
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//+------------------------------------------------------------------+
//| Класс визуального представления таблицы |
//+------------------------------------------------------------------+
class CTableView : public CPanel
{
2026-03-29 15:55:22 +07:00
private :
int m_rows_header_panel_w ; // Ширина при создании панели заголовка строк таблицы
2026-03-29 13:06:34 +07:00
protected :
//--- Получаемые данные таблицы
CTable * m_table_obj ; // Указатель на объект таблицы (включает модели таблицы и заголовка)
CTableModel * m_table_model ; // Указатель на модель таблицы (получаем из CTable)
CTableHeader * m_header_model ; // Указатель на модель заголовка таблицы (получаем из CTable)
//--- Данные компонента View
2026-03-29 15:55:22 +07:00
CPanel * m_header_panel ; // Панель для размещения заголовка таблицы
2026-03-29 13:06:34 +07:00
CTableHeaderView * m_header_view ; // Указатель на заголовок таблицы (View)
2026-03-29 15:55:22 +07:00
CPanel * m_rows_header_panel ; // Панель для размещения заголовка строк таблицы
CTableRowsHeaderView * m_rows_header_view ; // Указатель на заголовок строк таблицы (View)
2026-03-29 13:06:34 +07:00
CPanel * m_table_area ; // Панель для размещения строк таблицы
CContainer * m_table_area_container ; // Контейнер для размещения панели со строками таблицы
2026-03-29 15:55:22 +07:00
bool m_sortable ; // Флаг сортируемой таблицы
2026-03-29 13:06:34 +07:00
//--- (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 ; }
2026-03-29 15:55:22 +07:00
//--- (1) Устанавливает требуемый размер панели заголовка строк, (2) возвращает ширину заголовка строк таблицы
void SetRowsHeaderPanelSize ( const int width ) { this . m_rows_header_panel_w = width ; }
int RowsHeaderWidth ( void ) const
{
return ( this . m_rows_header_view ! = NULL ? this . m_rows_header_view . Width ( ) : 0 ) ;
}
2026-03-29 13:06:34 +07:00
2026-03-29 15:55:22 +07:00
//--- Создаёт из модели объект (1) таблицы, (2-3) заголовка, (4) обновляет изменённую таблицу
2026-03-29 13:06:34 +07:00
bool CreateTable ( void ) ;
2026-03-29 15:55:22 +07:00
bool CreateHeader ( void ) ;
public :
bool CreateRowsHeader ( string & captions_array [ ] ) ;
2026-03-29 15:13:53 +07:00
bool UpdateTable ( void ) ;
2026-03-29 13:06:34 +07:00
//--- (1) Устанавливает, (2) возвращает объект таблицы
bool TableObjectAssign ( CTable * table_obj ) ;
CTable * GetTableObj ( void ) { return this . m_table_obj ; }
2026-03-29 15:55:22 +07:00
//--- Возвращает (1-2) заголовок, (3) область размещения таблицы, (4) контейнер области таблицы
2026-03-29 15:13:53 +07:00
CTableHeaderView * GetHeader ( void ) { return this . m_header_view ; }
2026-03-29 15:55:22 +07:00
CTableRowsHeaderView * GetRowsHeader ( void ) { return this . m_rows_header_view ; }
2026-03-29 15:13:53 +07:00
CPanel * GetTableArea ( void ) { return this . m_table_area ; }
CContainer * GetTableAreaContainer ( void ) { return this . m_table_area_container ; }
2026-03-29 13:06:34 +07:00
//--- Распечатывает в журнале назначенную модель (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 ) ;
2026-03-29 15:13:53 +07:00
//--- Получает заголовок столбца (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 ) ; }
2026-03-29 15:55:22 +07:00
//--- Возвращает объект визуального представления указанной (1) строки, (2) ячейки
2026-03-29 15:13:53 +07:00
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 ) ; }
2026-03-29 15:55:22 +07:00
//--- Возвращает количество ячеек в указанной строке таблицы
int CellsInRow ( const uint row )
{ return ( this . GetRowView ( row ) ! = NULL ? this . GetRowView ( row ) . CellsTotal ( ) : 0 ) ; }
2026-03-29 13:06:34 +07:00
2026-03-29 15:55:22 +07:00
//--- Устанавливает метод подсветки строк
void SetRowsHighlightMode ( const ENUM_ROWS_HIGHLIGHT_MODE mode ) ;
//--- (1) Устанавливает, (2) возвращает флаг сортируемой таблицы
void SetSortable ( const bool flag ) ;
bool IsSortable ( void ) const { return this . m_sortable ; }
2026-03-29 13:06:34 +07:00
//--- Рисует внешний вид
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 ) ;
2026-03-29 15:13:53 +07:00
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 ) ;
2026-03-29 13:06:34 +07:00
//--- Инициализация (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 ) ,
2026-03-29 15:55:22 +07:00
m_table_model ( NULL ) , m_header_model ( NULL ) , m_table_obj ( NULL ) , m_header_view ( NULL ) , m_rows_header_view ( NULL ) ,
m_table_area ( NULL ) , m_table_area_container ( NULL ) , m_rows_header_panel_w ( 0 ) , m_sortable ( true )
2026-03-29 13:06:34 +07:00
{
//--- Инициализация
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 ) :
2026-03-29 15:55:22 +07:00
CPanel ( object_name , text , chart_id , wnd , x , y , w , h ) , m_table_model ( NULL ) , m_header_model ( NULL ) , m_rows_header_view ( NULL ) , m_table_obj ( NULL ) , m_header_view ( NULL ) ,
m_table_area ( NULL ) , m_table_area_container ( NULL ) , m_rows_header_panel_w ( 0 ) , m_sortable ( true )
2026-03-29 13:06:34 +07:00
{
//--- Инициализация
this .Init ( ) ;
}
//+------------------------------------------------------------------+
//| CTableView::Инициализация |
//+------------------------------------------------------------------+
void CTableView ::Init ( void )
{
//--- Инициализация родительского объекта
CPanel ::Init ( ) ;
2026-03-29 15:55:22 +07:00
//--- Ширина рамки, непрозрачность
2026-03-29 13:06:34 +07:00
this . SetBorderWidth ( 1 ) ;
2026-03-29 15:55:22 +07:00
this . SetAlphaBG ( 255 ) ;
this . SetAlphaFG ( 255 ) ;
//--- Инициализируем цвета заднего плана панели и делаем его текущим цветом фона
this . InitBackColors ( C ' 230 , 230 , 230 ' , C ' 230 , 230 , 230 ' , C ' 230 , 230 , 230 ' , clrSilver ) ;
this . BackColorToDefault ( ) ;
//--- Инициализируем цвета рамки панели и делаем его текущим цветом рамки
this . InitBorderColors ( C ' 180 , 180 , 180 ' , C ' 180 , 180 , 180 ' , C ' 180 , 180 , 180 ' , clrSilver ) ;
this . BorderColorToDefault ( ) ;
//--- Смещение координаты X для заголовка и строк таблицы (ширина вертикального заголовка строк)
int dx = ( int ) : : StringToInteger ( this . Text ( ) ) ;
this . m_rows_header_panel_w = dx ;
this . SetText ( " " ) ;
if ( dx > DEF_TABLE_ROWS_HEADER_W )
dx + = 12 ;
//--- Координаты и размеры панели заголовка таблицы (заголовок таблицы горизонтальный)
int x = 1 + dx ;
int y = 1 ;
int w = this . Width ( ) -2 - dx ;
int h = DEF_TABLE_HEADER_H ;
//--- Создаём панель для заголовка таблицы
this . m_header_panel = this . InsertNewElement ( ELEMENT_TYPE_PANEL , " " , " TableHeaderPanel " , x , y , w , h ) ;
if ( this . m_header_panel = = NULL )
return ;
//--- Инициализируем цвета заднего плана панели и делаем его текущим цветом фона
this . m_header_panel . InitBackColors ( C ' 230 , 230 , 230 ' , C ' 230 , 230 , 230 ' , C ' 230 , 230 , 230 ' , clrSilver ) ;
this . m_header_panel . BackColorToDefault ( ) ;
this . m_header_panel . SetBorderWidth ( 0 ) ;
this . m_header_panel . SetAlphaBG ( 255 ) ;
2026-03-29 13:06:34 +07:00
//--- Создаём заголовок таблицы
2026-03-29 15:55:22 +07:00
this . m_header_view = this . m_header_panel . InsertNewElement ( ELEMENT_TYPE_TABLE_HEADER_VIEW , " " , " TableHeader " , 0 , 0 , this . m_header_panel . Width ( ) , this . m_header_panel . Height ( ) ) ;
2026-03-29 13:06:34 +07:00
if ( this . m_header_view = = NULL )
return ;
2026-03-29 15:55:22 +07:00
this . m_header_view . SetBorderWidth ( 0 ) ;
//--- Координаты и размеры панели для заголовка строк таблицы (заголовок таблицы вертикальный)
x = 1 ;
y = DEF_TABLE_HEADER_H ;
w = ( dx > 0 ? dx : 1 ) ;
h = this . Height ( ) -2 - DEF_TABLE_HEADER_H ;
//--- Создаём панель
this . m_rows_header_panel = this . InsertNewElement ( ELEMENT_TYPE_PANEL , " " , " TableRowsHeaderPanel " , x , y , w , h ) ;
if ( this . m_rows_header_panel = = NULL )
return ;
//--- Инициализируем цвета заднего плана панели и делаем его текущим цветом фона
this . m_rows_header_panel . InitBackColors ( C ' 230 , 230 , 230 ' , C ' 230 , 230 , 230 ' , C ' 230 , 230 , 230 ' , clrSilver ) ;
this . m_rows_header_panel . BackColorToDefault ( ) ;
this . m_rows_header_panel . SetBorderWidth ( 0 ) ;
this . m_rows_header_panel . SetAlphaBG ( 255 ) ;
//--- Создаём заголовок строк таблицы
this . m_rows_header_view = this . m_rows_header_panel . InsertNewElement ( ELEMENT_TYPE_TABLE_ROWS_HEADER_VIEW , " " , " TableRowsHeader " , 0 , 0 , this . m_rows_header_panel . Width ( ) , this . m_rows_header_panel . Height ( ) ) ;
if ( this . m_rows_header_view = = NULL )
return ;
this . m_rows_header_view . SetBorderWidth ( 0 ) ;
this . m_rows_header_view . SetAlphaBG ( 0 ) ;
if ( this . m_rows_header_panel_w = = 0 )
this . m_rows_header_view . Hide ( false ) ;
//--- Координаты и размеры контейнера, в котором будет находиться панель строк таблицы
x = 1 + dx ;
y = 1 + DEF_TABLE_HEADER_H ;
w = this . Width ( ) -2 - dx ;
h = this . Height ( ) -2 - DEF_TABLE_HEADER_H ;
//--- Создаём контейнер
this . m_table_area_container = this . InsertNewElement ( ELEMENT_TYPE_CONTAINER , " " , " TableAreaContainer " , x , y , w , h ) ;
2026-03-29 13:06:34 +07:00
if ( this . m_table_area_container = = NULL )
return ;
this . m_table_area_container . SetBorderWidth ( 0 ) ;
this . m_table_area_container . SetScrollable ( true ) ;
//--- Присоединяем к контейнеру панель для хранения строк таблицы
2026-03-29 15:55:22 +07:00
this . m_table_area = this . m_table_area_container . InsertNewElement ( ELEMENT_TYPE_PANEL , " " , " TableAreaPanel " , 0 , 0 , this . m_table_area_container . Width ( ) -0 , this . m_table_area_container . Height ( ) -0 ) ;
2026-03-29 13:06:34 +07:00
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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| CTableView::Создаёт объект заголовка строк |
//+------------------------------------------------------------------+
bool CTableView : : CreateRowsHeader ( string & captions_array [ ] )
{
if ( this . m_rows_header_view = = NULL )
{
: : PrintFormat ( " %s: Error. Table rows header object not created " , __FUNCTION__ ) ;
return false ;
}
return this . m_rows_header_view . TableRowCaptionsAssign ( captions_array ) ;
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| CTableView::Создаёт из модели объект таблицы |
//+------------------------------------------------------------------+
bool CTableView : : CreateTable ( void )
{
if ( this . m_table_area = = NULL )
return false ;
2026-03-29 15:55:22 +07:00
2026-03-29 15:13:53 +07:00
//--- В цикле создаём и присоединяем к элементу Panel (m_table_area) RowsTotal строк из элементов TableRowView
2026-03-29 13:06:34 +07:00
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 + + )
{
//--- Создаём и присоединяем к панели объект строки таблицы
2026-03-29 15:13:53 +07:00
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 ) ;
2026-03-29 13:06:34 +07:00
if ( row = = NULL )
return false ;
//--- Устанавливаем идентификатор строки
row . SetID ( i ) ;
2026-03-29 15:55:22 +07:00
row . SetIndex ( i ) ;
2026-03-29 13:06:34 +07:00
//--- В зависимости от номера строки (чет/нечет) устанавливаем цвет её фона
if ( row . ID ( ) % 2 = = 0 )
row . InitBackColorDefault ( clrWhite ) ;
else
2026-03-29 15:13:53 +07:00
row . InitBackColorDefault ( C ' 242 , 242 , 242 ' ) ;
2026-03-29 13:06:34 +07:00
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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 ) ;
2026-03-29 15:55:22 +07:00
row . SetIndex ( i ) ;
2026-03-29 15:13:53 +07:00
//--- В зависимости от номера строки (чет/нечет) устанавливаем цвет её фона
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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| CTableView::Рисует внешний вид |
//+------------------------------------------------------------------+
void CTableView : : Draw ( const bool chart_redraw )
{
2026-03-29 15:55:22 +07:00
//--- Рисуем основу
CPanel : : Draw ( false ) ;
2026-03-29 13:06:34 +07:00
//--- Рисуем заголовок и строки таблицы
2026-03-29 15:55:22 +07:00
if ( this . m_header_view ! = NULL )
this . m_header_view . Draw ( false ) ;
if ( this . m_table_area_container ! = NULL )
this . m_table_area_container . Draw ( false ) ;
//--- Устанавливаем смещение и размеры области изображенеия
int x = this . m_rows_header_panel . Width ( ) -16 ;
int y = this . m_header_panel . Height ( ) -16 ;
int w = 11 ;
int h = w ;
//--- Очищаем область и рисуем угол
m_painter . Clear ( x , y , w , h , false ) ;
m_painter . TriangleRB ( x , y , w , h , BorderColor ( ) , AlphaFG ( ) , true ) ;
2026-03-29 13:06:34 +07:00
//--- Если указано - обновляем график
if ( chart_redraw )
: : ChartRedraw ( this . m_chart_id ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| CTableView::Устанавливает метод подсветки строк |
//+------------------------------------------------------------------+
void CTableView : : SetRowsHighlightMode ( const ENUM_ROWS_HIGHLIGHT_MODE highlight_mode )
{
int total = this . RowsTotal ( ) ;
for ( int i = 0 ; i < total ; i + + )
{
CTableRowView * row = this . GetRowView ( i ) ;
if ( row ! = NULL )
row . SetHighlightMode ( highlight_mode ) ;
}
}
//+------------------------------------------------------------------+
//| CTableView::Устанавливает флаг сортируемой таблицы |
//+------------------------------------------------------------------+
void CTableView : : SetSortable ( const bool flag )
{
this . m_sortable = flag ;
CTableHeaderView * header = this . GetHeader ( ) ;
if ( header ! = NULL )
header . SetSortableFlag ( flag ) ;
}
//+------------------------------------------------------------------+
2026-03-29 13:06:34 +07:00
//| 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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| 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 передаются координаты курсора,
//--- то для этого обработчика передаётся отрицательное значение индекса заголовка, по которому было событие
2026-03-29 15:55:22 +07:00
int index = ( int ) : : fabs ( lparam + 10000 ) ;
2026-03-29 15:13:53 +07:00
//--- Получаем заголовок столбца по индексу
CColumnCaptionView * caption = this . GetColumnCaption ( index ) ;
if ( caption = = NULL )
return ;
//--- Сортируем список строк по значению сортировки в заголовке столбца и обновляем таблицу
2026-03-29 15:55:22 +07:00
if ( this .Sort ( index , caption . SortMode ( ) ) & & this . UpdateTable ( ) )
2026-03-29 15:13:53 +07:00
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
2026-03-29 15:55:22 +07:00
if ( this . m_header_model = = NULL | | ! this . m_sortable | | sort_mode = = TABLE_SORT_MODE_NONE )
2026-03-29 15:13:53 +07:00
return false ;
//--- Устанавливаем флаг направления сортировки и сортируем модель таблицы по указанному столбцу и направлению
bool descending = ( sort_mode = = TABLE_SORT_MODE_DESC ) ;
this . m_table_model . SortByColumn ( column , descending ) ;
//--- Успешно
return true ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| Класс управления таблицами |
2026-03-29 15:13:53 +07:00
//+------------------------------------------------------------------+
class CTableControl : public CPanel
{
2026-03-29 15:55:22 +07:00
private :
//--- Возвращает максимальное значение целочисленного массива
bool ArrayMaximumValue ( int & array [ ] , int & value ) ;
//--- Возвращает максимальную ширину текста в массиве заголовков строк
int GetMaximumRowCaptionTextSize ( string & array_row_captions [ ] ) ;
2026-03-29 15:13:53 +07:00
protected :
CListObj m_list_table_model ;
//--- Добавляет объект (1) модели (CTable), (2) визуального представления (CTableView) таблицы в список
bool TableModelAdd ( CTable * table_model , const int table_id , const string source ) ;
2026-03-29 15:55:22 +07:00
CTableView * TableViewAdd ( CTable * table_model , string & row_names [ ] , const string source ) ;
2026-03-29 15:13:53 +07:00
//--- Обновляет указанный столбец указанной таблицы
bool ColumnUpdate ( const string source , CTable * table_model , const uint table , const uint col , const bool cells_redraw ) ;
public :
//--- Возвращает (1) модель, (2) объект визуального представления таблицы, (3) тип объекта
2026-03-29 15:55:22 +07:00
CTable * GetTableModel ( const uint index ) { return this . m_list_table_model . GetNodeAtIndex ( index ) ; }
2026-03-29 15:13:53 +07:00
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 ) ;
2026-03-29 15:55:22 +07:00
template < typename T >
CTableView * TableCreate ( T & row_data [ ] [ ] , const string & column_names [ ] , string & row_names [ ] , const int table_id = WRONG_VALUE ) ;
CTableView * TableCreate ( const uint num_rows , const uint num_columns , string & row_names [ ] , const int table_id = WRONG_VALUE ) ;
CTableView * TableCreate ( const matrix & row_data , const string & column_names [ ] , string & row_names [ ] , const int table_id = WRONG_VALUE ) ;
CTableView * TableCreate ( CList & row_data , const string & column_names [ ] , string & row_names [ ] , const int table_id = WRONG_VALUE ) ;
2026-03-29 15:13:53 +07:00
//--- Возвращает (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 ) ;
2026-03-29 15:55:22 +07:00
//--- Устанавливает цвет (1) переднего, (2) заднего плана в указанную ячейку (View)
2026-03-29 15:13:53 +07:00
void CellSetForeColor ( const uint table , const uint row , const uint col , const color clr , const bool chart_redraw ) ;
2026-03-29 15:55:22 +07:00
void CellSetBackColor ( const uint table , const uint row , const uint col , const color clr , const bool chart_redraw ) ;
2026-03-29 15:13:53 +07:00
//--- (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 ) ;
2026-03-29 15:55:22 +07:00
//--- Возвращает количество (1) строк, (2) ячеек в строке в указанной таблице
uint RowsTotal ( const uint table ) ;
uint CellsInRow ( const uint table , const uint row ) ;
//--- Устанавливает (1) режим подсветки строк, (2) возможность сортировки указанной таблицы
void SetRowsHighlightMode ( const uint table , const ENUM_ROWS_HIGHLIGHT_MODE highlight_mode ) ;
void SetSortable ( const uint table , const bool flag ) ;
2026-03-29 15:13:53 +07:00
//--- Тип объекта
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 " ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| Возвращает максимальное значение целочисленного массива |
//+------------------------------------------------------------------+
bool CTableControl : : ArrayMaximumValue ( int & array [ ] , int & value )
{
: : ResetLastError ( ) ;
int index = : : ArrayMaximum ( array ) ;
if ( index < 0 )
{
: : PrintFormat ( " %s: ArrayMaximum() failed. Error %d " , __FUNCTION__ , : : GetLastError ( ) ) ;
return false ;
}
value = array [ index ] ;
return true ;
}
//+------------------------------------------------------------------+
//| Возвращает максимальную ширину текста в массиве заголовков строк |
//+------------------------------------------------------------------+
int CTableControl : : GetMaximumRowCaptionTextSize ( string & row_captions [ ] )
{
int total = ( int ) row_captions .Size ( ) ;
if ( total = = 0 )
return 0 ;
int array [ ] = { } ;
: : ArrayResize ( array , total ) ;
for ( int i = 0 ; i < total ; i + + )
{
string text = row_captions [ i ] ;
text .TrimLeft ( ) ;
text .TrimRight ( ) ;
array [ i ] = this . m_foreground . TextWidth ( text ) ;
}
int value = 0 ;
return ( this . ArrayMaximumValue ( array , value ) ? value : 0 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| Добавляет объект модели таблицы (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) |
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
CTableView * CTableControl : : TableViewAdd ( CTable * table_model , string & row_names [ ] , const string source )
2026-03-29 15:13:53 +07:00
{
//--- Проверяем объект модели таблицы
if ( table_model = = NULL )
{
: : PrintFormat ( " %s::%s: Error. An invalid Table Model object was passed " , source , __FUNCTION__ ) ;
return NULL ;
}
2026-03-29 15:55:22 +07:00
//--- Получаем максимальную ширину текста заголовков строк
int w = this . GetMaximumRowCaptionTextSize ( row_names ) ;
if ( w > 0 & & w < DEF_TABLE_ROWS_HEADER_W )
w = DEF_TABLE_ROWS_HEADER_W ;
2026-03-29 15:13:53 +07:00
//--- Создаём новый элемент - визуальное представление таблицы, прикреплённый к панели
2026-03-29 15:55:22 +07:00
CTableView * table_view = this . InsertNewElement ( ELEMENT_TYPE_TABLE_VIEW , ( string ) w , " TableView " + ( string ) table_model . ID ( ) , 1 , 1 , this . Width ( ) -2 , this . Height ( ) -2 ) ;
2026-03-29 15:13:53 +07:00
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 ) ;
2026-03-29 15:55:22 +07:00
table_view . CreateRowsHeader ( row_names ) ;
2026-03-29 15:13:53 +07:00
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 ;
2026-03-29 15:55:22 +07:00
//--- Создаём и возвращаем таблицу с пустым массивом заголовков строк
string array [ ] = { } ;
return this . TableViewAdd ( table_model , array , __FUNCTION__ ) ;
2026-03-29 15:13:53 +07:00
}
//+------------------------------------------------------------------+
//| Создаёт таблицу с определением количества колонок и строк. |
//| Колонки будут иметь 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 ;
2026-03-29 15:55:22 +07:00
//--- Создаём и возвращаем таблицу с пустым массивом заголовков строк
string array [ ] = { } ;
return this . TableViewAdd ( table_model , array , __FUNCTION__ ) ;
2026-03-29 15:13:53 +07:00
}
//+------------------------------------------------------------------+
//| Создаёт таблицу с инициализацией колонок согласно 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 ;
2026-03-29 15:55:22 +07:00
//--- Создаём и возвращаем таблицу с пустым массивом заголовков строк
string array [ ] = { } ;
return this . TableViewAdd ( table_model , array , __FUNCTION__ ) ;
2026-03-29 15:13:53 +07:00
}
//+------------------------------------------------------------------+
//| Создаёт таблицу с указанием массива таблицы на основе |
//| списка 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 ;
2026-03-29 15:55:22 +07:00
//--- Создаём и возвращаем таблицу с пустым массивом заголовков строк
string array [ ] = { } ;
return this . TableViewAdd ( table_model , array , __FUNCTION__ ) ;
}
//+-------------------------------------------------------------------+
//| Создаёт таблицу с указанием массива таблицы и массива заголовков. |
//| Определяет количество и наименования колонок согласно column_names|
//| Количество строк определены размером массива данных row_data, |
//| который используется и для заполнения таблицы |
//+-------------------------------------------------------------------+
template < typename T >
CTableView * CTableControl : : TableCreate ( T & row_data [ ] [ ] , const string & column_names [ ] , string & row_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 , row_names , __FUNCTION__ ) ;
}
//+------------------------------------------------------------------+
//| Создаёт таблицу с определением количества колонок и строк. |
//| Колонки будут иметь Excel-наименования "A", "B", "C" и т.д. |
//+------------------------------------------------------------------+
CTableView * CTableControl : : TableCreate ( const uint num_rows , const uint num_columns , string & row_names [ ] , 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 , row_names , __FUNCTION__ ) ;
}
//+------------------------------------------------------------------+
//| Создаёт таблицу с инициализацией колонок согласно column_names |
//| Количество строк определены параметром row_data, с типом matrix |
//+------------------------------------------------------------------+
CTableView * CTableControl : : TableCreate ( const matrix & row_data , const string & column_names [ ] , string & row_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 , row_names , __FUNCTION__ ) ;
}
//+------------------------------------------------------------------+
//| Создаёт таблицу с указанием массива таблицы на основе |
//| списка row_data, содержащего объекты с данными полей структуры. |
//| Определяет количество и наименования колонок согласно количеству |
//| наименований столбцов в массиве column_names |
//+------------------------------------------------------------------+
CTableView * CTableControl : : TableCreate ( CList & row_data , const string & column_names [ ] , string & row_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 ;
2026-03-29 15:13:53 +07:00
//--- Создаём и возвращаем таблицу
2026-03-29 15:55:22 +07:00
return this . TableViewAdd ( table_model , row_names , __FUNCTION__ ) ;
2026-03-29 15:13:53 +07:00
}
//+------------------------------------------------------------------+
//| Устанавливает значение в указанную ячейку (Model + View) |
//+------------------------------------------------------------------+
template < typename T >
void CTableControl : : CellSetValue ( const uint table , const uint row , const uint col , const T value , const bool chart_redraw )
{
//--- Получаем модель таблицы
2026-03-29 15:55:22 +07:00
CTable * table_model = this . GetTableModel ( table ) ;
2026-03-29 15:13:53 +07:00
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 )
{
//--- Получаем модель таблицы
2026-03-29 15:55:22 +07:00
CTable * table_model = this . GetTableModel ( table ) ;
2026-03-29 15:13:53 +07:00
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 )
{
//--- Получаем модель таблицы
2026-03-29 15:55:22 +07:00
CTable * table_model = this . GetTableModel ( table ) ;
2026-03-29 15:13:53 +07:00
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 )
{
//--- Получаем модель таблицы
2026-03-29 15:55:22 +07:00
CTable * table_model = this . GetTableModel ( table ) ;
2026-03-29 15:13:53 +07:00
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 ;
2026-03-29 15:55:22 +07:00
//--- В объект визуального представления ячейки устанавливаем цвет текста ячейки
2026-03-29 15:13:53 +07:00
//--- Перерисовываем ячейку с флагом обновления графика
cell_view . SetForeColor ( clr ) ;
cell_view . Draw ( chart_redraw ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| Устанавливает цвет заднего плана в указанную ячейку (View) |
//+------------------------------------------------------------------+
void CTableControl : : CellSetBackColor ( 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 . SetBackColor ( clr ) ;
cell_view . Draw ( chart_redraw ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:13:53 +07:00
//| Устанавливает точку привязки текста в указанную ячейку (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 )
{
//--- Получаем модель таблицы
2026-03-29 15:55:22 +07:00
CTable * table_model = this . GetTableModel ( table ) ;
2026-03-29 15:13:53 +07:00
if ( table_model = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to get CTable object " , __FUNCTION__ ) ;
return ;
}
//--- Устанавливаем Digits для указанного столбца в модели таблицы
table_model . ColumnSetDigits ( col , digits ) ;
2026-03-29 13:06:34 +07:00
2026-03-29 15:13:53 +07:00
//--- Обновляем отображение данных столбца и, если указано, перерисовываем график
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 )
{
//--- Получаем модель таблицы
2026-03-29 15:55:22 +07:00
CTable * table_model = this . GetTableModel ( table ) ;
2026-03-29 15:13:53 +07:00
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 )
{
//--- Получаем модель таблицы
2026-03-29 15:55:22 +07:00
CTable * table_model = this . GetTableModel ( table ) ;
2026-03-29 15:13:53 +07:00
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 )
{
//--- Получаем модель таблицы
2026-03-29 15:55:22 +07:00
CTable * table_model = this . GetTableModel ( table ) ;
2026-03-29 15:13:53 +07:00
if ( table_model = = NULL )
{
2026-03-29 15:55:22 +07:00
: : PrintFormat ( " %s: Error. Failed to get CTable object " , __FUNCTION__ ) ;
2026-03-29 15:13:53 +07:00
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 )
{
2026-03-29 15:55:22 +07:00
CTable * table_model = this . GetTableModel ( table ) ;
2026-03-29 15:13:53 +07:00
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 ) ;
}
//+------------------------------------------------------------------+
2026-03-29 15:55:22 +07:00
//| Возвращает количество строк в указанной таблице |
//+------------------------------------------------------------------+
uint CTableControl : : RowsTotal ( const uint table )
{
CTableView * table_view = this . GetTableView ( table ) ;
if ( table_view = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to get CTableView object " , __FUNCTION__ ) ;
return NULL ;
}
return table_view . RowsTotal ( ) ;
}
//+------------------------------------------------------------------+
//| Возвращает количество ячеек в строке в указанной таблице |
//+------------------------------------------------------------------+
uint CTableControl : : CellsInRow ( const uint table , const uint row )
{
CTableRowView * row_view = this . GetRowView ( table , row ) ;
return ( row_view ! = NULL ? row_view . CellsTotal ( ) : 0 ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает режим подсветки строк указанной таблицы |
//+------------------------------------------------------------------+
void CTableControl : : SetRowsHighlightMode ( const uint table , const ENUM_ROWS_HIGHLIGHT_MODE highlight_mode )
{
CTableView * table_view = this . GetTableView ( table ) ;
if ( table_view = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to get CTableView object " , __FUNCTION__ ) ;
return ;
}
table_view . SetRowsHighlightMode ( highlight_mode ) ;
}
//+------------------------------------------------------------------+
//| Устанавливает возможность сортировки указанной таблицы |
//+------------------------------------------------------------------+
void CTableControl : : SetSortable ( const uint table , const bool flag )
{
CTableView * table_view = this . GetTableView ( table ) ;
if ( table_view = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to get CTableView object " , __FUNCTION__ ) ;
return ;
}
table_view . SetSortable ( flag ) ;
}
//+------------------------------------------------------------------+