session-levels/mql4/Indicators/SessionLevels/ObjSync.mqh
76 lines
3 KiB
MQL5
//+------------------------------------------------------------------+
//| ObjSync.mqh |
//| Copyright 2026, Allan Niñal |
//| https://www.allanninal.dev/mql5 |
//+------------------------------------------------------------------+
//| Chart objects that survive a redraw. A product that redraws on |
//| every new bar used to delete all its objects and create them |
//| again; here each object is created once, its points and |
//| properties are changed only when they differ, and only the |
//| objects the pass did not ask for are deleted: |
//| OsBegin(); ... OsRect / OsTrend / OsText / OsLabel ... |
//| OsEnd(prefix); |
//| An object is marked "used in this pass" in its z-order property |
//| (a pass number; the objects are not selectable). Works the same |
//| in MQL5 and MQL4. |
//+------------------------------------------------------------------+
// SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0 (see LICENSE)
#ifndef OBJSYNC_MQH
#define OBJSYNC_MQH
int g_os_gen=0;
void OsBegin(void)
{
g_os_gen=(g_os_gen>=2000000000 ? 1 : g_os_gen+1);
}
void OsInt(const string name,const ENUM_OBJECT_PROPERTY_INTEGER prop,const long v)
{
if(ObjectGetInteger(0,name,prop)!=v)
ObjectSetInteger(0,name,prop,v);
}
void OsStr(const string name,const ENUM_OBJECT_PROPERTY_STRING prop,const string v)
{
if(ObjectGetString(0,name,prop)!=v)
ObjectSetString(0,name,prop,v);
}
//--- the object `name`: created once, moved only when a point differs, marked as used in this pass.
//--- npts is 1 or 2. Returns false when the chart refuses the object.
bool OsPlace(const string name,const ENUM_OBJECT type,const int npts,const datetime t1,const double p1,
const datetime t2,const double p2)
{
if(ObjectFind(0,name)<0)
{
bool ok=(npts==1 ? ObjectCreate(0,name,type,0,t1,p1) : ObjectCreate(0,name,type,0,t1,p1,t2,p2));
if(!ok)
return(false);
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
}
else
{
if(ObjectGetInteger(0,name,OBJPROP_TIME,0)!=(long)t1 || ObjectGetDouble(0,name,OBJPROP_PRICE,0)!=p1)
ObjectMove(0,name,0,t1,p1);
if(npts>1 && (ObjectGetInteger(0,name,OBJPROP_TIME,1)!=(long)t2 || ObjectGetDouble(0,name,OBJPROP_PRICE,1)!=p2))
ObjectMove(0,name,1,t2,p2);
}
ObjectSetInteger(0,name,OBJPROP_ZORDER,g_os_gen);
return(true);
}
//--- delete every object with `prefix` that this pass did not ask for
void OsEnd(const string prefix)
{
for(int i=ObjectsTotal(0,-1,-1)-1; i>=0; i--)
{
string nm=ObjectName(0,i);
if(StringFind(nm,prefix)==0 && ObjectGetInteger(0,nm,OBJPROP_ZORDER)!=g_os_gen)
ObjectDelete(0,nm);
}
}
#endif
//+------------------------------------------------------------------+