| //+------------------------------------------------------------------+
|
| //| 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
|
| //+------------------------------------------------------------------+
|