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();
| |||
}
| |||
| |||
}
| |||
//+------------------------------------------------------------------+
|