//+------------------------------------------------------------------+ //| TextEdit.mqh | //| Copyright 2016, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "..\Element.mqh" #include "TextBox.mqh" class CCalendar; //+------------------------------------------------------------------+ //| Класс для создания текстового поля ввода | //+------------------------------------------------------------------+ class CTextEdit : public CElement { private: //--- Объекты для создания поля ввода CTextBox m_edit; CButton m_button_inc; CButton m_button_dec; //--- Режим элемента с чек-боксом bool m_checkbox_mode; //--- Режим числового поля ввода с кнопками bool m_spin_edit_mode; //--- Текущее значение в поле ввода string m_edit_value; //--- Режим сброса значения (пустая строка) bool m_reset_mode; //--- Минимальное/максимальное значение double m_min_value; double m_max_value; //--- Шаг для изменения значения в поле ввода double m_step_value; //--- Счётчик таймера для перемотки списка int m_timer_counter; //--- Количество знаков после запятой int m_digits; //--- public: CTextEdit(void); ~CTextEdit(void); //--- Методы для создания текствого поля ввода bool CreateTextEdit(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 CreateEdit(void); bool CreateSpinButton(CButton &button_obj,const int index); //--- public: //--- Возвращает указатели на составные элементы CTextBox *GetTextBoxPointer(void) { return(::GetPointer(m_edit)); } CButton *GetIncButtonPointer(void) { return(::GetPointer(m_button_inc)); } CButton *GetDecButtonPointer(void) { return(::GetPointer(m_button_dec)); } //--- Режим сброса при нажатии на текстовой метке bool ResetMode(void) const { return(m_reset_mode); } void ResetMode(const bool mode) { m_reset_mode=mode; } //--- (1) Режимы чек-бокса и (2) числового поля ввода void CheckBoxMode(const bool state) { m_checkbox_mode=state; } bool SpinEditMode(void) const { return(m_spin_edit_mode); } void SpinEditMode(const bool state) { m_spin_edit_mode=state; } //--- Минимальное значение double MinValue(void) const { return(m_min_value); } void MinValue(const double value) { m_min_value=value; } //--- Максимальное значение double MaxValue(void) const { return(m_max_value); } void MaxValue(const double value) { m_max_value=value; } //--- (1) Шаг значения, (2) установка количества знаков после запятой double StepValue(void) const { return(m_step_value); } void StepValue(const double value) { m_step_value=(value<=0)? 1 : value; } int GetDigits(void) const { return(m_digits); } void SetDigits(const int digits) { m_digits=::fabs(digits); } //--- Состояние элемента (нажат/отжат) bool IsPressed(void) const { return(m_is_pressed); } void IsPressed(const bool state); //--- Возвращение и установка значения поля ввода string GetValue(void) { return(m_edit.GetValue(0)); } void SetValue(const string value,const bool is_size_adjustment=true); //--- public: //--- Обработчик событий графика virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- Таймер virtual void OnEventTimer(void); //--- Блокировка virtual void IsLocked(const bool state); //--- Рисует элемент virtual void Draw(void); //--- private: //--- Обработка нажатия на элементе bool OnClickElement(const string clicked_object); //--- Обработка окончания ввода значения bool OnEndEdit(const uint id); //--- Обработка нажатия кнопок поля ввода bool OnClickButtonInc(const string pressed_object,const uint id,const uint index); bool OnClickButtonDec(const string pressed_object,const uint id,const uint index); //--- Ускоренная перемотка значений в поле ввода void FastSwitching(void); //--- Корректировка значения string AdjustmentValue(const double value); //--- Подсвечивание лимита void HighlightLimit(void); //--- Рисует картинку virtual void DrawImage(void); //--- Изменить ширину по правому краю окна virtual void ChangeWidthByRightWindowSide(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTextEdit::CTextEdit(void) : m_edit_value(""), m_digits(0), m_min_value(DBL_MIN), m_max_value(DBL_MAX), m_step_value(1), m_reset_mode(false), m_checkbox_mode(false), m_spin_edit_mode(false), m_timer_counter(SPIN_DELAY_MSC) { //--- Сохраним имя класса элемента в базовом классе CElementBase::ClassName(CLASS_NAME); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CTextEdit::~CTextEdit(void) { } //+------------------------------------------------------------------+ //| Обработка событий | //+------------------------------------------------------------------+ void CTextEdit::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Обработка события перемещения курсора if(id==CHARTEVENT_MOUSE_MOVE) { //--- Проверка фокуса над элементами m_edit.MouseFocus(m_mouse.X()>m_edit.X() && m_mouse.X()m_edit.Y() && m_mouse.Y()m_max_value) corrected_value=m_max_value; //--- Если значение было изменено if(::StringToDouble(m_edit_value)!=corrected_value || m_edit_value=="") m_edit_value=::DoubleToString(corrected_value,m_digits); //--- Значение без изменений return(m_edit_value); } //+------------------------------------------------------------------+ //| Блокировка | //+------------------------------------------------------------------+ void CTextEdit::IsLocked(const bool state) { CElement::IsLocked(state); //--- Установить соответствующую картинку CElement::ChangeImage(0,(m_is_locked)? !m_is_pressed? 1 : 3 : !m_is_pressed? 0 : 2); } //+------------------------------------------------------------------+ //| Обработка нажатия на элементе | //+------------------------------------------------------------------+ bool CTextEdit::OnClickElement(const string clicked_object) { //--- Выйдем, если (1) элемент заблокирован или (2) чужое имя объекта if(CElementBase::IsLocked() || m_canvas.ChartObjectName()!=clicked_object) return(false); //--- Если включен режим сброса значения if(m_reset_mode) SetValue(""); //--- Если чек-бокс включен if(m_checkbox_mode) { //--- Переключить на противоположное состояние IsPressed(!(IsPressed())); //--- Нарисовать элемент Update(true); //--- Отправим сообщение об этом ::EventChartCustom(m_chart_id,ON_CLICK_CHECKBOX,CElementBase::Id(),CElementBase::Index(),""); } //--- return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на элементе | //+------------------------------------------------------------------+ bool CTextEdit::OnEndEdit(const uint id) { //--- Выйдем, если идентификаторы не совпадают if(id!=CElementBase::Id()) return(false); //--- Установить значение SetValue(m_edit.GetValue()); //--- Обновить поле ввода m_edit.Update(true); return(true); } //+------------------------------------------------------------------+ //| Нажатие на переключатель инкремента | //+------------------------------------------------------------------+ bool CTextEdit::OnClickButtonInc(const string pressed_object,const uint id,const uint index) { //--- Выйдем, если нажатие было не на кнопке if(::StringFind(pressed_object,m_program_name+"_spin_inc")<0) return(false); //--- Выйдем, если идентификаторы и индексы не совпадают if(id!=CElementBase::Id() || index!=m_button_inc.Index()) return(false); //--- Получим новое значение double value=::StringToDouble(m_edit.GetValue())+m_step_value; //--- Увеличим на один шаг и проверим на выход за ограничение SetValue(::DoubleToString(value),false); //--- Отожмём кнопку m_button_inc.IsPressed(false); //--- Обновить поле ввода m_edit.Update(true); // Aqui agregamos un nuevo evento para INC ::EventChartCustom(m_chart_id,ON_CLICK_INC,CElementBase::Id(),m_button_inc.Index(),""); return(true); } //+------------------------------------------------------------------+ //| Нажатие на переключатель декремента | //+------------------------------------------------------------------+ bool CTextEdit::OnClickButtonDec(const string pressed_object,const uint id,const uint index) { //--- Выйдем, если нажатие было не на кнопке if(::StringFind(pressed_object,m_program_name+"_spin_dec")<0) return(false); //--- Выйдем, если идентификаторы и индексы не совпадают if(id!=CElementBase::Id() || index!=m_button_dec.Index()) return(false); //--- Получим текущее значение double value=::StringToDouble(m_edit.GetValue())-m_step_value; //--- Уменьшим на один шаг и проверим на выход за ограничение SetValue(::DoubleToString(value),false); //--- Отожмём кнопку m_button_dec.IsPressed(false); //--- Обновить поле ввода m_edit.Update(true); // Aqui agregamos un nuevo evento para DEC ::EventChartCustom(m_chart_id,ON_CLICK_DEC,CElementBase::Id(),m_button_dec.Index(),""); return(true); } //+------------------------------------------------------------------+ //| Ускоренная промотка значения в поле ввода | //+------------------------------------------------------------------+ void CTextEdit::FastSwitching(void) { //--- Выйдем, если (1) нет фокуса на элементе или (2) элемент является частью календаря if(!CElementBase::MouseFocus() || dynamic_cast(m_main)!=NULL) return; //--- Вернём счётчик к первоначальному значению, если кнопка мыши отжата if(!m_mouse.LeftButtonState()) m_timer_counter=SPIN_DELAY_MSC; //--- Если же кнопка мыши нажата else { //--- Увеличим счётчик на установленный интервал m_timer_counter+=TIMER_STEP_MSC; //--- Выйдем, если меньше нуля if(m_timer_counter<0) return; //--- Получим текущее значение в поле ввода double current_value=::StringToDouble(m_edit.GetValue()); //--- Если увеличить if(m_button_inc.MouseFocus()) { SetValue(::DoubleToString(current_value+m_step_value),false); m_edit.Update(true); //--- Отправим сообщение об этом ::EventChartCustom(m_chart_id,ON_CLICK_INC,CElementBase::Id(),m_button_inc.Index(),""); } //--- Если уменьшить else if(m_button_dec.MouseFocus()) { SetValue(::DoubleToString(current_value-m_step_value),false); m_edit.Update(true); //--- Отправим сообщение об этом ::EventChartCustom(m_chart_id,ON_CLICK_DEC,CElementBase::Id(),m_button_dec.Index(),""); } } } //+------------------------------------------------------------------+ //| Рисует элемент | //+------------------------------------------------------------------+ void CTextEdit::Draw(void) { //--- Нарисовать фон CElement::DrawBackground(); //--- Нарисовать картинку CElement::DrawImage(); //--- Нарисовать текст CElement::DrawText(); } //+------------------------------------------------------------------+ //| Рисует картинку | //+------------------------------------------------------------------+ void CTextEdit::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(); } //+------------------------------------------------------------------+ //| Изменить ширину по правому краю формы | //+------------------------------------------------------------------+ void CTextEdit::ChangeWidthByRightWindowSide(void) { //--- Выйти, если включен режим фиксации к правому краю формы if(m_anchor_right_window_side) return; //--- Координаты и размеры int x=0,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(); } //+------------------------------------------------------------------+