2026-03-28 03:09:22 +07:00
//+------------------------------------------------------------------+
//| Controls.mqh |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
# property copyright " Copyright 2025, MetaQuotes Ltd. "
# property link " https://www.mql5.com "
//+------------------------------------------------------------------+
//| Включаемые библиотеки |
//+------------------------------------------------------------------+
# include "Base.mqh"
//+------------------------------------------------------------------+
//| Макроподстановки |
//+------------------------------------------------------------------+
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 / / Высота кнопки по умолчанию
# 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-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-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-28 03:09:22 +07:00
//+------------------------------------------------------------------+
//| Функции |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Классы |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
2026-03-28 12:12:49 +07:00
//| Класс связанного списка объектов |
//+------------------------------------------------------------------+
class CListObj : public CList
{
protected :
ENUM_ELEMENT_TYPE m_element_type ; // Тип создаваемого объекта в CreateElement()
public :
//--- Установка типа элемента
void SetElementType ( const ENUM_ELEMENT_TYPE type ) { this . m_element_type = type ; }
//--- Виртуальный метод (1) загрузки списка из файла, (2) создания элемента списка
virtual bool Load ( const int file_handle ) ;
virtual CObject * CreateElement ( void ) ;
} ;
//+------------------------------------------------------------------+
//| Загрузка списка из файла |
//+------------------------------------------------------------------+
bool CListObj : : Load ( const int file_handle )
{
//--- Переменные
CObject * node ;
bool result = true ;
//--- Проверяем хэндл
if ( file_handle = = INVALID_HANDLE )
return ( false ) ;
//--- Загрузка и проверка маркера начала списка - 0xFFFFFFFFFFFFFFFF
if ( : : FileReadLong ( file_handle ) ! = MARKER_START_DATA )
return ( false ) ;
//--- Загрузка и проверка типа списка
if ( : : FileReadInteger ( file_handle , INT_VALUE ) ! = this . Type ( ) )
return ( false ) ;
//--- Чтение размера списка (количество объектов)
uint num = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Последовательно заново создаём элементы списка с помощью вызова метода Load() объектов node
this . Clear ( ) ;
for ( uint i = 0 ; i < num ; i + + )
{
//--- Читаем и проверяем маркер начала данных объекта - 0xFFFFFFFFFFFFFFFF
if ( : : FileReadLong ( file_handle ) ! = MARKER_START_DATA )
return false ;
//--- Читаем тип объекта
this . m_element_type = ( ENUM_ELEMENT_TYPE ) : : FileReadInteger ( file_handle , INT_VALUE ) ;
node = this . CreateElement ( ) ;
if ( node = = NULL )
return false ;
this . Add ( node ) ;
//--- Сейчас файловый указатель смещён относительно начала маркера объекта на 12 байт (8 - маркер, 4 - тип)
//--- Поставим указатель на начало данных объекта и загрузим свойства объекта из файла методом Load() элемента node.
if ( ! : : FileSeek ( file_handle , -12 , SEEK_CUR ) )
return false ;
result & = node . Load ( file_handle ) ;
}
//--- Результат
return result ;
}
//+------------------------------------------------------------------+
//| Метод создания элемента списка |
//+------------------------------------------------------------------+
CObject * CListObj : : CreateElement ( void )
{
//--- В зависимости от типа объекта в m_element_type, создаём новый объект
switch ( this . m_element_type )
{
case ELEMENT_TYPE_BASE : return new CBaseObj ( ) ; // Базовый объект графических элементов
case ELEMENT_TYPE_COLOR : return new CColor ( ) ; // Объект цвета
case ELEMENT_TYPE_COLORS_ELEMENT : return new CColorElement ( ) ; // Объект цветов элемента графического объекта
case ELEMENT_TYPE_RECTANGLE_AREA : return new CBound ( ) ; // Прямоугольная область элемента
case ELEMENT_TYPE_IMAGE_PAINTER : return new CImagePainter ( ) ; // Объект для рисования изображений
case ELEMENT_TYPE_CANVAS_BASE : return new CCanvasBase ( ) ; // Базовый объект холста графических элементов
case ELEMENT_TYPE_ELEMENT_BASE : return new CElementBase ( ) ; // Базовый объект графических элементов
2026-03-28 12:36:14 +07:00
case ELEMENT_TYPE_HINT : return new CVisualHint ( ) ; // Подсказка
2026-03-28 12:12:49 +07:00
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_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 03:09:22 +07:00
//| Класс рисования изображений |
//+------------------------------------------------------------------+
class CImagePainter : public CBaseObj
{
protected :
CCanvas * m_canvas ; // Указатель на канвас, где рисуем
CBound m_bound ; // Координаты и границы изображения
uchar m_alpha ; // Прозрачность
//--- Проверяет валидность холста и корректность размеров
bool CheckBound ( void ) ;
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-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
//--- Виртуальные методы (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::Проверяет валидность холста и корректность размеров|
//+------------------------------------------------------------------+
bool CImagePainter : : CheckBound ( void )
{
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-28 12:36:14 +07:00
: : PrintFormat ( " %s: Error: (w %d, h %d). First you need to set the area size using the SetSize() or SetBound() methods " , __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
if ( ! this . CheckBound ( ) )
return false ;
//--- Очищаем прозрачным цветом всю область изображения
this . m_canvas . FillRectangle ( x , y , x + w -1 , y + h -1 , clrNULL ) ;
//--- Если указано - обновляем канвас
if ( update )
this . m_canvas . Update ( false ) ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//| CImagePainter::Рисует закрашенную стрелку вверх |
//+------------------------------------------------------------------+
bool CImagePainter : : ArrowUp ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true )
{
//--- Если область изображения не валидна - возвращаем false
if ( ! this . CheckBound ( ) )
return false ;
//--- Рассчитываем координаты углов стрелки внутри области изображения
int hw = ( int ) : : floor ( w / 2 ) ; // Половина ширины
if ( hw = = 0 )
hw = 1 ;
int x1 = x + 1 ; // X. Основание (левая точка)
int y1 = y + h - 4 ; // Y. Левая точка основания
int x2 = x1 + hw ; // X. Вершина (центральная верхняя точка)
int y2 = y + 3 ; // Y. Вершина (верхняя точка)
int x3 = x1 + w - 1 ; // X. Основание (правая точка)
int y3 = y1 ; // Y. Основание (правая точка)
//--- Рисуем треугольник
this . m_canvas . FillTriangle ( x1 , y1 , x2 , y2 , x3 , y3 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| CImagePainter::Рисует закрашенную стрелку вниз |
//+------------------------------------------------------------------+
bool CImagePainter : : ArrowDown ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true )
{
//--- Если область изображения не валидна - возвращаем false
if ( ! this . CheckBound ( ) )
return false ;
//--- Рассчитываем координаты углов стрелки внутри области изображения
int hw = ( int ) : : floor ( w / 2 ) ; // Половина ширины
if ( hw = = 0 )
hw = 1 ;
int x1 = x + 1 ; // X. Основание (левая точка)
int y1 = y + 4 ; // Y. Левая точка основания
int x2 = x1 + hw ; // X. Вершина (центральная нижняя точка)
int y2 = y + h -3 ; // Y. Вершина (нижняя точка)
int x3 = x1 + w -1 ; // X. Основание (правая точка)
int y3 = y1 ; // Y. Основание (правая точка)
//--- Рисуем треугольник
this . m_canvas . FillTriangle ( x1 , y1 , x2 , y2 , x3 , y3 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| CImagePainter::Рисует закрашенную стрелку влево |
//+------------------------------------------------------------------+
bool CImagePainter : : ArrowLeft ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true )
{
//--- Если область изображения не валидна - возвращаем false
if ( ! this . CheckBound ( ) )
return false ;
//--- Рассчитываем координаты углов стрелки внутри области изображения
int hh = ( int ) : : floor ( h / 2 ) ; // Половина высоты
if ( hh = = 0 )
hh = 1 ;
int x1 = x + w -4 ; // X. Основание (правая сторона)
int y1 = y + 1 ; // Y. Верхний угол основания
int x2 = x + 3 ; // X. Вершина (левая центральная точка)
int y2 = y1 + hh ; // Y. Центральная точка (вершина)
int x3 = x1 ; // X. Нижний угол основания
int y3 = y1 + h -1 ; // Y. Нижний угол основания
//--- Рисуем треугольник
this . m_canvas . FillTriangle ( x1 , y1 , x2 , y2 , x3 , y3 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| CImagePainter::Рисует закрашенную стрелку вправо |
//+------------------------------------------------------------------+
bool CImagePainter : : ArrowRight ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true )
{
//--- Если область изображения не валидна - возвращаем false
if ( ! this . CheckBound ( ) )
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
if ( ! this . CheckBound ( ) )
return false ;
//--- Координаты фигуры
int arrx [ 15 ] = { 0 , 3 , 4 , 4 , 12 , 12 , 13 , 16 , 13 , 12 , 12 , 4 , 4 , 3 , 0 } ;
int arry [ 15 ] = { 3 , 0 , 0 , 2 , 2 , 0 , 0 , 3 , 6 , 6 , 4 , 4 , 6 , 6 , 3 } ;
//--- Рисуем белую подложку
this . m_canvas . Polyline ( arrx , arry , : : ColorToARGB ( clrWhite , alpha ) ) ;
//--- Рисуем линию стрелок
this . m_canvas . Line ( 1 , 3 , 15 , 3 , : : ColorToARGB ( clr , alpha ) ) ;
//--- Рисуем левый треугольник
this . m_canvas . Line ( 1 , 3 , 1 , 3 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 2 , 2 , 2 , 4 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 3 , 1 , 3 , 5 , : : ColorToARGB ( clr , alpha ) ) ;
//--- Рисуем правый треугольник
this . m_canvas . Line ( 13 , 1 , 13 , 5 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 14 , 2 , 14 , 4 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 15 , 3 , 15 , 3 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| CImagePainter::Рисует вертикальную 7х17 двойную стрелку |
//+------------------------------------------------------------------+
bool CImagePainter : : ArrowVert ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true )
{
//--- Если область изображения не валидна - возвращаем false
if ( ! this . CheckBound ( ) )
return false ;
//--- Координаты фигуры
int arrx [ 15 ] = { 3 , 6 , 6 , 4 , 4 , 6 , 6 , 3 , 0 , 0 , 2 , 2 , 0 , 0 , 3 } ;
int arry [ 15 ] = { 0 , 3 , 4 , 4 , 12 , 12 , 13 , 16 , 13 , 12 , 12 , 4 , 4 , 3 , 0 } ;
//--- Рисуем белую подложку
this . m_canvas . Polyline ( arrx , arry , : : ColorToARGB ( clrWhite , alpha ) ) ;
//--- Рисуем линию стрелок
this . m_canvas . Line ( 3 , 1 , 3 , 15 , : : ColorToARGB ( clr , alpha ) ) ;
//--- Рисуем верхний треугольник
this . m_canvas . Line ( 3 , 1 , 3 , 1 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 2 , 2 , 4 , 2 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 1 , 3 , 5 , 3 , : : ColorToARGB ( clr , alpha ) ) ;
//--- Рисуем нижний треугольник
this . m_canvas . Line ( 1 , 13 , 5 , 13 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 2 , 14 , 4 , 14 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 3 , 15 , 3 , 15 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| CImagePainter::Рисует диагональную сверху-слева --- вниз-вправо |
//| 13х13 двойную стрелку (NorthWest-SouthEast) |
//+------------------------------------------------------------------+
bool CImagePainter : : ArrowNWSE ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true )
{
//--- Если область изображения не валидна - возвращаем false
if ( ! this . CheckBound ( ) )
return false ;
//--- Координаты фигуры
int arrx [ 19 ] = { 0 , 4 , 5 , 4 , 4 , 9 , 10 , 11 , 12 , 12 , 8 , 7 , 8 , 8 , 3 , 2 , 1 , 0 , 0 } ;
int arry [ 19 ] = { 0 , 0 , 1 , 2 , 3 , 8 , 8 , 7 , 8 , 12 , 12 , 11 , 10 , 9 , 4 , 4 , 5 , 4 , 0 } ;
//--- Рисуем белую подложку
this . m_canvas . Polyline ( arrx , arry , : : ColorToARGB ( clrWhite , alpha ) ) ;
//--- Рисуем линию стрелок
this . m_canvas . Line ( 3 , 3 , 9 , 9 , : : ColorToARGB ( clr , alpha ) ) ;
//--- Рисуем верхний-левый треугольник
this . m_canvas . Line ( 1 , 1 , 4 , 1 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 1 , 2 , 3 , 2 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 1 , 3 , 3 , 3 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 1 , 4 , 1 , 4 , : : ColorToARGB ( clr , alpha ) ) ;
//--- Рисуем нижний-правый треугольник
this . m_canvas . Line ( 11 , 8 , 11 , 8 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 9 , 9 , 11 , 9 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 9 , 10 , 11 , 10 , : : ColorToARGB ( clr , alpha ) ) ;
this . m_canvas . Line ( 8 , 11 , 11 , 11 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| CImagePainter::Рисует диагональную снизу-слева --- вверх-вправо |
//| 13х13 двойную стрелку (NorthEast-SouthWest) |
//+------------------------------------------------------------------+
bool CImagePainter : : ArrowNESW ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true )
{
//--- Если область изображения не валидна - возвращаем false
if ( ! this . CheckBound ( ) )
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
if ( ! this . CheckBound ( ) )
return false ;
//--- Координаты прямоугольника
int x1 = x + 1 ; // Левый верхний угол, X
int y1 = y + 1 ; // Левый верхний угол, Y
int x2 = x + w -2 ; // Правый нижний угол, X
int y2 = y + h -2 ; // Правый нижний угол, Y
//--- Рисуем прямоугольник
this . m_canvas . Rectangle ( x1 , y1 , x2 , y2 , : : ColorToARGB ( clr , alpha ) ) ;
//--- Координаты "галочки"
int arrx [ 3 ] , arry [ 3 ] ;
arrx [ 0 ] = x1 + ( x2 - x1 ) / 4 ; // X. Левая точка
arrx [ 1 ] = x1 + w / 3 ; // X. Центральная точка
arrx [ 2 ] = x2 - ( x2 - x1 ) / 4 ; // X. Правая точка
arry [ 0 ] = y1 + 1 + ( y2 - y1 ) / 2 ; // Y. Левая точка
arry [ 1 ] = y2 - ( y2 - y1 ) / 3 ; // Y. Центральная точка
arry [ 2 ] = y1 + ( y2 - y1 ) / 3 ; // Y. Правая точка
//--- Рисуем "галочку" линией двойной толщины
this . m_canvas . Polyline ( arrx , arry , : : ColorToARGB ( clr , alpha ) ) ;
arrx [ 0 ] + + ;
arrx [ 1 ] + + ;
arrx [ 2 ] + + ;
this . m_canvas . Polyline ( arrx , arry , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| CImagePainter::Рисует неотмеченный CheckBox |
//+------------------------------------------------------------------+
bool CImagePainter : : UncheckedBox ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true )
{
//--- Если область изображения не валидна - возвращаем false
if ( ! this . CheckBound ( ) )
return false ;
//--- Координаты прямоугольника
int x1 = x + 1 ; // Левый верхний угол, X
int y1 = y + 1 ; // Левый верхний угол, Y
int x2 = x + w -2 ; // Правый нижний угол, X
int y2 = y + h -2 ; // Правый нижний угол, Y
//--- Рисуем прямоугольник
this . m_canvas . Rectangle ( x1 , y1 , x2 , y2 , : : ColorToARGB ( clr , alpha ) ) ;
if ( update )
this . m_canvas . Update ( false ) ;
return true ;
}
//+------------------------------------------------------------------+
//| CImagePainter::Рисует отмеченный RadioButton |
//+------------------------------------------------------------------+
bool CImagePainter : : CheckedRadioButton ( const int x , const int y , const int w , const int h , const color clr , const uchar alpha , const bool update = true )
{
//--- Если область изображения не валидна - возвращаем false
if ( ! this . CheckBound ( ) )
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
if ( ! this . CheckBound ( ) )
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
if ( ! this . CheckBound ( ) )
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-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-28 12:36:14 +07:00
CListObj 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) удаляет из списка объекты-подсказки со стрелками
bool AddHintsArrowed ( void ) ;
bool DeleteHintsArrowed ( void ) ;
//--- Отображает курсор изменения размеров
bool ShowCursorHint ( const ENUM_CURSOR_REGION edge , int x , int y ) ;
//--- Обработчик перетаскивания граней и углов элемента
virtual void ResizeActionDragHandler ( const int x , const int y ) ;
//--- Обработчики изменения размеров элемента по сторонам и углам
virtual bool ResizeZoneLeftHandler ( const int x , const int y ) ;
virtual bool ResizeZoneRightHandler ( const int x , const int y ) ;
virtual bool ResizeZoneTopHandler ( const int x , const int y ) ;
virtual bool ResizeZoneBottomHandler ( const int x , const int y ) ;
virtual bool ResizeZoneLeftTopHandler ( const int x , const int y ) ;
virtual bool ResizeZoneRightTopHandler ( const int x , const int y ) ;
virtual bool ResizeZoneLeftBottomHandler ( const int x , const int y ) ;
virtual bool ResizeZoneRightBottomHandler ( const int x , const int y ) ;
//--- Возвращает указатель на подсказку по (1) индексу, (2) идентификатору, (3) наименованию
CVisualHint * GetHintAt ( const int index ) ;
CVisualHint * GetHint ( const int id ) ;
CVisualHint * GetHint ( const string name ) ;
//--- Создаёт новую подсказку
CVisualHint * CreateNewHint ( const ENUM_HINT_TYPE type , const string object_name , const string user_name , const int id , const int x , const int y , const int w , const int h ) ;
//--- (1) Отображает указанную подсказку со стрелками, (2) скрывает все подсказки
void ShowHintArrowed ( const ENUM_HINT_TYPE type , const int x , const int y ) ;
void HideHintsAll ( const bool chart_redraw ) ;
2026-03-28 12:12:49 +07:00
public :
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-28 12:36:14 +07:00
CListObj * GetListHints ( void ) { return & this . m_list_hints ; }
//--- Создаёт и добавляет (1) новый, (2) ранее созданный объект-подсказку (только тултип) в список
CVisualHint * InsertNewTooltip ( const ENUM_HINT_TYPE type , const string user_name , const int w , const int h ) ;
CVisualHint * InsertTooltip ( CVisualHint * obj , const int dx , const int dy ) ;
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 ) ;
~ CElementBase ( void ) { }
} ;
//+----------------------------------------------------------------------+
//| CElementBase::Конструктор параметрический. Строит элемент в указанном|
//| окне указанного графика с указанными текстом, координами и размерами |
//+----------------------------------------------------------------------+
CElementBase : : CElementBase ( const string object_name , const string text , const long chart_id , const int wnd , const int x , const int y , const int w , const int h ) :
CCanvasBase ( object_name , chart_id , wnd , x , y , w , h ) , m_group ( -1 )
{
//--- Объекту рисования назначаем канвас переднего плана и
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 ) ;
string area = : : StringFormat ( " x %d, y %d, w %d, h %d " , this . X ( ) , this . Y ( ) , this . Width ( ) , this . Height ( ) ) ;
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 ;
}
//--- Устанавливаем списку флаг сортировки по идентификатору
this . m_list_hints .Sort ( ELEMENT_SORT_BY_ID ) ;
//--- Если такого элемента нет в списке - возвращаем результат его добавления в список
if ( this . m_list_hints . Search ( obj ) = = NULL )
return ( this . m_list_hints . Add ( obj ) > -1 ) ;
//--- Элемент с таким идентификатором уже есть в списке - возвращаем 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
//--- Массивы наименований и типов подсказок
string array [ 4 ] = { " HintHORZ " , " HintVERT " , " HintNWSE " , " HintNESW " } ;
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 ) ;
hint = this . GetHint ( " HintHORZ " ) ;
break ;
//--- Курсор на верхней или нижней границе - вертикальная двойная стрелка
case CURSOR_REGION_TOP :
case CURSOR_REGION_BOTTOM :
hint_shift_x = 12 ;
hint_shift_y = 4 ;
this . ShowHintArrowed ( HINT_TYPE_ARROW_VERT , x + hint_shift_x , y + hint_shift_y ) ;
hint = this . GetHint ( " HintVERT " ) ;
break ;
//--- Курсор в левом верхнем или правом нижнем углу - диагональная двойная стрелка от лево-верх до право-низ
case CURSOR_REGION_LEFT_TOP :
case CURSOR_REGION_RIGHT_BOTTOM :
hint_shift_x = 10 ;
hint_shift_y = 2 ;
this . ShowHintArrowed ( HINT_TYPE_ARROW_NWSE , x + hint_shift_x , y + hint_shift_y ) ;
hint = this . GetHint ( " HintNWSE " ) ;
break ;
//--- Курсор в левом нижнем или правом верхнем углу - диагональная двойная стрелка от лево-низ до право-верх
case CURSOR_REGION_LEFT_BOTTOM :
case CURSOR_REGION_RIGHT_TOP :
hint_shift_x = 5 ;
hint_shift_y = 12 ;
this . ShowHintArrowed ( HINT_TYPE_ARROW_NESW , x + hint_shift_x , y + hint_shift_y ) ;
hint = this . GetHint ( " HintNESW " ) ;
break ;
//--- По умолчанию ничего не делаем
default : break ;
}
//--- Возвращаем результат корректировки положения подсказки относительно курсора
return ( hint ! = NULL ? hint . Move ( x + hint_shift_x , y + hint_shift_y ) : false ) ;
}
//+------------------------------------------------------------------+
//| CElementBase::Обработчик изменения размеров |
//+------------------------------------------------------------------+
void CElementBase : : OnResizeZoneEvent ( const int id , const long lparam , const double dparam , const string sparam )
{
int x = ( int ) lparam ; // Координата X курсора
int y = ( int ) dparam ; // Координата Y курсора
int shift_x = 0 ; // Смещение подсказки по X
int shift_y = 0 ; // Смещение подсказки по Y
//--- Получаем положение курсора относительно границ элемента и режим взаимодействия
ENUM_CURSOR_REGION edge = ( this . ResizeRegion ( ) = = CURSOR_REGION_NONE ? this . CheckResizeZone ( x , y ) : this . ResizeRegion ( ) ) ;
ENUM_RESIZE_ZONE_ACTION action = ( ENUM_RESIZE_ZONE_ACTION ) id ;
//--- Если курсор за границами изменения размеров или только что наведён на зону взаимодействия
if ( action = = RESIZE_ZONE_ACTION_NONE | | ( action = = RESIZE_ZONE_ACTION_HOVER & & edge = = CURSOR_REGION_NONE ) )
{
//--- отключаем режим изменения размеров и регион взаимодействия,
//--- скрываем все подсказки
this . SetResizeMode ( false ) ;
this . SetResizeRegion ( CURSOR_REGION_NONE ) ;
this . HideHintsAll ( true ) ;
}
//--- Курсор на одной из границ изменения размеров
if ( action = = RESIZE_ZONE_ACTION_HOVER )
{
//--- Отображаем подсказку со стрелкой для региона взаимодействия
if ( this . ShowCursorHint ( edge , x , y ) )
: : ChartRedraw ( this . m_chart_id ) ;
}
//--- Начало изменения размеров
if ( action = = RESIZE_ZONE_ACTION_BEGIN )
{
//--- включаем режим изменения размеров и регион взаимодействия,
//--- отображаем соответствующую подсказку курсора
this . SetResizeMode ( true ) ;
this . SetResizeRegion ( edge ) ;
this . ShowCursorHint ( edge , x , y ) ;
}
//--- Перетаскивание границы объекта для изменения размеров элемента
if ( action = = RESIZE_ZONE_ACTION_DRAG )
{
//--- Вызываем обработчик перетягивания границ объекта для изменения его размеров,
//--- отображаем соответствующую подсказку курсора
this . ResizeActionDragHandler ( x , y ) ;
this . ShowCursorHint ( edge , x , y ) ;
}
}
//+------------------------------------------------------------------+
//| CElementBase::Обработчик перетаскивания граней и углов элемента |
//+------------------------------------------------------------------+
void CElementBase : : ResizeActionDragHandler ( const int x , const int y )
{
//--- Изменение размера за правую границу
if ( this . ResizeRegion ( ) = = CURSOR_REGION_RIGHT )
this . ResizeZoneRightHandler ( x , y ) ;
//--- Изменение размера за нижнюю границу
if ( this . ResizeRegion ( ) = = CURSOR_REGION_BOTTOM )
this . ResizeZoneBottomHandler ( x , y ) ;
//--- Изменение размера за левую границу
if ( this . ResizeRegion ( ) = = CURSOR_REGION_LEFT )
this . ResizeZoneLeftHandler ( x , y ) ;
//--- Изменение размера за верхнюю границу
if ( this . ResizeRegion ( ) = = CURSOR_REGION_TOP )
this . ResizeZoneTopHandler ( x , y ) ;
//--- Изменение размера за правый нижний угол
if ( this . ResizeRegion ( ) = = CURSOR_REGION_RIGHT_BOTTOM )
this . ResizeZoneRightBottomHandler ( x , y ) ;
//--- Изменение размера за правый верхний угол
if ( this . ResizeRegion ( ) = = CURSOR_REGION_RIGHT_TOP )
this . ResizeZoneRightTopHandler ( x , y ) ;
//--- Изменение размера за левый нижний угол
if ( this . ResizeRegion ( ) = = CURSOR_REGION_LEFT_BOTTOM )
this . ResizeZoneLeftBottomHandler ( x , y ) ;
//--- Изменение размера за левый верхний угол
if ( this . ResizeRegion ( ) = = CURSOR_REGION_LEFT_TOP )
this . ResizeZoneLeftTopHandler ( x , y ) ;
}
//+------------------------------------------------------------------+
//| CElementBase::Обработчик изменения размеров за правую грань |
//+------------------------------------------------------------------+
bool CElementBase : : ResizeZoneRightHandler ( const int x , const int y )
{
//--- Рассчитываем и устанавливаем новую ширину элемента
int width = : : fmax ( x - this . X ( ) + 1 , DEF_PANEL_MIN_W ) ;
if ( ! this . ResizeW ( width ) )
return false ;
//--- Получаем указатель на подсказку
CVisualHint * hint = this . GetHint ( " HintHORZ " ) ;
if ( hint = = NULL )
return false ;
//--- Смещаем подсказку на указанные величины относительно курсора
int shift_x = 1 ;
int shift_y = 18 ;
return hint . Move ( x + shift_x , y + shift_y ) ;
}
//+------------------------------------------------------------------+
//| CElementBase::Обработчик изменения размеров за нижнюю грань |
//+------------------------------------------------------------------+
bool CElementBase : : ResizeZoneBottomHandler ( const int x , const int y )
{
//--- Рассчитываем и устанавливаем новую высоту элемента
int height = : : fmax ( y - this . Y ( ) , DEF_PANEL_MIN_H ) ;
if ( ! this . ResizeH ( height ) )
return false ;
//--- Получаем указатель на подсказку
CVisualHint * hint = this . GetHint ( " HintVERT " ) ;
if ( hint = = NULL )
return false ;
//--- Смещаем подсказку на указанные величины относительно курсора
int shift_x = 12 ;
int shift_y = 4 ;
return hint . Move ( x + shift_x , y + shift_y ) ;
}
//+------------------------------------------------------------------+
//| CElementBase::Изменение размера за левую грань |
//+------------------------------------------------------------------+
bool CElementBase : : ResizeZoneLeftHandler ( const int x , const int y )
{
//--- Рассчитываем новые координату X и ширину элемента
int new_x = : : fmin ( x , this . Right ( ) - DEF_PANEL_MIN_W + 1 ) ;
int width = this . Right ( ) - new_x + 1 ;
//--- Устанавливаем новые координату X и ширину элемента
if ( ! this . MoveXYWidthResize ( new_x , this . Y ( ) , width , this . Height ( ) ) )
return false ;
//--- Получаем указатель на подсказку
CVisualHint * hint = this . GetHint ( " HintHORZ " ) ;
if ( hint = = NULL )
return false ;
//--- Смещаем подсказку на указанные величины относительно курсора
int shift_x = 1 ;
int shift_y = 18 ;
return hint . Move ( x + shift_x , y + shift_y ) ;
}
//+------------------------------------------------------------------+
//| CElementBase::Изменение размера за верхнюю грань |
//+------------------------------------------------------------------+
bool CElementBase : : ResizeZoneTopHandler ( const int x , const int y )
{
//--- Рассчитываем новые координату Y и высоту элемента
int new_y = : : fmin ( y , this . Bottom ( ) - DEF_PANEL_MIN_H + 1 ) ;
int height = this . Bottom ( ) - new_y + 1 ;
//--- Устанавливаем новые координату Y и высоту элемента
if ( ! this . MoveXYWidthResize ( this . X ( ) , new_y , this . Width ( ) , height ) )
return false ;
//--- Получаем указатель на подсказку
CVisualHint * hint = this . GetHint ( " HintVERT " ) ;
if ( hint = = NULL )
return false ;
//--- Смещаем подсказку на указанные величины относительно курсора
int shift_x = 12 ;
int shift_y = 4 ;
return hint . Move ( x + shift_x , y + shift_y ) ;
}
//+------------------------------------------------------------------+
//| CElementBase::Изменение размера за правый нижний угол |
//+------------------------------------------------------------------+
bool CElementBase : : ResizeZoneRightBottomHandler ( const int x , const int y )
{
//--- Рассчитываем и устанавливаем новые ширину и высоту элемента
int width = : : fmax ( x - this . X ( ) + 1 , DEF_PANEL_MIN_W ) ;
int height = : : fmax ( y - this . Y ( ) + 1 , DEF_PANEL_MIN_H ) ;
if ( ! this .Resize ( width , height ) )
return false ;
//--- Получаем указатель на подсказку
CVisualHint * hint = this . GetHint ( " HintNWSE " ) ;
if ( hint = = NULL )
return false ;
//--- Смещаем подсказку на указанные величины относительно курсора
int shift_x = 10 ;
int shift_y = 2 ;
return hint . Move ( x + shift_x , y + shift_y ) ;
}
//+------------------------------------------------------------------+
//| CElementBase::Изменение размера за правый верхний угол |
//+------------------------------------------------------------------+
bool CElementBase : : ResizeZoneRightTopHandler ( const int x , const int y )
{
//--- Рассчитываем и устанавливаем новые координату Y, ширину и высоту элемента
int new_y = : : fmin ( y , this . Bottom ( ) - DEF_PANEL_MIN_H + 1 ) ;
int width = : : fmax ( x - this . X ( ) + 1 , DEF_PANEL_MIN_W ) ;
int height = this . Bottom ( ) - new_y + 1 ;
if ( ! this . MoveXYWidthResize ( this . X ( ) , new_y , width , height ) )
return false ;
//--- Получаем указатель на подсказку
CVisualHint * hint = this . GetHint ( " HintNESW " ) ;
if ( hint = = NULL )
return false ;
//--- Смещаем подсказку на указанные величины относительно курсора
int shift_x = 5 ;
int shift_y = 12 ;
return hint . Move ( x + shift_x , y + shift_y ) ;
}
//+------------------------------------------------------------------+
//| CElementBase::Изменение размера за левый нижний угол |
//+------------------------------------------------------------------+
bool CElementBase : : ResizeZoneLeftBottomHandler ( const int x , const int y )
{
//--- Рассчитываем и устанавливаем новые координату X, ширину и высоту элемента
int new_x = : : fmin ( x , this . Right ( ) - DEF_PANEL_MIN_W + 1 ) ;
int width = this . Right ( ) - new_x + 1 ;
int height = : : fmax ( y - this . Y ( ) + 1 , DEF_PANEL_MIN_H ) ;
if ( ! this . MoveXYWidthResize ( new_x , this . Y ( ) , width , height ) )
return false ;
//--- Получаем указатель на подсказку
CVisualHint * hint = this . GetHint ( " HintNESW " ) ;
if ( hint = = NULL )
return false ;
//--- Смещаем подсказку на указанные величины относительно курсора
int shift_x = 5 ;
int shift_y = 12 ;
return hint . Move ( x + shift_x , y + shift_y ) ;
}
//+------------------------------------------------------------------+
//| CElementBase::Изменение размера за левый верхний угол |
//+------------------------------------------------------------------+
bool CElementBase : : ResizeZoneLeftTopHandler ( const int x , const int y )
{
//--- Рассчитываем и устанавливаем новые координаты X и Y, ширину и высоту элемента
int new_x = : : fmin ( x , this . Right ( ) - DEF_PANEL_MIN_W + 1 ) ;
int new_y = : : fmin ( y , this . Bottom ( ) - DEF_PANEL_MIN_H + 1 ) ;
int width = this . Right ( ) - new_x + 1 ;
int height = this . Bottom ( ) - new_y + 1 ;
if ( ! this . MoveXYWidthResize ( new_x , new_y , width , height ) )
return false ;
//--- Получаем указатель на подсказку
CVisualHint * hint = this . GetHint ( " HintNWSE " ) ;
if ( hint = = NULL )
return false ;
//--- Смещаем подсказку на указанные величины относительно курсора
int shift_x = 10 ;
int shift_y = 2 ;
return hint . Move ( x + shift_x , y + shift_y ) ;
}
//+------------------------------------------------------------------+
//| CElementBase::Сохранение в файл |
//+------------------------------------------------------------------+
bool CElementBase : : Save ( const int file_handle )
{
//--- Сохраняем данные родительского объекта
if ( ! CCanvasBase : : Save ( file_handle ) )
return false ;
//--- Сохраняем список подсказок
if ( ! this . m_list_hints . Save ( file_handle ) )
return false ;
//--- Сохраняем объект изображения
if ( ! this . m_painter . Save ( file_handle ) )
return false ;
//--- Сохраняем группу
if ( : : FileWriteInteger ( file_handle , this . m_group , INT_VALUE ) ! = INT_VALUE )
return false ;
//--- Сохраняем флаг видимости в контейнере
if ( : : FileWriteInteger ( file_handle , this . m_visible_in_container , INT_VALUE ) ! = INT_VALUE )
return false ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//| CElementBase::Загрузка из файла |
//+------------------------------------------------------------------+
bool CElementBase : : Load ( const int file_handle )
{
//--- Загружаем данные родительского объекта
if ( ! CCanvasBase : : Load ( file_handle ) )
return false ;
//--- Загружаем список подсказок
if ( ! this . m_list_hints . Load ( file_handle ) )
return false ;
//--- Загружаем объект изображения
if ( ! this . m_painter . Load ( file_handle ) )
return false ;
//--- Загружаем группу
this . m_group = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Загружаем флаг видимости в контейнере
this . m_visible_in_container = : : FileReadInteger ( file_handle , INT_VALUE ) ;
//--- Всё успешно
return true ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс текстовой метки |
//+------------------------------------------------------------------+
class CLabel : public CElementBase
{
protected :
ushort m_text [ ] ; // Текст
ushort m_text_prev [ ] ; // Прошлый текст
int m_text_x ; // Координата X текста (смещение относительно левой границы объекта)
int m_text_y ; // Координата Y текста (смещение относительно верхней границы объекта)
//--- (1) Устанавливает, (2) возвращает прошлый текст
void SetTextPrev ( const string text ) { : : StringToShortArray ( text , this . m_text_prev ) ; }
string TextPrev ( void ) const { return : : ShortArrayToString ( this . m_text_prev ) ; }
//--- Стирает текст
void ClearText ( void ) ;
public :
//--- (1) Устанавливает, (2) возвращает текст
void SetText ( const string text ) { : : StringToShortArray ( text , this . m_text ) ; }
string Text ( void ) const { return : : ShortArrayToString ( this . m_text ) ; }
//--- Возвращает координату (1) X, (2) Y текста
int TextX ( void ) const { return this . m_text_x ; }
int TextY ( void ) const { return this . m_text_y ; }
//--- Устанавливает координату (1) X, (2) Y текста
void SetTextShiftH ( const int x ) { this . ClearText ( ) ; this . m_text_x = x ; }
void SetTextShiftV ( const int y ) { this . ClearText ( ) ; this . m_text_y = y ; }
//--- Выводит текст
void DrawText ( const int dx , const int dy , const string text , const bool chart_redraw ) ;
//--- Рисует внешний вид
virtual void Draw ( const bool chart_redraw ) ;
//--- Виртуальные методы (1) сравнения, (2) сохранения в файл, (3) загрузки из файла, (4) тип объекта
virtual int Compare ( const CObject * node , const int mode = 0 ) const ;
virtual bool Save ( const int file_handle ) ;
virtual bool Load ( const int file_handle ) ;
virtual int Type ( void ) const { return ( ELEMENT_TYPE_LABEL ) ; }
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
virtual void InitColors ( void ) { }
//--- Конструкторы/деструктор
CLabel ( void ) ;
CLabel ( const string object_name , const string text , const long chart_id , const int wnd , const int x , const int y , const int w , const int h ) ;
~ CLabel ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CLabel::Конструктор по умолчанию. Строит метку в главном окне |
//| текущего графика в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
CLabel : : CLabel ( void ) : CElementBase ( " Label " , " Label " , : : ChartID ( ) , 0 , 0 , 0 , DEF_LABEL_W , DEF_LABEL_H ) , m_text_x ( 0 ) , m_text_y ( 0 )
{
//--- Инициализация
this .Init ( " Label " ) ;
}
//+-------------------------------------------------------------------+
//| CLabel::Конструктор параметрический. Строит метку в указанном окне|
//| указанного графика с указанными текстом, координами и размерами |
//+-------------------------------------------------------------------+
CLabel : : CLabel ( const string object_name , const string text , const long chart_id , const int wnd , const int x , const int y , const int w , const int h ) :
CElementBase ( object_name , text , chart_id , wnd , x , y , w , h ) , m_text_x ( 0 ) , m_text_y ( 0 )
{
//--- Инициализация
this .Init ( text ) ;
}
//+------------------------------------------------------------------+
//| CLabel::Инициализация |
//+------------------------------------------------------------------+
void CLabel ::Init ( const string text )
{
//--- Устанавливаем текущий и предыдущий текст
this . SetText ( text ) ;
this . SetTextPrev ( " " ) ;
//--- Фон - прозрачный, передний план - нет
this . SetAlphaBG ( 0 ) ;
this . SetAlphaFG ( 255 ) ;
}
//+------------------------------------------------------------------+
//| CLabel::Сравнение двух объектов |
//+------------------------------------------------------------------+
int CLabel : : Compare ( const CObject * node , const int mode = 0 ) const
{
if ( node = = NULL )
return -1 ;
const CLabel * obj = node ;
switch ( mode )
{
case ELEMENT_SORT_BY_NAME : return ( this . Name ( ) > obj . Name ( ) ? 1 : this . Name ( ) < obj . Name ( ) ? -1 : 0 ) ;
case ELEMENT_SORT_BY_TEXT : return ( this . Text ( ) > obj . Text ( ) ? 1 : this . Text ( ) < obj . Text ( ) ? -1 : 0 ) ;
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-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-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-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-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-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-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) вертикальную стрелку,
//--- стрелки (4) сверху-лево --- низ-право, (5) снизу-лево --- верх-право
void DrawTooltip ( void ) ;
void DrawArrHorz ( void ) ;
void DrawArrVert ( void ) ;
void DrawArrNWSE ( void ) ;
void DrawArrNESW ( void ) ;
//--- Инициализация цветов для типа подсказки (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-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 )
{
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 ;
default : break ;
}
//--- Устанавливаем смещение и размеры области изображенеия,
//--- инициализируем цвета по типу подсказки
this . SetImageBound ( 0 , 0 , this . Width ( ) , this . Height ( ) ) ;
this . InitColors ( ) ;
}
//+------------------------------------------------------------------+
//| CVisualHint::Рисует внешний вид |
//+------------------------------------------------------------------+
void CVisualHint : : Draw ( const bool chart_redraw )
{
//--- В зависимости от типа подсказки вызываем соответствующий метод рисования
switch ( this . m_hint_type )
{
case HINT_TYPE_ARROW_HORZ : this . DrawArrHorz ( ) ; break ;
case HINT_TYPE_ARROW_VERT : this . DrawArrVert ( ) ; break ;
case HINT_TYPE_ARROW_NESW : this . DrawArrNESW ( ) ; break ;
case HINT_TYPE_ARROW_NWSE : this . DrawArrNWSE ( ) ; break ;
default : this . DrawTooltip ( ) ; break ;
}
//--- Если указано - обновляем график
if ( chart_redraw )
: : ChartRedraw ( this . m_chart_id ) ;
}
//+------------------------------------------------------------------+
//| CVisualHint::Рисует тултип |
//+------------------------------------------------------------------+
void CVisualHint : : DrawTooltip ( void )
{
//--- Заливаем объект цветом фона, рисуем рамку и обновляем канвас фона
this .Fill ( this . BackColor ( ) , false ) ;
this . m_background . Rectangle ( this . AdjX ( 0 ) , this . AdjY ( 0 ) , this . AdjX ( this . Width ( ) -1 ) , this . AdjY ( this . Height ( ) -1 ) , : : ColorToARGB ( this . BorderColor ( ) , this . AlphaBG ( ) ) ) ;
this . m_background . Update ( false ) ;
}
//+------------------------------------------------------------------+
//| CVisualHint::Рисует горизонтальную стрелку |
//+------------------------------------------------------------------+
void CVisualHint : : DrawArrHorz ( void )
{
//--- Очищаем область рисунка
this . m_painter . Clear ( this . AdjX ( this . m_painter . X ( ) ) , this . AdjY ( this . m_painter . Y ( ) ) , this . m_painter . Width ( ) , this . m_painter . Height ( ) , false ) ;
//--- Рисуем двойную горизонтальную стрелку
this . m_painter . ArrowHorz ( this . AdjX ( this . m_painter . X ( ) ) , this . AdjY ( this . m_painter . Y ( ) ) , this . m_painter . Width ( ) , this . m_painter . Height ( ) , this . ForeColor ( ) , this . AlphaFG ( ) , true ) ;
}
//+------------------------------------------------------------------+
//| CVisualHint::Рисует вертикальную стрелку |
//+------------------------------------------------------------------+
void CVisualHint : : DrawArrVert ( void )
{
//--- Очищаем область рисунка
this . m_painter . Clear ( this . AdjX ( this . m_painter . X ( ) ) , this . AdjY ( this . m_painter . Y ( ) ) , this . m_painter . Width ( ) , this . m_painter . Height ( ) , false ) ;
//--- Рисуем двойную вертикальную стрелку
this . m_painter . ArrowVert ( this . AdjX ( this . m_painter . X ( ) ) , this . AdjY ( this . m_painter . Y ( ) ) , this . m_painter . Width ( ) , this . m_painter . Height ( ) , this . ForeColor ( ) , this . AlphaFG ( ) , true ) ;
}
//+------------------------------------------------------------------+
//| CVisualHint::Рисует стрелки сверху-лево --- низ-право |
//+------------------------------------------------------------------+
void CVisualHint : : DrawArrNWSE ( void )
{
//--- Очищаем область рисунка
this . m_painter . Clear ( this . AdjX ( this . m_painter . X ( ) ) , this . AdjY ( this . m_painter . Y ( ) ) , this . m_painter . Width ( ) , this . m_painter . Height ( ) , false ) ;
//--- Рисуем двойную диагональную стрелку сверху-лево --- вниз-право
this . m_painter . ArrowNWSE ( this . AdjX ( this . m_painter . X ( ) ) , this . AdjY ( this . m_painter . Y ( ) ) , this . m_painter . Width ( ) , this . m_painter . Height ( ) , this . ForeColor ( ) , this . AlphaFG ( ) , true ) ;
}
//+------------------------------------------------------------------+
//| CVisualHint::Рисует стрелки снизу-лево --- верх-право |
//+------------------------------------------------------------------+
void CVisualHint : : DrawArrNESW ( void )
{
//--- Очищаем область рисунка
this . m_painter . Clear ( this . AdjX ( this . m_painter . X ( ) ) , this . AdjY ( this . m_painter . Y ( ) ) , this . m_painter . Width ( ) , this . m_painter . Height ( ) , false ) ;
//--- Рисуем двойную диагональную стрелку снизу-лево --- верх-право
this . m_painter . ArrowNESW ( this . AdjX ( this . m_painter . X ( ) ) , this . AdjY ( this . m_painter . Y ( ) ) , this . m_painter . Width ( ) , this . m_painter . Height ( ) , this . ForeColor ( ) , this . AlphaFG ( ) , true ) ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс элемента управления 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-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-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 :
CListObj m_list_elm ; // Список прикреплённых элементов
CListObj m_list_bounds ; // Список областей
//--- Добавляет новый элемент в список
bool AddNewElement ( CElementBase * element ) ;
public :
//--- Возвращает указатель на список (1) прикреплённых элементов, (2) областей
CListObj * GetListAttachedElements ( void ) { return & this . m_list_elm ; }
CListObj * 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 ) ;
//--- Возвращает область по (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 ) ;
//--- Создаёт и добавляет в список новую область
CBound * InsertNewBound ( const string name , const int dx , const int dy , const int w , const int h ) ;
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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
//| с указанными текстом, координами и размерами |
//+------------------------------------------------------------------+
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 ) ;
}
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 ) ;
}
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 ) ;
}
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 ) ) ;
this . m_painter . FrameGroupElements ( this . AdjX ( this . m_painter . X ( ) ) , this . AdjY ( this . m_painter . Y ( ) ) ,
this . m_painter . Width ( ) , this . m_painter . Height ( ) , this . Text ( ) ,
this . ForeColor ( ) , clr_dark , clr_light , this . AlphaFG ( ) , true ) ;
//--- Обновляем канвас фона без перерисовки графика
this . m_background . Update ( false ) ;
//--- Рисуем элементы списка
for ( int i = 0 ; i < this . m_list_elm . Total ( ) ; i + + )
{
CElementBase * elm = this . GetAttachedElementAt ( i ) ;
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 ;
}
//--- Устанавливаем списку флаг сортировки по идентификатору
this . m_list_elm .Sort ( ELEMENT_SORT_BY_ID ) ;
//--- Если такого элемента нет в списке - возвращаем результат его добавления в список
if ( this . m_list_elm . Search ( element ) = = NULL )
return ( this . m_list_elm . Add ( element ) > -1 ) ;
//--- Элемент с таким идентификатором уже есть в списке - возвращаем false
return false ;
}
//+------------------------------------------------------------------+
//| CPanel::Создаёт и добавляет новый элемент в список |
//+------------------------------------------------------------------+
CElementBase * CPanel : : InsertNewElement ( const ENUM_ELEMENT_TYPE type , const string text , const string user_name , const int dx , const int dy , const int w , const int h )
{
//--- Создаём имя графического объекта
int elm_total = this . m_list_elm . Total ( ) ;
string obj_name = this . NameFG ( ) + " _ " + ElementShortName ( type ) + ( string ) elm_total ;
//--- Рассчитываем координаты
int x = this . X ( ) + dx ;
int y = this . Y ( ) + dy ;
//--- В зависимости от типа объекта, создаём новый объект
CElementBase * element = NULL ;
switch ( type )
{
case ELEMENT_TYPE_LABEL : element = new CLabel ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Текстовая метка
case ELEMENT_TYPE_BUTTON : element = new CButton ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Простая кнопка
case ELEMENT_TYPE_BUTTON_TRIGGERED : element = new CButtonTriggered ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Двухпозиционная кнопка
case ELEMENT_TYPE_BUTTON_ARROW_UP : element = new CButtonArrowUp ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Кнопка со стрелкой вверх
case ELEMENT_TYPE_BUTTON_ARROW_DOWN : element = new CButtonArrowDown ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Кнопка со стрелкой вниз
case ELEMENT_TYPE_BUTTON_ARROW_LEFT : element = new CButtonArrowLeft ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Кнопка со стрелкой влево
case ELEMENT_TYPE_BUTTON_ARROW_RIGHT : element = new CButtonArrowRight ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Кнопка со стрелкой вправо
case ELEMENT_TYPE_CHECKBOX : element = new CCheckBox ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Элемент управления CheckBox
case ELEMENT_TYPE_RADIOBUTTON : element = new CRadioButton ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Элемент управления RadioButton
case ELEMENT_TYPE_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_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_CONTAINER : element = new CContainer ( obj_name , text , this . m_chart_id , this . m_wnd , x , y , w , h ) ; break ; // Элемент управления Container
default : element = NULL ;
}
//--- Если новый элемент не создан - сообщаем об этом и возвращаем NULL
if ( element = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to create graphic element %s " , __FUNCTION__ , ElementDescription ( type ) ) ;
return NULL ;
}
//--- Устанавливаем идентификатор, имя, контейнер и z-order элемента
element . SetID ( elm_total ) ;
element . SetName ( user_name ) ;
element . SetContainerObj ( & this ) ;
element . ObjectSetZOrder ( this . ObjectZOrder ( ) + 1 ) ;
//--- Если созданный элемент не добавлен в список - сообщаем об этом, удаляем созданный элемент и возвращаем NULL
if ( ! this . AddNewElement ( element ) )
{
: : PrintFormat ( " %s: Error. Failed to add %s element with ID %d to list " , __FUNCTION__ , ElementDescription ( type ) , element . ID ( ) ) ;
delete element ;
return NULL ;
}
//--- Получаем родительский элемент, к которому привязаны дочерние
CElementBase * elm = this . GetContainer ( ) ;
//--- Если родительский элемент имеет тип "Контейнер", значит, у него есть полосы прокрутки
if ( elm ! = NULL & & elm . Type ( ) = = ELEMENT_TYPE_CONTAINER )
{
//--- Преобразуем CElementBase в CContainer
CContainer * container_obj = elm ;
//--- Если горизонтальная полоса прокрутки видима,
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 ) ;
if ( this . m_list_bounds . Search ( & this . m_temp_bound ) ! = NULL )
{
: : PrintFormat ( " %s: Error. An area named \" %s \" is already in the list " , __FUNCTION__ , name ) ;
return NULL ;
}
//--- Создаём новый объект-область; при неудаче - сообщаем об этом и возвращаем NULL
CBound * bound = new CBound ( dx , dy , w , h ) ;
if ( bound = = NULL )
{
: : PrintFormat ( " %s: Error. Failed to create CBound object " , __FUNCTION__ ) ;
return NULL ;
}
//--- Если новый объект не удалось добавить в список - сообщаем об этом, удаляем объект и возвращаем NULL
if ( this . m_list_bounds . Add ( bound ) = = -1 )
{
: : PrintFormat ( " %s: Error. Failed to add CBound object to list " , __FUNCTION__ ) ;
delete bound ;
return NULL ;
}
//--- Устанавливаем имя области и идентификатор, и возвращаем указатель на объект
bound . SetName ( name ) ;
bound . SetID ( this . m_list_bounds . Total ( ) ) ;
return bound ;
}
//+------------------------------------------------------------------+
//| Выводит в журнал описание объекта |
//+------------------------------------------------------------------+
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-28 12:12:49 +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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
//| с указанными текстом, координами и размерами |
//+------------------------------------------------------------------+
CGroupBox : : CGroupBox ( const string object_name , const string text , const long chart_id , const int wnd , const int x , const int y , const int w , const int h ) :
CPanel ( object_name , text , chart_id , wnd , x , y , w , h )
{
//--- Инициализация
this .Init ( ) ;
}
//+------------------------------------------------------------------+
//| CGroupBox::Инициализация |
//+------------------------------------------------------------------+
void CGroupBox ::Init ( void )
{
//--- Инициализация при помощи родительского класса
CPanel ::Init ( ) ;
}
//+------------------------------------------------------------------+
//| CGroupBox::Устанавливает группу элементов |
//+------------------------------------------------------------------+
void CGroupBox : : SetGroup ( const int group )
{
//--- Устанавливаем группу этому элементу методом родительского класса
CElementBase : : SetGroup ( group ) ;
//--- В цикле по списку привязанных элементов
for ( int i = 0 ; i < this . m_list_elm . Total ( ) ; i + + )
{
//--- получаем очередной элемент и назначаем ему группу
CElementBase * elm = this . GetAttachedElementAt ( i ) ;
if ( elm ! = NULL )
elm . SetGroup ( group ) ;
}
}
//+------------------------------------------------------------------+
//| CGroupBox::Создаёт и добавляет новый элемент в список |
//+------------------------------------------------------------------+
CElementBase * CGroupBox : : InsertNewElement ( const ENUM_ELEMENT_TYPE type , const string text , const string user_name , const int dx , const int dy , const int w , const int h )
{
//--- Создаём и добавляем в список элементов новый элемент
CElementBase * element = CPanel : : InsertNewElement ( type , text , user_name , dx , dy , w , h ) ;
if ( element = = NULL )
return NULL ;
//--- Устанавливаем созданному элементу группу, равную группе этого объекта
element . SetGroup ( this . Group ( ) ) ;
return element ;
}
//+------------------------------------------------------------------+
//| CGroupBox::Добавляет указанный элемент в список |
//+------------------------------------------------------------------+
CElementBase * CGroupBox : : InsertElement ( CElementBase * element , const int dx , const int dy )
{
//--- Добавляем в список элементов новый элемент
if ( CPanel : : InsertElement ( element , dx , dy ) = = NULL )
return NULL ;
//--- Устанавливаем добавленному элементу группу, равную группе этого объекта
element . SetGroup ( this . Group ( ) ) ;
return element ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Класс ползунка горизонтальной полосы прокрутки |
//+------------------------------------------------------------------+
class CScrollBarThumbH : public CButton
{
protected :
bool m_chart_redraw ; // Флаг обновления графика
public :
//--- (1) Устанавливает, (2) возвращает флаг обновления графика
void SetChartRedrawFlag ( const bool flag ) { this . m_chart_redraw = flag ; }
bool ChartRedrawFlag ( void ) const { return this . m_chart_redraw ; }
//--- Виртуальные методы (1) сохранения в файл, (2) загрузки из файла, (3) тип объекта
virtual bool Save ( const int file_handle ) ;
virtual bool Load ( const int file_handle ) ;
virtual int Type ( void ) const { return ( ELEMENT_TYPE_SCROLLBAR_THUMB_H ) ; }
//--- Инициализация (1) объекта класса, (2) цветов объекта по умолчанию
void Init ( const string text ) ;
//--- Обработчики событий (1) перемещения курсора, (2) прокрутки колёсика
virtual void OnMoveEvent ( const int id , const long lparam , const double dparam , const string sparam ) ;
virtual void OnWheelEvent ( const int id , const long lparam , const double dparam , const string sparam ) ;
//--- Конструкторы/деструктор
CScrollBarThumbH ( void ) ;
CScrollBarThumbH ( const string object_name , const string text , const long chart_id , const int wnd , const int x , const int y , const int w , const int h ) ;
~ CScrollBarThumbH ( void ) { }
} ;
//+------------------------------------------------------------------+
//| CScrollBarThumbH::Конструктор по умолчанию. |
//| Строит элемент в главном окне текущего графика |
//| в координатах 0,0 с размерами по умолчанию |
//+------------------------------------------------------------------+
CScrollBarThumbH : : CScrollBarThumbH ( void ) : CButton ( " SBThumb " , " " , : : ChartID ( ) , 0 , 0 , 0 , DEF_PANEL_W , DEF_SCROLLBAR_TH )
{
//--- Инициализация
this .Init ( " " ) ;
}
//+------------------------------------------------------------------+
//| CScrollBarThumbH::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
//| с указанными текстом, координами и размерами |
//+------------------------------------------------------------------+
CScrollBarThumbH : : CScrollBarThumbH ( const string object_name , const string text , const long chart_id , const int wnd , const int x , const int y , const int w , const int h ) :
CButton ( object_name , text , chart_id , wnd , x , y , w , h )
{
//--- Инициализация
this .Init ( " " ) ;
}
//+------------------------------------------------------------------+
//| CScrollBarThumbH::Инициализация |
//+------------------------------------------------------------------+
void CScrollBarThumbH ::Init ( const string text )
{
//--- Инициализация родительского класса
CButton ::Init ( " " ) ;
//--- Устанавливаем флаги перемещаемости и обновления графика
this . SetMovable ( true ) ;
this . SetChartRedrawFlag ( false ) ;
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 ( ) ;
//--- Если для ползунка не установлен флаг перемещаемости, либо указатель на базовый объект не получен - уходим
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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
//| с указанными текстом, координами и размерами |
//+------------------------------------------------------------------+
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 ( ) ;
//--- Если для ползунка не установлен флаг перемещаемости, либо указатель на базовый объект не получен - уходим
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-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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
//| с указанными текстом, координами и размерами |
//+------------------------------------------------------------------+
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 ( " " ) ;
//--- Элемент не обрезается по границам контейнера
this . m_trim_flag = false ;
//--- Создаём кнопки прокрутки
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 ( ) ;
2026-03-28 12:36:14 +07:00
this . m_butt_left . SetTrimmered ( false ) ;
this . m_butt_left . SetVisibleInContainer ( false ) ;
2026-03-28 12:12:49 +07:00
//--- Настраиваем цвета и вид кнопки со стрелкой вправо
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 ( ) ;
2026-03-28 12:36:14 +07:00
this . m_butt_right . SetTrimmered ( false ) ;
this . m_butt_right . SetVisibleInContainer ( false ) ;
2026-03-28 12:12:49 +07:00
//--- Создаём ползунок
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
this . m_thumb . SetTrimmered ( false ) ;
this . m_thumb . SetVisibleInContainer ( false ) ;
//--- Запрещаем самостоятельную перерисовку графика
2026-03-28 12:12:49 +07:00
this . m_thumb . SetChartRedrawFlag ( false ) ;
2026-03-28 12:36:14 +07:00
//--- Изначально в контейнере не отображается
this . m_visible_in_container = 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-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
{
return ( this . m_thumb ! = NULL ? this . m_thumb . X ( ) - this . TrackBegin ( ) - this . X ( ) : 0 ) ;
}
//+------------------------------------------------------------------+
//| 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-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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
//| с указанными текстом, координами и размерами |
//+------------------------------------------------------------------+
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 ( " " ) ;
//--- Элемент не обрезается по границам контейнера
this . m_trim_flag = false ;
//--- Создаём кнопки прокрутки
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 ( ) ;
2026-03-28 12:36:14 +07:00
this . m_butt_up . SetTrimmered ( false ) ;
this . m_butt_up . SetVisibleInContainer ( false ) ;
2026-03-28 12:12:49 +07:00
//--- Настраиваем цвета и вид кнопки со стрелкой вниз
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 ( ) ) ;
2026-03-28 12:36:14 +07:00
this . m_butt_down . SetTrimmered ( false ) ;
this . m_butt_down . SetVisibleInContainer ( false ) ;
2026-03-28 12:12:49 +07:00
//--- Создаём ползунок
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 ) ;
2026-03-28 12:36:14 +07:00
this . m_thumb . SetTrimmered ( false ) ;
this . m_thumb . SetVisibleInContainer ( false ) ;
2026-03-28 12:12:49 +07:00
//--- запрещаем самостоятельную перерисовку графика
this . m_thumb . SetChartRedrawFlag ( false ) ;
2026-03-28 12:36:14 +07:00
//--- Изначально в контейнере не отображается
this . m_visible_in_container = 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-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
{
return ( this . m_thumb ! = NULL ? this . m_thumb . Y ( ) - this . TrackBegin ( ) - this . Y ( ) : 0 ) ;
}
//+------------------------------------------------------------------+
//| 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
//--- Проверяет размеры элемента для отображения полос прокрутки
void CheckElementSizes ( CElementBase * element ) ;
//--- Рассчитывает и возвращает размер (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 ) ; }
//--- Устанавливает флаг прокрутки содержимого
void SetScrolling ( const bool flag ) { this . m_scroll_flag = flag ; }
//--- Возвращает флаг видимости (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::Конструктор параметрический. |
//| Строит элемент в указанном окне указанного графика |
//| с указанными текстом, координами и размерами |
//+------------------------------------------------------------------+
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 независимо от указанных в параметрах
CElementBase * elm = CPanel : : InsertNewElement ( type , text , user_name , 0 , 0 , w , h ) ;
//--- Проверяем размеры элемента для отображения полос прокрутки
this . CheckElementSizes ( elm ) ;
//--- Возвращаем указатель на элемент
return elm ;
}
//+------------------------------------------------------------------+
//| CContainer::Добавляет указанный элемент в список |
//+------------------------------------------------------------------+
CElementBase * CContainer : : InsertElement ( CElementBase * element , const int dx , const int dy )
{
//--- Проверяем, чтобы в списке было не более трёх объектов - две полосы прокрутки и добавляемый
if ( this . m_list_elm . Total ( ) > 2 )
{
: : PrintFormat ( " %s: Error. You can only add one element to a container \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-28 12:36:14 +07:00
int content_offset = this . CalculateContentOffsetHorz ( value ) ;
2026-03-28 12:12:49 +07:00
//--- Возвращаем результат сдвига содержимого на рассчитанную величину
return ( elm . MoveX ( this . X ( ) - content_offset ) ) ;
}
//+------------------------------------------------------------------+
//| 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-28 12:36:14 +07:00
int content_offset = this . CalculateContentOffsetVert ( value ) ;
2026-03-28 12:12:49 +07:00
//--- Возвращаем результат сдвига содержимого на рассчитанную величину
return ( elm . MoveY ( this . Y ( ) - content_offset ) ) ;
}
//+------------------------------------------------------------------+
//| Возвращает тип элемента, отправившего событие |
//+------------------------------------------------------------------+
ENUM_ELEMENT_TYPE CContainer : : GetEventElementType ( const string name )
{
//--- Получаем имена всех элементов в иерархии (при ошибке - возвращаем -1)
string names [ ] = { } ;
int total = GetElementNames ( name , " _ " , names ) ;
if ( total = = WRONG_VALUE )
return WRONG_VALUE ;
//--- Если имя базового элемента в иерархии не совпадает с именем контейнера, то это не наше событие - уходим
string base_name = names [ 0 ] ;
if ( base_name ! = this . NameFG ( ) )
return WRONG_VALUE ;
//--- События, пришедшие не от скроллбаров, пропускаем
string check_name = : : StringSubstr ( names [ 1 ] , 0 , 4 ) ;
if ( check_name ! = " SCBH " & & check_name ! = " SCBV " )
return WRONG_VALUE ;
//--- Получаем имя элемента, от которого пришло событие и инициализируем тип элемента
string elm_name = names [ names .Size ( ) -1 ] ;
ENUM_ELEMENT_TYPE type = WRONG_VALUE ;
//--- Проверяем и записываем тип элемента
//--- Кнопка со стрелкой вверх
if ( : : StringFind ( elm_name , " BTARU " ) = = 0 )
type = ELEMENT_TYPE_BUTTON_ARROW_UP ;
//--- Кнопка со стрелкой вниз
else if ( : : StringFind ( elm_name , " BTARD " ) = = 0 )
type = ELEMENT_TYPE_BUTTON_ARROW_DOWN ;
//--- Кнопка со стрелкой влево
else if ( : : StringFind ( elm_name , " BTARL " ) = = 0 )
type = ELEMENT_TYPE_BUTTON_ARROW_LEFT ;
//--- Кнопка со стрелкой вправо
else if ( : : StringFind ( elm_name , " BTARR " ) = = 0 )
type = ELEMENT_TYPE_BUTTON_ARROW_RIGHT ;
//--- Ползунок горизонтальной полосы прокрутки
else if ( : : StringFind ( elm_name , " THMBH " ) = = 0 )
type = ELEMENT_TYPE_SCROLLBAR_THUMB_H ;
//--- Ползунок вертикальной полосы прокрутки
else if ( : : StringFind ( elm_name , " THMBV " ) = = 0 )
type = ELEMENT_TYPE_SCROLLBAR_THUMB_V ;
//--- Элемент управления ScrollBarHorisontal
else if ( : : StringFind ( elm_name , " SCBH " ) = = 0 )
type = ELEMENT_TYPE_SCROLLBAR_H ;
//--- Элемент управления ScrollBarVertical
else if ( : : StringFind ( elm_name , " SCBV " ) = = 0 )
type = ELEMENT_TYPE_SCROLLBAR_V ;
//--- Возвращаем тип элемента
return type ;
}
//+------------------------------------------------------------------+
//| CContainer::Обработчик пользовательского события элемента |
//| при перемещении курсора в области объекта |
//+------------------------------------------------------------------+
void CContainer : : MouseMoveHandler ( const int id , const long lparam , const double dparam , const string sparam )
{
bool res = false ;
//--- Получаем указатель на содержимое контейнера
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
//+------------------------------------------------------------------+