231 lines
7.1 KiB
MQL5
231 lines
7.1 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| Screen.mqh |
| |
//| Copyright 2025, MetaQuotes Ltd. |
| |
//| https://www.mql5.com |
| |
//+------------------------------------------------------------------+
| |
#property copyright "Copyright 2025, MetaQuotes Ltd."
| |
#property link "https://www.mql5.com"
| |
#property version "1.00"
| |
| |
#include <Collection/DynamicArraylist.mqh>
| |
#include "ZoneObject.mqh"
| |
#include "ScreenListener.mqh"
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
class Screen
| |
{
| |
| |
private:
| |
long m_chart_id;
| |
int m_width, m_height;
| |
| |
long m_zoom;
| |
int m_fontSize;
| |
long m_min_zoom_to_keep_texts;
| |
bool m_min_zoom_reached_already;
| |
| |
datetime m_from_time, m_to_time;
| |
double m_min_price, m_max_price;
| |
| |
CArrayList<ZoneObject*>* objects;
| |
| |
| |
void UpdateViewBounds();
| |
void OnZoomChanged();
| |
void OnViewChanged();
| |
void OnMinZoomReached();
| |
| |
int FindExist(ZoneObject* zoneObject)
| |
{
| |
for(int i = objects.Size() - 1; i >= 0; i--)
| |
{
| |
ZoneObject* z = objects.At(i);
| |
| |
if(z.GetName() == zoneObject.GetName() && z.GetName() == zoneObject.GetName())
| |
{
| |
return i;
| |
}
| |
}
| |
return -1;
| |
| |
}
| |
int GetScaledFontSize(int baseSizePoints) const
| |
{
| |
return (int)MathMax(6.0, baseSizePoints - (m_zoom - 2));
| |
}
| |
| |
public:
| |
Screen(): m_fontSize(12), m_chart_id(ChartID()) { objects = new CArrayList<ZoneObject*>(); UpdateViewBounds(); }
| |
~Screen() {delete objects;}
| |
| |
void SetMinZoomForTexts(long zoomLevel) { m_min_zoom_to_keep_texts = zoomLevel; }
| |
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
| |
void AddLevel(ZoneObject* zoneObject);
| |
| |
void Delete(string name)
| |
{
| |
for(int i = objects.Size() - 1; i >= 0; i--)
| |
{
| |
ZoneObject* z = objects.At(i); // returns pointer
| |
if(z == NULL) continue;
| |
| |
// ✅ Use . for pointers in MQL5
| |
if(z.GetName() == name) // ❌ change to z.GetName()
| |
{
| |
z.Delete();
| |
//Print(z.GetText()); // ✅ also use . here
| |
| |
bool removed = objects.RemoveAt(i);
| |
// Print("RemoveAt(", i, ") returned: ", removed);
| |
}
| |
}
| |
}
| |
| |
| |
void Render();
| |
};
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void Screen::OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
| |
{
| |
if(id == CHARTEVENT_CHART_CHANGE)
| |
{
| |
UpdateViewBounds();
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void Screen::AddLevel(ZoneObject* zoneObject)
| |
{
| |
if(zoneObject == NULL)
| |
return;
| |
if(zoneObject.GetSymbol() != _Symbol)
| |
{
| |
Print("Error Adding Levels");
| |
return;
| |
}
| |
| |
int ind = FindExist(zoneObject);
| |
if(ind < 0)
| |
{
| |
objects.Add(zoneObject);
| |
Render();
| |
return;
| |
}
| |
| |
ZoneObject* z = objects.At(ind);
| |
| |
PointLevel* supply = dynamic_cast<PointLevel*>(z);
| |
TrendLevel* trend = dynamic_cast<TrendLevel*>(zoneObject);
| |
| |
if(supply != NULL && trend != NULL)
| |
{
| |
objects.RemoveAt(ind);
| |
delete z;
| |
objects.AddAt(ind, zoneObject);
| |
Render();
| |
return;
| |
}
| |
| |
| |
z.SetA(zoneObject.GetA());
| |
z.SetB(zoneObject.GetB());
| |
delete zoneObject;
| |
Render();
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void Screen::Render()
| |
{
| |
UpdateViewBounds();
| |
bool boundsValid = (m_from_time < m_to_time && m_min_price < m_max_price);
| |
| |
for(int i = objects.Size() - 1; i >= 0; i--)
| |
{
| |
objects.At(i).UpdateDraw((int)ChartGetInteger(m_chart_id, CHART_SCALE), m_from_time, m_to_time, m_min_price, m_max_price, (int)m_min_zoom_to_keep_texts);
| |
}
| |
}
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void Screen::OnZoomChanged()
| |
{
| |
if(!m_min_zoom_reached_already)
| |
{
| |
for(int i = objects.Size() - 1; i >= 0; i--)
| |
{
| |
objects.At(i).SetFontSize(GetScaledFontSize(m_fontSize));
| |
}
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void Screen::OnViewChanged()
| |
{
| |
Render();
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void Screen::OnMinZoomReached()
| |
{
| |
for(int i = objects.Size() - 1; i >= 0; i--)
| |
{
| |
objects.At(i).DeleteAllText();
| |
}
| |
}
| |
//+------------------------------------------------------------------+
| |
//| View bounds update |
| |
//+------------------------------------------------------------------+
| |
void Screen::UpdateViewBounds()
| |
{
| |
long old_zoom = m_zoom;
| |
datetime old_from = m_from_time;
| |
datetime old_to = m_to_time;
| |
double old_minp = m_min_price;
| |
double old_maxp = m_max_price;
| |
| |
m_width = (int)ChartGetInteger(m_chart_id, CHART_WIDTH_IN_PIXELS);
| |
m_height = (int)ChartGetInteger(m_chart_id, CHART_HEIGHT_IN_PIXELS);
| |
m_zoom = ChartGetInteger(m_chart_id, CHART_SCALE);
| |
| |
int sub_window = 0;
| |
ChartXYToTimePrice(m_chart_id, 0, 0, sub_window, m_from_time, m_max_price);
| |
ChartXYToTimePrice(m_chart_id, m_width, m_height, sub_window, m_to_time, m_min_price);
| |
| |
if(m_zoom != old_zoom)
| |
{
| |
OnZoomChanged();
| |
bool below_threshold = (m_zoom < m_min_zoom_to_keep_texts);
| |
| |
if(below_threshold && !m_min_zoom_reached_already)
| |
{
| |
OnMinZoomReached();
| |
m_min_zoom_reached_already = true;
| |
| |
}
| |
else
| |
if(!below_threshold)
| |
{
| |
m_min_zoom_reached_already = false;
| |
// Render();
| |
}
| |
}
| |
| |
if(m_from_time != old_from || m_to_time != old_to ||
| |
m_min_price != old_minp || m_max_price != old_maxp)
| |
{
| |
OnViewChanged();
| |
}
| |
| |
}
| |
//+------------------------------------------------------------------+
|