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

329 lignes
28 Kio
MQL5

//+------------------------------------------------------------------+
//| MenuItem.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "..\Element.mqh"
#include "Button.mqh"
class CContextMenu;
//+------------------------------------------------------------------+
//| Класс создания пункта меню |
//+------------------------------------------------------------------+
class CMenuItem : public CButton
{
private:
//--- Указатель на предыдущий узел
CMenuItem *m_prev_node;
//--- Указатель на привязанное контекстное меню
CContextMenu *m_context_menu;
//--- Тип пункта меню
ENUM_TYPE_MENU_ITEM m_type_menu_item;
//--- Свойства признака контекстного меню
bool m_show_right_arrow;
int m_arrow_x_gap;
//--- Состояние чекбокса
bool m_checkbox_state;
//--- Состояние радио-кнопки и её идентификатор
bool m_radiobutton_state;
int m_radiobutton_id;
//---
public:
CMenuItem(void);
~CMenuItem(void);
//--- Методы для создания пункта меню
bool CreateMenuItem(const string text,const int x_gap,const int y_gap);
//---
public:
//--- (1) Получение и (2) сохранение указателя предыдущего узла
void GetPrevNodePointer(CMenuItem &object) { m_prev_node=::GetPointer(object); }
CMenuItem *GetPrevNodePointer(void) const { return(m_prev_node); }
void GetContextMenuPointer(CContextMenu &object) { m_context_menu=::GetPointer(object); }
CContextMenu *GetContextMenuPointer(void) const { return(m_context_menu); }
//--- (1) Установка и получение типа, (2) номер индекса
void TypeMenuItem(const ENUM_TYPE_MENU_ITEM type) { m_type_menu_item=type; }
ENUM_TYPE_MENU_ITEM TypeMenuItem(void) const { return(m_type_menu_item); }
//--- (1) Отображение признака наличия контекстного меню, (2) общее состояние пункта-чекбокса
void ShowRightArrow(const bool flag) { m_show_right_arrow=flag; }
bool CheckBoxState(void) const { return(m_checkbox_state); }
void CheckBoxState(const bool state);
//--- (1) Идентификатор радио-пункта, (2) состояние радио-пункта
void RadioButtonID(const int id) { m_radiobutton_id=id; }
int RadioButtonID(void) const { return(m_radiobutton_id); }
bool RadioButtonState(void) const { return(m_radiobutton_state); }
void RadioButtonState(const bool state);
//---
public:
//--- Обработчик событий графика
virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- Управление
virtual void Show(void);
virtual void Hide(void);
//--- Рисует элемент
virtual void Draw(void);
//---
private:
//--- Нажатие на пункте меню
bool OnClickMenuItem(const string pressed_object,const int id,const int index);
//--- Рисует картинку
virtual void DrawImage(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CMenuItem::CMenuItem(void) : m_type_menu_item(MI_SIMPLE),
m_checkbox_state(true),
m_radiobutton_id(0),
m_radiobutton_state(false),
m_show_right_arrow(true),
m_arrow_x_gap(18)
{
//--- Сохраним имя класса элемента в базовом классе
CElementBase::ClassName(CLASS_NAME);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CMenuItem::~CMenuItem(void)
{
}
//+------------------------------------------------------------------+
//| Обработчик событий |
//+------------------------------------------------------------------+
void CMenuItem::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Обработать событие в базовом классе
CButton::OnEvent(id,lparam,dparam,sparam);
//--- Обработка события нажатия левой кнопки мыши на элементе
if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
{
if(OnClickMenuItem(sparam,(uint)lparam,(uint)dparam))
return;
//---
return;
}
}
//+------------------------------------------------------------------+
//| Создаёт элемент "Пункт меню" |
//+------------------------------------------------------------------+
bool CMenuItem::CreateMenuItem(const string text,const int x_gap,const int y_gap)
{
//--- Выйти, если нет указателя на главный элемент
if(!CElement::CheckMainPointer())
return(false);
//--- Если указателя на предыдущий узел нет, то пункт не является частью контекстного меню
if(::CheckPointer(m_prev_node)==POINTER_INVALID)
{
//--- Выйти, если установленный тип не соответствует
if(m_type_menu_item!=MI_SIMPLE && m_type_menu_item!=MI_HAS_CONTEXT_MENU)
{
::Print(__FUNCTION__," > Тип независимого пункта меню может быть только MI_SIMPLE или MI_HAS_CONTEXT_MENU, ",
"то есть, с наличием контекстного меню.\n",
__FUNCTION__," > Установить тип пункта меню можно с помощью метода CMenuItem::TypeMenuItem()");
return(false);
}
}
//--- Определим ярлыки, если пункт имеет выпадающее меню
if(m_type_menu_item==MI_HAS_CONTEXT_MENU)
{
CButton::TwoState(true);
//--- Если нужно отображать стрелку, как признак наличия контекстного меню
if(m_show_right_arrow)
{
if(CButton::ImagesGroupTotal()<2)
{
CButton::AddImagesGroup(CElementBase::XSize()-m_arrow_x_gap,CElement::IconYGap());
CButton::AddImage(1,RESOURCE_ARROW_RIGHT_BLACK);
CButton::AddImage(1,RESOURCE_ARROW_RIGHT_WHITE);
}
}
}
//--- Если это чекбокс
if(m_type_menu_item==MI_CHECKBOX)
{
//--- Изображения по умолчанию
CButton::SetImage(0,0,RESOURCE_CHECKBOX_MINI_BLACK);
CButton::SetImage(0,1,RESOURCE_CHECKBOX_MINI_WHITE);
CButton::AddImage(0,INT_MAX);
}
//--- Если это радио-пункт
else if(m_type_menu_item==MI_RADIOBUTTON)
{
//--- Изображения по умолчанию
CButton::SetImage(0,0,RESOURCE_CHECKBOX_MINI_BLACK);
CButton::SetImage(0,1,RESOURCE_CHECKBOX_MINI_WHITE);
CButton::AddImage(0,INT_MAX);
}
//--- Свойства
CButton::NamePart("menu_item");
//--- Создадим элемент управления
if(!CButton::CreateButton(text,x_gap,y_gap))
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Изменение состояния пункта меню типа чекбокс |
//+------------------------------------------------------------------+
void CMenuItem::CheckBoxState(const bool state)
{
m_checkbox_state=state;
Update(true);
}
//+------------------------------------------------------------------+
//| Изменение состояния пункта меню типа радиопункт |
//+------------------------------------------------------------------+
void CMenuItem::RadioButtonState(const bool state)
{
m_radiobutton_state=state;
Update(true);
}
//+------------------------------------------------------------------+
//| Делает видимым пункт меню |
//+------------------------------------------------------------------+
void CMenuItem::Show(void)
{
//--- Выйти, если элемент уже видим
if(CElementBase::IsVisible())
return;
//--- Показать элемент
CButton::Show();
//--- Обновить положение объектов
Moving();
}
//+------------------------------------------------------------------+
//| Скрывает пункт меню |
//+------------------------------------------------------------------+
void CMenuItem::Hide(void)
{
//--- Выйти, если элемент скрыт
if(!CElementBase::IsVisible())
return;
//--- Скрыть элемент
CButton::Hide();
//--- Обнуление переменных
CElementBase::IsVisible(false);
CElementBase::MouseFocus(false);
}
//+------------------------------------------------------------------+
//| Обработка нажатия на пункте меню |
//+------------------------------------------------------------------+
bool CMenuItem::OnClickMenuItem(const string pressed_object,const int id,const int index)
{
//--- Выйдем, если нажатие было не на кнопке
if(::StringFind(pressed_object,"menu_item")<0)
return(false);
//--- Выйти, если (1) идентификаторы не совпадают или (2) элемент заблокирован
if(id!=CElementBase::Id() || index!=CElementBase::Index() || CElementBase::IsLocked())
return(false);
//--- Если этот пункт содержит контекстное меню
if(m_type_menu_item==MI_HAS_CONTEXT_MENU)
{
if(::CheckPointer(m_context_menu)==POINTER_INVALID)
return(true);
//--- Если выпадающее меню этого пункта не активировано
if(!m_context_menu.IsVisible())
{
//--- Показать контекстное меню
m_context_menu.Show();
//--- Сообщение на восстановление доступных элементов
::EventChartCustom(m_chart_id,ON_SET_AVAILABLE,CElementBase::Id(),0,"");
//--- Отправим сообщение об изменении в графическом интерфейсе
::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0.0,"");
}
else
{
int is_restore=1;
if(CheckPointer(m_prev_node)!=POINTER_INVALID)
is_restore=0;
//--- Скрыть контекстное меню
m_context_menu.Hide();
//--- Отправим сигнал для закрытия контекстных меню, которые дальше этого пункта
::EventChartCustom(m_chart_id,ON_HIDE_BACK_CONTEXTMENUS,CElementBase::Id(),0,"");
//--- Сообщение на восстановление доступных элементов
::EventChartCustom(m_chart_id,ON_SET_AVAILABLE,CElementBase::Id(),is_restore,"");
//--- Отправим сообщение об изменении в графическом интерфейсе
::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0.0,"");
}
}
//--- Если этот пункт не содержит контекстное меню, но является частью контекстного меню
else
{
//--- Префикс сообщения с именем программы
string message=CElementBase::ProgramName();
//--- Если это чекбокс, изменим его состояние
if(m_type_menu_item==MI_CHECKBOX)
{
m_checkbox_state=(m_checkbox_state)? false : true;
//--- Добавим в сообщение, что это чекбокс
message+="_checkbox";
}
//--- Если это радио-пункт, изменим его состояние
else if(m_type_menu_item==MI_RADIOBUTTON)
{
m_radiobutton_state=(m_radiobutton_state)? false : true;
//--- Добавим в сообщение, что это радио-пункт
message+="_radioitem_"+(string)m_radiobutton_id;
}
//--- Отжать кнопку
CElementBase::MouseFocus(false);
CElement::Update(true);
//--- Отправим сообщение об этом
::EventChartCustom(m_chart_id,ON_CLICK_MENU_ITEM,CElementBase::Id(),CElementBase::Index(),message);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Рисует элемент |
//+------------------------------------------------------------------+
void CMenuItem::Draw(void)
{
//--- Нарисовать фон
CButton::DrawBackground();
//--- Нарисовать рамку
CButton::DrawBorder();
//--- Нарисовать картинку
if(m_type_menu_item!=MI_SIMPLE)
CMenuItem::DrawImage();
else
CButton::DrawImage();
//--- Нарисовать текст
CElement::DrawText();
}
//+------------------------------------------------------------------+
//| Рисует картинку |
//+------------------------------------------------------------------+
void CMenuItem::DrawImage(void)
{
//--- Определим индекс
uint image_index=0;
//---
if(m_type_menu_item==MI_CHECKBOX)
{
image_index=(m_checkbox_state)?(m_mouse_focus)? 1 : 0 : 2;
//--- Сохранить индекс выбранного изображения
CElement::ChangeImage(0,image_index);
}
else if(m_type_menu_item==MI_RADIOBUTTON)
{
image_index=(m_radiobutton_state)?(m_mouse_focus)? 1 : 0 : 2;
//--- Сохранить индекс выбранного изображения
CElement::ChangeImage(0,image_index);
}
else if(m_type_menu_item==MI_HAS_CONTEXT_MENU)
{
image_index=(m_mouse_focus || m_is_pressed)? 1 : 0;
//--- Сохранить индекс выбранного изображения
CElement::ChangeImage(0,0);
CElement::ChangeImage(1,image_index);
}
else
{
//--- Сохранить индекс выбранного изображения
CElement::ChangeImage(0,image_index);
}
//--- Рисуем картинку
CElement::DrawImage();
}
//+------------------------------------------------------------------+