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

481 líneas
39 KiB
MQL5

//+------------------------------------------------------------------+
//| ComboBox.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "..\Element.mqh"
#include "ListView.mqh"
//+------------------------------------------------------------------+
//| Класс для создания комбинированного списка |
//+------------------------------------------------------------------+
class CComboBox : public CElement
{
private:
//--- Экземпляры для создания элемента
CButton m_button;
CListView m_listview;
//--- Режим элемента с чек-боксом
bool m_checkbox_mode;
//---
public:
CComboBox(void);
~CComboBox(void);
//--- Методы для создания комбо-бокса
bool CreateComboBox(const string text,const int x_gap,const int y_gap);
//---
private:
void InitializeProperties(const string text,const int x_gap,const int y_gap);
bool CreateCanvas(void);
bool CreateButton(void);
bool CreateList(void);
//---
public:
//--- Возвращает указатели на (1) кнопку, (2) список и (3) полосу прокрутки
CButton *GetButtonPointer(void) { return(::GetPointer(m_button)); }
CListView *GetListViewPointer(void) { return(::GetPointer(m_listview)); }
CScrollV *GetScrollVPointer(void) { return(m_listview.GetScrollVPointer()); }
//--- (1) Размер списка (количество пунктов) (2) установка режима элемента с чек-боксом
void ItemsTotal(const int items_total) { m_listview.ListSize(items_total); }
void CheckBoxMode(const bool state) { m_checkbox_mode=state; }
//--- Состояние элемента (нажат/отжат)
bool IsPressed(void) const { return(m_is_pressed); }
void IsPressed(const bool state);
//--- Сохраняет переданное значение в списке по указанному индексу
void SetValue(const int item_index,const string item_text);
//--- Возвращает выбранное значение в списке
string GetValue(void);
//--- Выделение пункта по указанному индексу
void SelectItem(const int item_index);
//--- Изменяет текущее состояние комбо-бокса на противоположное
void ChangeComboBoxListState(void);
//---
public:
//--- Обработчик событий графика
virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- Блокировка
virtual void IsLocked(const bool state);
//--- Управление видимостью
virtual void Hide(void);
//--- Рисует элемент
virtual void Draw(void);
//---
private:
//--- Обработка нажатия на элементе
bool OnClickElement(const string pressed_object);
//--- Обработка нажатия на кнопку
bool OnClickButton(const string pressed_object,const int id,const int index);
//--- Обработка нажатия на пункте списка
bool OnClickListItem(const int id);
//--- Проверка нажатой левой кнопки мыши над кнопкой комбо-бокса
void CheckPressedOverButton(void);
//--- Рисует картинку
virtual void DrawImage(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CComboBox::CComboBox(void) : m_checkbox_mode(false)
{
//--- Сохраним имя класса элемента в базовом классе
CElementBase::ClassName(CLASS_NAME);
//--- Режим выпадающего списка
m_listview.IsDropdown(true);
m_listview.GetScrollVPointer().IsDropdown(true);
m_listview.GetScrollVPointer().GetIncButtonPointer().IsDropdown(true);
m_listview.GetScrollVPointer().GetDecButtonPointer().IsDropdown(true);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CComboBox::~CComboBox(void)
{
}
//+------------------------------------------------------------------+
//| Обработчик событий |
//+------------------------------------------------------------------+
void CComboBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Обработка события перемещения курсора
if(id==CHARTEVENT_MOUSE_MOVE)
{
//--- Проверка нажатой левой кнопки мыши над кнопкой
CheckPressedOverButton();
//--- Перерисовать элемент
if(CheckCrossingBorder())
Update(true);
//---
return;
}
//--- Обработка события нажатия на пункте списка
if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
{
if(!OnClickListItem((int)lparam))
return;
//---
return;
}
//--- Обработка нажатия на элементе
if(id==CHARTEVENT_OBJECT_CLICK)
{
if(OnClickElement(sparam))
return;
//---
return;
}
//--- Обработка события нажатия на кнопке
if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
{
if(OnClickButton(sparam,(uint)lparam,(uint)dparam))
return;
//---
return;
}
//--- Обработка события изменения свойств графика
if(id==CHARTEVENT_CHART_CHANGE)
{
//--- Выйти, если (1) элемент заблокирован или (2) кнопка отжата
if(CElementBase::IsLocked() || !m_button.IsPressed())
return;
//--- Отжать кнопку
m_button.IsPressed(false);
//--- Изменить состояние списка
ChangeComboBoxListState();
return;
}
}
//+------------------------------------------------------------------+
//| Создаёт группу объектов типа комбо-бокс |
//+------------------------------------------------------------------+
bool CComboBox::CreateComboBox(const string text,const int x_gap,const int y_gap)
{
//--- Выйти, если нет указателя на главный элемент
if(!CElement::CheckMainPointer())
return(false);
//--- Инициализация свойств
InitializeProperties(text,x_gap,y_gap);
//--- Создание элемента
if(!CreateCanvas())
return(false);
if(!CreateButton())
return(false);
if(!CreateList())
return(false);
//--- Установить текст в кнопку
m_button.LabelText(m_listview.SelectedItemText());
return(true);
}
//+------------------------------------------------------------------+
//| Инициализация свойств |
//+------------------------------------------------------------------+
void CComboBox::InitializeProperties(const string text,const int x_gap,const int y_gap)
{
m_x =CElement::CalculateX(x_gap);
m_y =CElement::CalculateY(y_gap);
m_x_size =(m_x_size<1)? 50 : m_x_size;
m_y_size =(m_y_size<1)? 20 : m_y_size;
m_label_text =text;
//--- Цвет фона и отступы для картинки/чек-бокса
m_back_color=(m_back_color!=clrNONE)? m_back_color : m_main.BackColor();
//--- Отступы и цвет текстовой метки
m_icon_y_gap =(m_icon_y_gap!=WRONG_VALUE)? m_icon_y_gap : 4;
m_label_x_gap =(m_label_x_gap!=WRONG_VALUE)? m_label_x_gap : (m_checkbox_mode)? 20 : 0;
m_label_y_gap =(m_label_y_gap!=WRONG_VALUE)? m_label_y_gap : 4;
m_label_color =(m_label_color!=clrNONE)? m_label_color : clrBlack;
m_label_color_hover =(m_label_color_hover!=clrNONE)? m_label_color_hover : C'0,120,215';
m_label_color_locked =(m_label_color_locked!=clrNONE)? m_label_color_locked : clrSilver;
m_label_color_pressed =(m_label_color_pressed!=clrNONE)? m_label_color_pressed : clrBlack;
//--- Отступы от крайней точки
CElementBase::XGap(x_gap);
CElementBase::YGap(y_gap);
}
//+------------------------------------------------------------------+
//| Создаёт объект для рисования |
//+------------------------------------------------------------------+
bool CComboBox::CreateCanvas(void)
{
//--- Формирование имени объекта
string name=CElementBase::ElementName("combobox");
//--- Если нужен элемент с чек-боксом
if(m_checkbox_mode)
{
IconFile(RESOURCE_CHECKBOX_OFF);
IconFileLocked(RESOURCE_CHECKBOX_OFF_LOCKED);
IconFilePressed(RESOURCE_CHECKBOX_ON);
IconFilePressedLocked(RESOURCE_CHECKBOX_ON_LOCKED);
}
//--- Создание объекта
if(!CElement::CreateCanvas(name,m_x,m_y,m_x_size,m_y_size))
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Создаёт кнопку |
//+------------------------------------------------------------------+
bool CComboBox::CreateButton(void)
{
//--- Сохраним указатель на родительский элемент
m_button.MainPointer(this);
//--- Размеры
int x_size=(m_button.XSize()<1)? 80 : m_button.XSize();
//--- Координаты
int x =(m_button.XGap()<1)? x_size : m_button.XGap();
int y =0;
//--- Отступы для картинки
int icon_x_gap =(m_button.IconXGap()<1)? x_size-18 : m_button.IconXGap();
int icon_y_gap =(m_button.IconYGap()<1)? 2 : m_button.IconYGap();
//--- Отступы для текста
int label_x_gap =(m_button.LabelXGap()<1)? 7 : m_button.LabelXGap();
int label_y_gap =(m_button.LabelYGap()<1)? 4 : m_button.LabelYGap();
//--- Свойства
m_button.NamePart("combobox_button");
m_button.Index(0);
m_button.TwoState(true);
m_button.XSize(x_size);
m_button.YSize(m_y_size);
m_button.IconXGap(icon_x_gap);
m_button.IconYGap(icon_y_gap);
m_button.LabelXGap(label_x_gap);
m_button.LabelYGap(label_y_gap);
m_button.IsDropdown(CElementBase::IsDropdown());
m_button.IconFile(RESOURCE_DOWN_THIN_BLACK);
m_button.IconFileLocked(RESOURCE_DOWN_THIN_BLACK);
m_button.CElement::IconFilePressed(RESOURCE_UP_THIN_BLACK);
m_button.CElement::IconFilePressedLocked(RESOURCE_UP_THIN_BLACK);
//--- Создадим элемент управления
if(!m_button.CreateButton("",x,y))
return(false);
//--- Добавить элемент в массив
CElement::AddToArray(m_button);
return(true);
}
//+------------------------------------------------------------------+
//| Создаёт список |
//+------------------------------------------------------------------+
bool CComboBox::CreateList(void)
{
//--- Сохраним указатель на главный элемент
m_listview.MainPointer(this);
//--- Координаты
int x =m_button.XGap();
int y =m_button.YSize();
//--- Размеры
int x_size =(m_listview.XSize()<1)? m_button.XSize() : m_listview.XSize();
int y_size =(m_listview.YSize()<1)? 93 : m_listview.YSize();
//--- Свойства
m_listview.XSize(x_size);
m_listview.YSize(y_size);
m_listview.AnchorRightWindowSide(m_button.AnchorRightWindowSide());
//--- Создадим элемент управления
if(!m_listview.CreateListView(x,y))
return(false);
//--- Скрыть список
m_listview.Hide();
//--- Добавить элемент в массив
CElement::AddToArray(m_listview);
return(true);
}
//+------------------------------------------------------------------+
//| Установка состояния элемента (нажат/отжат) |
//+------------------------------------------------------------------+
void CComboBox::IsPressed(const bool state)
{
//--- Выйти, если (1) элемент заблокирован или (2) элемент уже в таком состоянии
if(CElementBase::IsLocked() || m_is_pressed==state)
return;
//--- Установка состояния
m_is_pressed=state;
//--- Установить соответствующую картинку
CElement::ChangeImage(0,!m_is_pressed? 0 : 2);
}
//+------------------------------------------------------------------+
//| Сохраняет переданное значение в списке по указанному индексу |
//+------------------------------------------------------------------+
void CComboBox::SetValue(const int item_index,const string item_text)
{
m_listview.SetValue(item_index,item_text);
}
//+------------------------------------------------------------------+
//| Возвращает выбранное в списке значение |
//+------------------------------------------------------------------+
string CComboBox::GetValue(void)
{
return(m_listview.SelectedItemText());
}
//+------------------------------------------------------------------+
//| Выделение пункта по указанному индексу |
//+------------------------------------------------------------------+
void CComboBox::SelectItem(const int item_index)
{
//--- Выбрать пункт в списке
m_listview.SelectItem(item_index);
//--- Установить текст в кнопку
m_button.LabelText(m_listview.SelectedItemText());
}
//+------------------------------------------------------------------+
//| Блокировка |
//+------------------------------------------------------------------+
void CComboBox::IsLocked(const bool state)
{
CElement::IsLocked(state);
//--- Установить соответствующую картинку
CElement::ChangeImage(0,(m_is_locked)? !m_is_pressed? 1 : 3 : !m_is_pressed? 0 : 2);
}
//+------------------------------------------------------------------+
//| Скрытие |
//+------------------------------------------------------------------+
void CComboBox::Hide(void)
{
CElement::Hide();
//--- Отжать кнопку
m_button.IsPressed(false);
}
//+------------------------------------------------------------------+
//| Изменяет текущее состояние комбо-бокса на противоположное |
//+------------------------------------------------------------------+
void CComboBox::ChangeComboBoxListState(void)
{
//--- Если кнопка нажата
if(m_button.IsPressed())
{
//--- Показать список
m_listview.Show();
//--- Отправим сообщение на определение доступных элементов
::EventChartCustom(m_chart_id,ON_SET_AVAILABLE,CElementBase::Id(),0,"");
//--- Отправим сообщение об изменении в графическом интерфейсе
::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,"");
}
else
{
//--- Скрыть список
m_listview.Hide();
//--- Отправим сообщение на восстановление элементов
::EventChartCustom(m_chart_id,ON_SET_AVAILABLE,CElementBase::Id(),1,"");
//--- Отправим сообщение об изменении в графическом интерфейсе
::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,"");
}
}
//+------------------------------------------------------------------+
//| Нажатие на чек-боксе |
//+------------------------------------------------------------------+
bool CComboBox::OnClickElement(const string pressed_object)
{
//--- Выйдем, если (1) элемент заблокирован или (2) чужое имя объекта
if(CElementBase::IsLocked() || m_canvas.ChartObjectName()!=pressed_object)
return(false);
//--- Если чек-бокс включен
if(m_checkbox_mode)
{
//--- Переключить на противоположный режим
IsPressed(!(IsPressed()));
//--- Отправим сообщение об этом
::EventChartCustom(m_chart_id,ON_CLICK_CHECKBOX,CElementBase::Id(),CElementBase::Index(),"");
}
//--- Нарисовать элемент
CElement::Update(true);
return(true);
}
//+------------------------------------------------------------------+
//| Нажатие на кнопку комбо-бокса |
//+------------------------------------------------------------------+
bool CComboBox::OnClickButton(const string pressed_object,const int id,const int index)
{
//--- Выйти, если нажатие было на другом элементе
if(!m_button.CheckElementName(pressed_object))
return(false);
//--- Выйти, если значения не совпадают
if(id!=m_button.Id() || index!=m_button.Index())
return(false);
//--- Изменить состояние списка
ChangeComboBoxListState();
//--- Отправим сообщение об этом
::EventChartCustom(m_chart_id,ON_CLICK_COMBOBOX_BUTTON,CElementBase::Id(),0,"");
return(true);
}
//+------------------------------------------------------------------+
//| Обработка нажатия на пункте списка |
//+------------------------------------------------------------------+
bool CComboBox::OnClickListItem(const int id)
{
//--- Выйти, если значения не совпадают
if(id!=CElementBase::Id())
return(false);
//--- Отжать кнопку
m_button.IsPressed(false);
//--- Установить текст в кнопку
m_button.LabelText(m_listview.SelectedItemText());
m_button.Update(true);
//--- Изменить состояние списка
ChangeComboBoxListState();
//--- Отправим сообщение об этом
::EventChartCustom(m_chart_id,ON_CLICK_COMBOBOX_ITEM,CElementBase::Id(),0,m_label_text);
return(true);
}
//+------------------------------------------------------------------+
//| Проверка нажатой левой кнопки мыши над кнопкой |
//+------------------------------------------------------------------+
void CComboBox::CheckPressedOverButton(void)
{
//--- Выйти, если кнопка уже отжата
if(!m_button.IsPressed())
return;
//--- Выйти, если (1) элемент заблокирован или (2) левая кнопка мыши отжата
if(CElementBase::IsLocked() || !m_mouse.LeftButtonState())
return;
//--- Если фокуса нет
if(!CElementBase::MouseFocus() && !m_button.MouseFocus())
{
//--- Выйти, если фокус на списке или полоса прокрутки списка в действии
if(m_listview.MouseFocus() || m_listview.ScrollState())
return;
//--- Скрыть список
m_listview.Hide();
m_button.IsPressed(false);
m_button.Update(true);
//--- Нарисовать элемент
Update(true);
//--- Отправим сообщение на восстановление элементов
::EventChartCustom(m_chart_id,ON_SET_AVAILABLE,CElementBase::Id(),1,"");
//--- Отправим сообщение об изменении в графическом интерфейсе
::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0.0,"");
}
}
//+------------------------------------------------------------------+
//| Рисует элемент |
//+------------------------------------------------------------------+
void CComboBox::Draw(void)
{
//--- Нарисовать фон
CElement::DrawBackground();
//--- Нарисовать картинку
CElement::DrawImage();
//--- Нарисовать текст
CElement::DrawText();
}
//+------------------------------------------------------------------+
//| Рисует картинку |
//+------------------------------------------------------------------+
void CComboBox::DrawImage(void)
{
//--- Выйти, если (1) чек-бокс не нужен или (2) картинка не определена
if(!m_checkbox_mode || CElement::IconFile()=="")
return;
//--- Определим индекс
uint image_index=(m_is_pressed)? 2 : 0;
//--- Если элемент не заблокирован
if(!CElementBase::IsLocked())
{
if(CElementBase::MouseFocus())
image_index=(m_is_pressed)? 2 : 0;
}
else
image_index=(m_is_pressed)? 3 : 1;
//--- Установить соответствующую картинку
CElement::ChangeImage(0,image_index);
//--- Рисуем картинку
CElement::DrawImage();
}
//+------------------------------------------------------------------+