EasyAndFastMod/Controls/ButtonsGroup.mqh
2026-01-15 07:23:17 -05:00

382 lignes
33 Kio
MQL5

//+------------------------------------------------------------------+
//| ButtonsGroup.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "..\Element.mqh"
#include "Button.mqh"
//+------------------------------------------------------------------+
//| Класс для создания группы кнопок |
//+------------------------------------------------------------------+
class CButtonsGroup : public CElement
{
private:
//--- Экземпляры для создания элемента
CButton m_buttons[];
//--- Режим радио-кнопок
bool m_radio_buttons_mode;
//--- Стиль отображения радио-кнопок
bool m_radio_buttons_style;
//--- Высота кнопок
int m_button_y_size;
//--- (1) Текст и (2) индекс выделенной кнопки
string m_selected_button_text;
int m_selected_button_index;
//---
public:
CButtonsGroup(void);
~CButtonsGroup(void);
//--- Методы для создания кнопки
bool CreateButtonsGroup(const int x_gap,const int y_gap);
//---
private:
void InitializeProperties(const int x_gap,const int y_gap);
bool CreateButtons(void);
//---
public:
//--- Возвращает указатель на кнопку по указанному индексу
CButton *GetButtonPointer(const uint index);
//--- (1) Количество кнопок, (2) высота кнопок
int ButtonsTotal(void) const { return(::ArraySize(m_buttons)); }
void ButtonYSize(const int y_size) { m_button_y_size=y_size; }
//--- (1) Установка режима и (2) стиля отображения радио-кнопок
void RadioButtonsMode(const bool flag) { m_radio_buttons_mode=flag; }
void RadioButtonsStyle(const bool flag) { m_radio_buttons_style=flag; }
//--- Возвращает (1) текст и (2) индекс выделенной кнопки
string SelectedButtonText(void) const { return(m_selected_button_text); }
int SelectedButtonIndex(void) const { return(m_selected_button_index); }
//--- Добавляет кнопку с указанными свойствами до создания
void AddButton(const int x_gap,const int y_gap,const string text,const int width,
const color button_color=clrNONE,const color button_color_hover=clrNONE,const color button_color_pressed=clrNONE);
//--- Переключает кнопку по указанному индексу
void SelectButton(const uint index,const bool is_external_call=true);
//---
public:
//--- Обработчик событий графика
virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- Управление объектами
virtual void Show(void);
virtual void Delete(void);
//--- Обновляет элемент для отображения последних изменений
virtual void Update(const bool redraw=false);
//--- Рисует элемент
virtual void Draw(void);
//---
private:
//--- Обработка нажатия на кнопку
bool OnClickButton(const string pressed_object,const int id,const int index);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CButtonsGroup::CButtonsGroup(void) : m_button_y_size(20),
m_radio_buttons_mode(false),
m_radio_buttons_style(false),
m_selected_button_text(""),
m_selected_button_index(WRONG_VALUE)
{
//--- Сохраним имя класса элемента в базовом классе
CElementBase::ClassName(CLASS_NAME);
//--- Метка по умолчанию
CElementBase::NamePart("button");
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CButtonsGroup::~CButtonsGroup(void)
{
}
//+------------------------------------------------------------------+
//| Обработчик события графика |
//+------------------------------------------------------------------+
void CButtonsGroup::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Обработка события нажатия левой кнопки мыши на элементе
if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
{
if(OnClickButton(sparam,(uint)lparam,(uint)dparam))
return;
//---
return;
}
}
//+------------------------------------------------------------------+
//| Создаёт группу кнопок |
//+------------------------------------------------------------------+
bool CButtonsGroup::CreateButtonsGroup(const int x_gap,const int y_gap)
{
//--- Выйти, если нет указателя на главный элемент
if(!CElement::CheckMainPointer())
return(false);
//--- Инициализация свойств
InitializeProperties(x_gap,y_gap);
//--- Создаёт кнопки
if(!CreateButtons())
return(false);
//--- Выделить радио-кнопку
if(m_radio_buttons_mode)
m_buttons[m_selected_button_index].IsPressed(true);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Инициализация свойств |
//+------------------------------------------------------------------+
void CButtonsGroup::InitializeProperties(const int x_gap,const int y_gap)
{
m_x =CElement::CalculateX(x_gap);
m_y =CElement::CalculateY(y_gap);
//--- Значения по умолчанию
m_label_x_gap =(m_label_x_gap!=WRONG_VALUE)? m_label_x_gap : 18;
m_label_y_gap =(m_label_y_gap!=WRONG_VALUE)? m_label_y_gap : 0;
//--- Одна радио-кнопка должна быть выделена обязательно
if(m_radio_buttons_mode)
m_selected_button_index=(m_selected_button_index!=WRONG_VALUE)? m_selected_button_index : 0;
//--- Отступы от крайней точки
CElementBase::XGap(x_gap);
CElementBase::YGap(y_gap);
//--- Приоритет, как у главного элемента, так как элемент не имеет своей области для нажатия
CElement::Z_Order(m_main.Z_Order());
}
//+------------------------------------------------------------------+
//| Создаёт кнопки |
//+------------------------------------------------------------------+
bool CButtonsGroup::CreateButtons(void)
{
//--- Координаты
int x=0,y=0;
//--- Получим количество кнопок
int buttons_total=ButtonsTotal();
//--- Если нет ни одной кнопки в группе, сообщить об этом
if(buttons_total<1)
{
//::Print(__FUNCTION__," > Вызов этого метода нужно осуществлять, ...\n"
// "... когда в группе есть хотя бы одна кнопка! Воспользуйтесь методом CButtonsGroup::AddButton()"
::Print(__FUNCTION__," > You must call this method when there is at least one button in the group! "
"Use the method CButtonsGroup::AddButton()");
return(false);
}
//--- Создадим указанное количество кнопок
for(int i=0; i<buttons_total; i++)
{
//--- Сохраним указатель на родительский элемент
m_buttons[i].MainPointer(this);
//--- Координаты
x =m_buttons[i].XGap();
y =m_buttons[i].YGap();
//--- Свойства
m_buttons[i].NamePart(CElementBase::NamePart());
m_buttons[i].Alpha(m_alpha);
m_buttons[i].IconXGap(m_icon_x_gap);
m_buttons[i].IconYGap(m_icon_y_gap);
m_buttons[i].LabelXGap(m_label_x_gap);
m_buttons[i].LabelYGap(m_label_y_gap);
m_buttons[i].IsCenterText(CElement::IsCenterText());
m_buttons[i].IsDropdown(CElementBase::IsDropdown());
//--- Создадим элемент управления
if(!m_buttons[i].CreateButton(m_buttons[i].LabelText(),x,y))
return(false);
//--- Нажмём кнопку, если определена
if(i==m_selected_button_index)
m_buttons[i].IsPressed(true);
//--- Добавить элемент в массив
CElement::AddToArray(m_buttons[i]);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Возвращает указатель на кнопку по указанному индексу |
//+------------------------------------------------------------------+
CButton *CButtonsGroup::GetButtonPointer(const uint index)
{
uint array_size=::ArraySize(m_buttons);
//--- Проверка размера массива объектов
if(array_size<1)
{
::Print(__FUNCTION__," > There is no button in the group!");
return(NULL);
}
//--- Корректировка в случае выхода из диапазона
uint i=(index>=array_size)? array_size-1 : index;
//--- Вернуть указатель объекта
return(::GetPointer(m_buttons[i]));
}
//+------------------------------------------------------------------+
//| Добавляет кнопку |
//+------------------------------------------------------------------+
void CButtonsGroup::AddButton(const int x_gap,const int y_gap,const string text,const int width,
const color button_color=clrNONE,const color button_color_hover=clrNONE,const color button_color_pressed=clrNONE)
{
//--- Резервный размер
int reserve_size=100;
//--- Увеличим размер массивов на один элемент
int array_size=::ArraySize(m_buttons);
int new_size=array_size+1;
::ArrayResize(m_buttons,new_size,reserve_size);
//--- Установим свойства
m_buttons[array_size].Index(array_size);
m_buttons[array_size].TwoState(true);
m_buttons[array_size].XSize(width);
m_buttons[array_size].YSize(m_button_y_size);
m_buttons[array_size].XGap(x_gap);
m_buttons[array_size].YGap(y_gap);
m_buttons[array_size].LabelText(text);
m_buttons[array_size].BackColor(button_color);
m_buttons[array_size].BackColorHover(button_color_hover);
m_buttons[array_size].BackColorPressed(button_color_pressed);
//--- Выйти, если выключен стиль радио-кнопок
if(!m_radio_buttons_style)
return;
//---
m_buttons[array_size].BackColor(m_main.BackColor());
m_buttons[array_size].BackColorHover(m_main.BackColor());
m_buttons[array_size].BackColorPressed(m_main.BackColor());
m_buttons[array_size].BackColorLocked(m_main.BackColor());
m_buttons[array_size].BorderColor(m_main.BackColor());
m_buttons[array_size].BorderColorHover(m_main.BackColor());
m_buttons[array_size].BorderColorPressed(m_main.BackColor());
m_buttons[array_size].BorderColorLocked(m_main.BackColor());
m_buttons[array_size].LabelColorHover(C'0,120,215');
m_buttons[array_size].IconXGap(m_icon_x_gap);
m_buttons[array_size].IconYGap(m_icon_y_gap);
m_buttons[array_size].IconFileLocked(RESOURCE_RADIO_BUTTON_OFF_LOCKED);
m_buttons[array_size].IconFile(RESOURCE_RADIO_BUTTON_OFF);
m_buttons[array_size].IconFileLocked(RESOURCE_RADIO_BUTTON_OFF_LOCKED);
m_buttons[array_size].CElement::IconFilePressed(RESOURCE_RADIO_BUTTON_ON);
m_buttons[array_size].CElement::IconFilePressedLocked(RESOURCE_RADIO_BUTTON_ON_LOCKED);
}
//+------------------------------------------------------------------+
//| Переключает кнопку по указанному индексу |
//+------------------------------------------------------------------+
void CButtonsGroup::SelectButton(const uint index,const bool is_external_call=true)
{
//--- Для проверки существования нажатой в группе кнопки
bool check_pressed_button=false;
//--- Получим количество кнопок
uint buttons_total=ButtonsTotal();
//--- Если нет ни одной кнопки в группе, сообщить об этом
if(buttons_total<1)
{
::Print(__FUNCTION__," > You must call this method when there is at least one button in the group! "
"Use the method CButtonsGroup::AddButton()");
return;
}
//--- Скорректировать значение индекса, если выходит из диапазона
uint correct_index=(index>=buttons_total)? buttons_total-1 : index;
//---
if(is_external_call && !m_radio_buttons_mode)
m_buttons[correct_index].IsPressed(!m_buttons[correct_index].IsPressed());
//--- Пройдёмся в цикле по группе кнопок
for(uint i=0; i<buttons_total; i++)
{
if(i==correct_index)
{
if(m_radio_buttons_mode)
m_buttons[i].IsPressed(true);
//--- Если есть нажатая кнопка
if(m_buttons[i].IsPressed())
check_pressed_button=true;
//---
continue;
}
//--- Отожмём остальные кнопки
if(m_buttons[i].IsPressed())
m_buttons[i].IsPressed(false);
}
//--- Если есть нажатая кнопка, сохраним её текст и индекс
m_selected_button_text =(check_pressed_button)? m_buttons[correct_index].LabelText() : "";
m_selected_button_index =(check_pressed_button)? (int)correct_index : WRONG_VALUE;
}
//+------------------------------------------------------------------+
//| Показать |
//+------------------------------------------------------------------+
void CButtonsGroup::Show(void)
{
CElement::Show();
int total=ButtonsTotal();
for(int i=0; i<total; i++)
m_buttons[i].Show();
}
//+------------------------------------------------------------------+
//| Удаление |
//+------------------------------------------------------------------+
void CButtonsGroup::Delete(void)
{
CElement::Delete();
//--- Освобождение массивов элемента
::ArrayFree(m_buttons);
}
//+------------------------------------------------------------------+
//| Обновление элемента |
//+------------------------------------------------------------------+
void CButtonsGroup::Update(const bool redraw=false)
{
int buttons_total=ButtonsTotal();
//--- С перерисовкой элемента
if(redraw)
{
for(int i=0; i<buttons_total; i++)
m_buttons[i].Draw();
for(int i=0; i<buttons_total; i++)
m_buttons[i].Update();
//---
return;
}
//--- Применить
for(int i=0; i<buttons_total; i++)
m_buttons[i].Update();
}
//+------------------------------------------------------------------+
//| Нажатие на кнопку в группе |
//+------------------------------------------------------------------+
bool CButtonsGroup::OnClickButton(const string pressed_object,const int id,const int index)
{
//--- Выйдем, если нажатие было не на этом элементе
if(!CElementBase::CheckElementName(pressed_object))
return(false);
//--- Выйти, если (1) идентификаторы не совпадают или (2) элемент заблокирован
if(id!=CElementBase::Id() || CElementBase::IsLocked())
return(false);
//--- Если эта кнопка уже нажата
if(index==m_selected_button_index)
{
//--- Переключить кнопку
SelectButton(m_selected_button_index,false);
return(true);
}
//---
int check_index=WRONG_VALUE;
//--- Проверим, было ли нажатие на одной из кнопок этой группы
int buttons_total=ButtonsTotal();
//--- Если нажатие было, то запомним индекс
for(int i=0; i<buttons_total; i++)
{
if(m_buttons[i].Index()==index)
{
check_index=i;
break;
}
}
//--- Выйдем, если не было нажатия на кнопку в этой группе
if(check_index==WRONG_VALUE)
return(false);
//--- Переключить кнопку
SelectButton(check_index,false);
Update(true);
//--- Отправим сообщение об этом
::EventChartCustom(m_chart_id,ON_CLICK_GROUP_BUTTON,CElementBase::Id(),m_selected_button_index,m_selected_button_text);
return(true);
}
//+------------------------------------------------------------------+
//| Рисует элемент |
//+------------------------------------------------------------------+
void CButtonsGroup::Draw(void)
{
int buttons_total=ButtonsTotal();
for(int i=0; i<buttons_total; i++)
m_buttons[i].Draw();
}
//+------------------------------------------------------------------+