//+------------------------------------------------------------------+ //| LatencyPanel.mqh | //| Copyright 2026, MetaQuotes Ltd. | //| www.mql5.com | //+------------------------------------------------------------------+ #ifndef REQUEST_LATENCY_LAB_LATENCY_PANEL_MQH #define REQUEST_LATENCY_LAB_LATENCY_PANEL_MQH #include "..\..\Include\RequestLatencyLab\Models.mqh" #define LAB_PANEL_PREFIX "RLL_Panel_" class CLatencyPanel { private: long m_chart_id; bool m_created; bool m_started; // R13-S1: НАМЕРЕННОЕ состояние кнопки (проекция из контроллера) string m_status; public: CLatencyPanel(void); void Create(const long chart_id); void Destroy(void); bool IsCreated() const { return(m_created); } bool IsStartPressed() const; void SetStatus(const string status) { m_status = status; } //--- R10-B1: состояние кнопки управляется ТОЛЬКО latch команды Start. //--- Кнопка остаётся нажатой/заблокированной, пока явно не вызван //--- SetStarted(false) (после финализации прогона). void SetStarted(const bool started); //--- R13-S1: OBJ_BUTTON при клике САМ переключает OBJPROP_STATE //--- (официальная семантика MQL5). После ОТКЛОНЁННОГО клика (повторный //--- клик занятой кнопки) графический вид восстановливается из //--- намеренного состояния, а не из того, что осталось в объекте. void RestoreStartedState(void); void Update(const bool running); }; //+------------------------------------------------------------------+ //| Внешние определения методов. | //+------------------------------------------------------------------+ CLatencyPanel::CLatencyPanel(void) { m_chart_id = 0; m_created = false; m_started = false; m_status = "IDLE"; } void CLatencyPanel::Create(const long chart_id) { m_chart_id = chart_id; if(m_created) return; //--- только объекты, принадлежащие программе ObjectCreate(m_chart_id, LAB_PANEL_PREFIX + "Bg", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Bg", OBJPROP_XDISTANCE, 10); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Bg", OBJPROP_YDISTANCE, 20); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Bg", OBJPROP_XSIZE, 320); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Bg", OBJPROP_YSIZE, 110); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Bg", OBJPROP_BGCOLOR, clrDarkSlateGray); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Bg", OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Bg", OBJPROP_BACK, false); ObjectCreate(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_XDISTANCE, 20); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_YDISTANCE, 30); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_XSIZE, 120); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_YSIZE, 30); ObjectSetString(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_TEXT, "Start"); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_BGCOLOR, clrForestGreen); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_HIDDEN, false); ObjectCreate(m_chart_id, LAB_PANEL_PREFIX + "StatusLabel", OBJ_LABEL, 0, 0, 0); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "StatusLabel", OBJPROP_XDISTANCE, 20); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "StatusLabel", OBJPROP_YDISTANCE, 75); ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "StatusLabel", OBJPROP_COLOR, clrWhite); ObjectSetString(m_chart_id, LAB_PANEL_PREFIX + "StatusLabel", OBJPROP_TEXT, "Status: IDLE"); m_created = true; ChartRedraw(m_chart_id); } void CLatencyPanel::Destroy(void) { if(!m_created) return; //--- удаляем только объекты с нашим префиксом for(int i = ObjectsTotal(m_chart_id, 0, -1) - 1; i >= 0; i--) { const string name = ObjectName(m_chart_id, i, 0, -1); if(StringFind(name, LAB_PANEL_PREFIX) == 0) ObjectDelete(m_chart_id, name); } m_created = false; } bool CLatencyPanel::IsStartPressed() const { if(!m_created) return(false); return(ObjectGetInteger(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_STATE) != 0); } void CLatencyPanel::SetStarted(const bool started) { m_started = started; // R13-S1: храним намеренное состояние if(!m_created) return; ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_STATE, (started ? 1 : 0)); ObjectSetString(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_TEXT, (started ? "Run…" : "Start")); } void CLatencyPanel::RestoreStartedState(void) { if(!m_created) return; ObjectSetInteger(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_STATE, (m_started ? 1 : 0)); ObjectSetString(m_chart_id, LAB_PANEL_PREFIX + "Start", OBJPROP_TEXT, (m_started ? "Run…" : "Start")); } void CLatencyPanel::Update(const bool running) { if(!m_created) return; ObjectSetString(m_chart_id, LAB_PANEL_PREFIX + "StatusLabel", OBJPROP_TEXT, "Status: " + m_status); //--- во время измерений панель не перерисовывается if(!running) ChartRedraw(m_chart_id); } #endif // REQUEST_LATENCY_LAB_LATENCY_PANEL_MQH //+------------------------------------------------------------------+