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

417 lines
35 KiB
MQL5

//+------------------------------------------------------------------+
//| MenuBar.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "..\Element.mqh"
#include "MenuItem.mqh"
#include "ContextMenu.mqh"
//+------------------------------------------------------------------+
//| Класс для создания главного меню |
//+------------------------------------------------------------------+
class CMenuBar : public CElement
{
private:
//--- Объекты для создания пункта меню
CMenuItem m_items[];
//--- Массив указателей на контекстные меню
CContextMenu *m_contextmenus[];
//--- Состояние главного меню
bool m_menubar_state;
//--- Индекс предыдущего активированного пункта
int m_prev_active_item_index;
//---
public:
CMenuBar(void);
~CMenuBar(void);
//--- Методы для создания элемента
bool CreateMenuBar(const int x_gap,const int y_gap);
//---
private:
void InitializeProperties(const int x_gap,const int y_gap);
bool CreateCanvas(void);
bool CreateItems(void);
//---
public:
//--- (1) Получение указателя указанного пункта меню, (2) получение указателя указанного контекстного меню
CMenuItem *GetItemPointer(const uint index);
CContextMenu *GetContextMenuPointer(const uint index);
//--- Количество (1) пунктов и (2) контекстных меню, (3) состояние главного меню
int ItemsTotal(void) const { return(::ArraySize(m_items)); }
int ContextMenusTotal(void) const { return(::ArraySize(m_contextmenus)); }
bool State(void) const { return(m_menubar_state); }
void State(const bool state);
//--- Добавляет пункт меню с указанными свойствами до создания главного меню
void AddItem(const int width,const string text);
//--- Присоединяет переданное контекстное меню к указанному пункту главного меню
void AddContextMenuPointer(const uint index,CContextMenu &object);
//---
public:
//--- Обработчик событий графика
virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- Удаление
virtual void Delete(void);
//--- Рисует элемент
virtual void Draw(void);
//---
private:
//--- Обработка нажатия на пункте меню
bool OnClickMenuItem(const int id,const int index);
//--- Возвращает активный пункт главного меню
int ActiveItemIndex(void);
//--- Переключает контекстные меню главного меню, наведением курсора
void SwitchContextMenuByFocus(void);
//--- Изменить ширину по правому краю окна
virtual void ChangeWidthByRightWindowSide(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CMenuBar::CMenuBar(void) : m_menubar_state(false),
m_prev_active_item_index(WRONG_VALUE)
{
//--- Сохраним имя класса элемента в базовом классе
CElementBase::ClassName(CLASS_NAME);
//--- Центрировать текст в пунктах меню
CElement::IsCenterText(true);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CMenuBar::~CMenuBar(void)
{
}
//+------------------------------------------------------------------+
//| Обработчик событий |
//+------------------------------------------------------------------+
void CMenuBar::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Обработка события смены фокуса на кнопках меню
if(id==CHARTEVENT_CUSTOM+ON_MOUSE_FOCUS)
{
//--- Выйти, если (2) главное меню не активировано или (2) идентификаторы не совпадают
if(!m_menubar_state || lparam!=CElementBase::Id())
return;
//--- Переключить контекстное меню по активированному пункту главного меню
SwitchContextMenuByFocus();
return;
}
//--- Обработка события нажатия левой кнопки мыши на пункте главного меню
if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
{
if(OnClickMenuItem((uint)lparam,(uint)dparam))
return;
//---
return;
}
}
//+------------------------------------------------------------------+
//| Создаёт главное меню |
//+------------------------------------------------------------------+
bool CMenuBar::CreateMenuBar(const int x_gap,const int y_gap)
{
//--- Выйти, если нет указателя на главный элемент
if(!CElement::CheckMainPointer())
return(false);
//--- Инициализация свойств
InitializeProperties(x_gap,y_gap);
//--- Создание элемента
if(!CreateCanvas())
return(false);
if(!CreateItems())
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Инициализация свойств |
//+------------------------------------------------------------------+
void CMenuBar::InitializeProperties(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 || m_auto_xresize_mode)? m_main.X2()-m_x-m_auto_xresize_right_offset : m_x_size;
m_y_size =(m_y_size<1)? 22 : m_y_size;
//--- Свойства по умолчанию
m_back_color =(m_back_color!=clrNONE)? m_back_color : C'225,225,225';
m_back_color_hover =(m_back_color_hover!=clrNONE)? m_back_color_hover : C'51,153,255';
m_back_color_pressed =(m_back_color_pressed!=clrNONE)? m_back_color_pressed : m_back_color_hover;
m_border_color =(m_border_color!=clrNONE)? m_border_color : m_back_color;
m_border_color_hover =(m_border_color_hover!=clrNONE)? m_border_color_hover : m_back_color;
m_border_color_pressed =(m_border_color_pressed!=clrNONE)? m_border_color_pressed : m_back_color;
m_label_y_gap =(m_label_y_gap!=WRONG_VALUE)? m_label_y_gap : 3;
m_label_color =(m_label_color!=clrNONE)? m_label_color : clrBlack;
m_label_color_hover =(m_label_color_hover!=clrNONE)? m_label_color_hover : clrWhite;
m_label_color_pressed =(m_label_color_pressed!=clrNONE)? m_label_color_pressed : clrWhite;
//--- Отступы от крайней точки
CElementBase::XGap(x_gap);
CElementBase::YGap(y_gap);
}
//+------------------------------------------------------------------+
//| Создаёт объект для рисования |
//+------------------------------------------------------------------+
bool CMenuBar::CreateCanvas(void)
{
//--- Формирование имени объекта
string name=CElementBase::ElementName("menubar");
//--- Создание объекта
if(!CElement::CreateCanvas(name,m_x,m_y,m_x_size,m_y_size))
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Создаёт список пунктов меню |
//+------------------------------------------------------------------+
bool CMenuBar::CreateItems(void)
{
//--- Координаты
int x=0,y=0;
//---
int items_total=ItemsTotal();
for(int i=0; i<items_total; i++)
{
//--- Расчёт координаты X
x=(i>0)? x+m_items[i-1].XSize() : x;
//--- Сохраним указатель на главный элемент
m_items[i].MainPointer(this);
//--- Установим свойства перед созданием
m_items[i].Index(i);
m_items[i].NamePart("menu_item");
m_items[i].TwoState(true);
m_items[i].TypeMenuItem(MI_HAS_CONTEXT_MENU);
m_items[i].ShowRightArrow(false);
m_items[i].XSize(m_items[i].XSize());
m_items[i].YSize(m_y_size);
m_items[i].BackColor(m_back_color);
m_items[i].BackColorHover(m_back_color_hover);
m_items[i].BackColorPressed(m_back_color_pressed);
m_items[i].BorderColor(m_border_color);
m_items[i].BorderColorHover(m_border_color_hover);
m_items[i].BorderColorPressed(m_border_color_pressed);
m_items[i].IconXGap(3);
m_items[i].IconYGap(4);
m_items[i].LabelXGap(m_label_x_gap);
m_items[i].LabelYGap(m_label_y_gap);
m_items[i].LabelColor(m_label_color);
m_items[i].LabelColorHover(m_label_color_hover);
m_items[i].LabelColorPressed(m_label_color_pressed);
m_items[i].IsCenterText(CElement::IsCenterText());
//--- Создание пункта меню
if(!m_items[i].CreateMenuItem(m_items[i].LabelText(),x,y))
return(false);
//--- Добавить элемент в массив
CElement::AddToArray(m_items[i]);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Установка состояния главного меню |
//+------------------------------------------------------------------+
void CMenuBar::State(const bool state)
{
if(state)
m_menubar_state=true;
else
{
m_menubar_state=false;
//--- Пройтись по всем пунктам главного меню для установки статуса отключенных контекстных меню
int items_total=ItemsTotal();
for(int i=0; i<items_total; i++)
{
m_items[i].IsPressed(false);
m_items[i].Update(true);
}
}
}
//+------------------------------------------------------------------+
//| Возвращает указатель пункта меню по индексу |
//+------------------------------------------------------------------+
CMenuItem *CMenuBar::GetItemPointer(const uint index)
{
uint array_size=::ArraySize(m_items);
//--- Если нет ни одного пункта в главном меню, сообщить об этом
if(array_size<1)
{
::Print(__FUNCTION__," > Вызов этого метода нужно осуществлять, "
"когда в главном меню есть хотя бы один пункт!");
}
//--- Корректировка в случае выхода из диапазона
uint i=(index>=array_size)? array_size-1 : index;
//--- Вернуть указатель
return(::GetPointer(m_items[i]));
}
//+------------------------------------------------------------------+
//| Возвращает указатель контекстного меню по индексу |
//+------------------------------------------------------------------+
CContextMenu *CMenuBar::GetContextMenuPointer(const uint index)
{
uint array_size=::ArraySize(m_contextmenus);
//--- Если нет ни одного пункта в главном меню, сообщить об этом
if(array_size<1)
{
::Print(__FUNCTION__," > Вызов этого метода нужно осуществлять, "
"когда в главном меню есть хотя бы один пункт!");
}
//--- Корректировка в случае выхода из диапазона
uint i=(index>=array_size)? array_size-1 : index;
//--- Вернуть указатель
return(::GetPointer(m_contextmenus[i]));
}
//+------------------------------------------------------------------+
//| Добавляет пункт меню |
//+------------------------------------------------------------------+
void CMenuBar::AddItem(const int width,const string text)
{
//--- Увеличим размер массивов на один элемент
int array_size=::ArraySize(m_items);
::ArrayResize(m_items,array_size+1);
::ArrayResize(m_contextmenus,array_size+1);
//--- Сохраним значения переданных параметров
m_items[array_size].XSize(width);
m_items[array_size].LabelText(text);
}
//+------------------------------------------------------------------+
//| Добавляет указатель контекстного меню |
//+------------------------------------------------------------------+
void CMenuBar::AddContextMenuPointer(const uint index,CContextMenu &object)
{
//--- Проверка на выход из диапазона
uint size=::ArraySize(m_contextmenus);
if(size<1 || index>=size)
return;
//--- Сохранить указатель
m_contextmenus[index]=::GetPointer(object);
}
//+------------------------------------------------------------------+
//| Удаление |
//+------------------------------------------------------------------+
void CMenuBar::Delete(void)
{
//--- Удаление объектов
CElement::Delete();
//--- Освобождение массивов элемента
::ArrayFree(m_items);
::ArrayFree(m_contextmenus);
}
//+------------------------------------------------------------------+
//| Нажатие на пункте главного меню |
//+------------------------------------------------------------------+
bool CMenuBar::OnClickMenuItem(const int id,const int index)
{
//--- Выйти, если (1) идентификаторы не совпадают или (2) элемент заблокирован
if(id!=CElementBase::Id() || CElementBase::IsLocked())
return(false);
//--- Если есть указатель на контекстное меню
if(::CheckPointer(m_contextmenus[index])!=POINTER_INVALID)
{
//--- Состояние главного меню зависит от видимости контекстного меню
m_menubar_state=(m_contextmenus[index].IsVisible())? false : true;
//--- Определим выделенный пункт
m_prev_active_item_index=(m_menubar_state)? index : WRONG_VALUE;
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Возвращает индекс активированного пункта меню |
//+------------------------------------------------------------------+
int CMenuBar::ActiveItemIndex(void)
{
int active_item_index=WRONG_VALUE;
//---
int items_total=ItemsTotal();
for(int i=0; i<items_total; i++)
{
//--- Если пункт в фокусе
if(m_items[i].MouseFocus())
{
//--- Запомним индекс и остановим цикл
active_item_index=i;
break;
}
}
//---
return(active_item_index);
}
//+------------------------------------------------------------------+
//| Переключает контекстные меню главного меню, наведением курсора |
//+------------------------------------------------------------------+
void CMenuBar::SwitchContextMenuByFocus(void)
{
//--- Получим индекс активиронного пункта главного меню
int active_item_index=ActiveItemIndex();
//--- Выйти, если (1) меню не активировано или (2) это тот же пункт меню
if(active_item_index==WRONG_VALUE || active_item_index==m_prev_active_item_index)
return;
//--- Перейти к следующему, если в этом пункте нет контекстного меню
if(::CheckPointer(m_contextmenus[active_item_index])!=POINTER_INVALID)
{
//--- Сделать контекстное меню видимым
m_contextmenus[active_item_index].Show();
m_items[active_item_index].IsPressed(true);
}
//--- Получим указатель на предыдущий выделенный пункт
CContextMenu *cm=m_contextmenus[m_prev_active_item_index];
//--- Скрыть контекстные меню, которые открыты из других контекстных меню.
// Пройдёмся в цикле по пунктам текущего контекстного меню, чтобы выяснить, есть ли такие.
int cm_items_total=cm.ItemsTotal();
for(int c=0; c<cm_items_total; c++)
{
CMenuItem *mi=cm.GetItemPointer(c);
//--- Перейти к следующему, если указатель на пункт некорректный
if(::CheckPointer(mi)==POINTER_INVALID)
continue;
//--- Перейти к следующему, если этот пункт не содержит в себе контекстное меню
if(mi.TypeMenuItem()!=MI_HAS_CONTEXT_MENU)
continue;
//--- Если контекстное меню активировано
if(mi.IsPressed())
{
//--- Отправить сигнал на закрытие всех контекстных меню, которые открыты из этого
::EventChartCustom(m_chart_id,ON_HIDE_BACK_CONTEXTMENUS,CElementBase::Id(),0,"");
break;
}
}
//--- Скрыть контекстное меню главного меню
m_contextmenus[m_prev_active_item_index].Hide();
m_items[m_prev_active_item_index].IsPressed(false);
m_items[m_prev_active_item_index].Update(true);
//--- Запомним индекс текущего активированного меню
m_prev_active_item_index=active_item_index;
//--- Отправим сообщение на определение доступных элементов
::EventChartCustom(m_chart_id,ON_SET_AVAILABLE,CElementBase::Id(),0,"");
//--- Отправим сообщение об изменении в графическом интерфейсе
::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0.0,"");
}
//+------------------------------------------------------------------+
//| Изменить ширину по правому краю формы |
//+------------------------------------------------------------------+
void CMenuBar::ChangeWidthByRightWindowSide(void)
{
//--- Выйти, если включен режим фиксации к правому краю формы
if(m_anchor_right_window_side)
return;
//--- Размеры
int x_size=0;
//--- Рассчитать и установить новый размер фону элемента
x_size=m_main.X2()-m_canvas.X()-m_auto_xresize_right_offset;
CElementBase::XSize(x_size);
m_canvas.XSize(x_size);
m_canvas.Resize(x_size,m_y_size);
//--- Перерисовать элемент
Draw();
//--- Обновить положение объектов
Moving();
}
//+------------------------------------------------------------------+
//| Рисует элемент |
//+------------------------------------------------------------------+
void CMenuBar::Draw(void)
{
//--- Нарисовать фон
CElement::DrawBackground();
}
//+------------------------------------------------------------------+