//+------------------------------------------------------------------+
//|                                                    Spaceline.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window

#include <Controls\Button.mqh>
CButton TLButton;
  
enum ENUM_PRICE
  {
   ManualInput,    // Input Price Manually
   D0Open,         // Today Open Price
   D1Open,         // Yesterday Open Price
  };

input string UniqueID = "Space1";
input ENUM_PRICE WhichPrice = ManualInput;
input double  StartPrice = 0;
input int     NumLines   = 9;
input int     Spacing    = 25;
input string  AboveBelow = "AB";
input color   LineColor  = Gray;
input color   BaseLineColor = clrLime;
input int     LineWidth  = 1;
input int     LineStyle  = 0;
input string  TimeFrames = "M1, M5, M15, M30, H1, H4, D1, W1, MN";



input string buttonConfig = "---------Button Config ---";
input int ButtonX = 25;
input int ButtonY = 25;
input int ButtonWidth = 100;
input int ButtonHeight = 25;


input string  Button_text        = "Lines"; 


double timeX = 0;
string TFs = TimeFrames;
string abovebelow = AboveBelow;


//+----------------------------------------------+
// Button related variables
//+----------------------------------------------+

bool OnStatus=false;
bool TL_Ind=false;
string GV_Prefix_String = "Lines_OnOFF_Status_";




//+------------------------------------------------------------------+
int OnInit()
  {
      
 
  if(Period()==1   )timeX=60;if(Period()==5    )timeX=300;if(Period()==15   )timeX=900;
  if(Period()==30  )timeX=1800;if(Period()==60   )timeX=3600;if(Period()==240  )timeX=14400;
  if(Period()==1440)timeX=86400;if(Period()==10080)timeX=604800;if(Period()==43200)timeX=2592000;


   ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
   int x1 = ButtonX;
   int y1 = ButtonY;
   int x2 = x1+ButtonWidth;  //button width
   int y2 = y1+ButtonHeight;   //button height

   TLButton.Create(0,Button_text,0,x1,y1,x2,y2);//Create TLButton
   TLButton.Text(Button_text);                         //Label
   
   
   
   //check OnStatus
   OnStatus = Get_GV_OnOffStatus();
   
   if (OnStatus == true )
    {
      TL_Ind = true;
      TLButton.Text(Button_text + " On");      
    }  
   else
    {
      TL_Ind = false;
      TLButton.Text(Button_text + " Off");      
    }
    
     
            
      
     switch(TL_Ind)
     {
         case(true):
         
           plot_obj();
 
         
         break;
         
         case(false):
                
            del_obj();
         
            break;
     }
    
  return(0);
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
  
//+------------------------------------------------------------------+
  del_obj();
 
  return ;
}

    //+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---Observes cursor position, Highlight button and detect Click event



   if(TLButton.Contains((int) lparam, (int)  dparam))
      TLButton.Pressed(true);   //Dtect cursor on the button
   else
      TLButton.Pressed(false);
     
    //button clicked
    
    if(id == CHARTEVENT_OBJECT_CLICK && sparam == Button_text)
     {
      //on/off  
      if( OnStatus==false)       
      {
          OnStatus=true;
          TL_Ind = true;
          TLButton.Text(Button_text + " On");  
          
          
      }
      else
      {     
            TL_Ind = false;
            OnStatus=false;
           TLButton.Text(Button_text + " Off");
           
      }

      
      GV_StoreOnOffStatus();
      
            
    

      switch(TL_Ind)
        {
           
         case(true):
         
           plot_obj();
 
         
         break;
         
         case(false):
                
            del_obj();
         
            break;
       
       
        }
    
     }
     
     
     
     //chart resized
     if( id == CHARTEVENT_CHART_CHANGE && TL_Ind == true)
     {
     
          del_obj();
          plot_obj();
      }
     
     
     
 
     
     ChartRedraw(0);
     

}



//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
  return(0);
}


//+------------------------------------------------------------------+
int MathSign(double n)
//+------------------------------------------------------------------+
// Returns the sign of a number (i.e. -1, 0, +1)
// Usage:   int x=MathSign(-25)   returns x=-1
{
  if (n > 0) return(1);
  else if (n < 0) return (-1);
  else return(0);
}  

//+------------------------------------------------------------------+
double MathFix(double n, int d)
//+------------------------------------------------------------------+
// Returns N rounded to D decimals - works around a precision bug in MQL4
{
  return(MathRound(n*MathPow(10,d)+0.000000000001*MathSign(n))/MathPow(10,d));
}  


//+------------------------------------------------------------------+
void plot_obj()  {
//+------------------------------------------------------------------+

  int x,y;
  
  TFs = StringUpper(TFs) + ",";
  
  int tf = 0;
  if (StringFind(TFs,"M1,")  >= 0)    tf += 1;
  if (StringFind(TFs,"M5,")  >= 0)    tf += 2;
  if (StringFind(TFs,"M15,") >= 0)    tf += 4;
  if (StringFind(TFs,"M30,") >= 0)    tf += 8;
  if (StringFind(TFs,"H1,")  >= 0)    tf += 16;
  if (StringFind(TFs,"H4,")  >= 0)    tf += 32;
  if (StringFind(TFs,"D1,")  >= 0)    tf += 64;
  if (StringFind(TFs,"W1,")  >= 0)    tf += 128;
  if (StringFind(TFs,"MN,")  >= 0)    tf += 256;

  double mult;
  double prc;
  
  if (_Digits >= 4)   {                            // non-JPY pair
     mult = 0.0001;
     prc  = MathFix( iClose(_Symbol,PERIOD_CURRENT,0),2);
  }
  else  {                                         // JPY pair
     mult = 0.01;
     prc  = MathFix(iClose(_Symbol,PERIOD_CURRENT,0),0);
  }   
  if (WhichPrice==ManualInput&&StartPrice > 0)     prc = StartPrice;
  if (WhichPrice==D0Open)    prc = iOpen(_Symbol,PERIOD_D1,0);
  if (WhichPrice==D1Open)    prc = iOpen(_Symbol,PERIOD_D1,1);

  abovebelow = StringUpper(abovebelow);
  int X0 = 0, X1 = 0;
  if (abovebelow == "A")    {  X0 = 0;            X1 = NumLines-1;  }     else
  if (abovebelow == "B")    {  X0 = -NumLines+1;  X1 = 0;           }     else
  if (abovebelow == "AB")   {  X0 = -NumLines+1;  X1 = NumLines-1;  }  
    
  for (int i=X0; i<=X1; i++)   
  {
    color HLineColor = LineColor;
    if ( i == 0) HLineColor = BaseLineColor;
    
    string objname = UniqueID + "Lspc-"+ IntegerToString(i);
    ObjectCreate(0,objname,OBJ_HLINE,0,0,prc+Spacing*mult*i);
    ObjectSetInteger(0,objname,OBJPROP_COLOR,HLineColor);
    ObjectSetInteger(0,objname,OBJPROP_WIDTH,LineWidth);
    ObjectSetInteger(0,objname,OBJPROP_STYLE,LineStyle);
    ObjectSetInteger(0,objname,OBJPROP_TIMEFRAMES,tf);
    
    ChartTimePriceToXY(0, 0, iTime(Symbol(),PERIOD_CURRENT,0) + timeX*3,prc+Spacing*mult*i, x, y);
    string Position = "";
    if ( i < 0 ) Position = "Dn";
    if ( i > 0 ) Position = "Up";
    
   
    DrawLabel( UniqueID + "Linelabel" + IntegerToString(i),x,y, Position +" " + IntegerToString(i) + " (" + DoubleToString(prc+Spacing*mult*i,_Digits) + ")" ,8,"Arial Rounded MT Bold",HLineColor);
   
   
  }
  return;
}

  
void del_obj()
{
   string lookFor       = UniqueID;
   int    lookForLength = StringLen(lookFor);
   for (int i=ObjectsTotal(0)-1; i>=0; i--)
   {
      string objectName = ObjectName(0,i);
         if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(0,objectName);
   }
}



//+------------------------------------------------------------------+
string StringUpper(string str)
//+------------------------------------------------------------------+
// Converts any lowercase characters in a string to uppercase
// Usage:    string x=StringUpper("The Quick Brown Fox")  returns x = "THE QUICK BROWN FOX"
{
  string outstr = "";
  string lower  = "abcdefghijklmnopqrstuvwxyz";
  string upper  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  for(int i=0; i<StringLen(str); i++)  {
    int t1 = StringFind(lower,StringSubstr(str,i,1),0);
    if (t1 >=0)  
      outstr = outstr + StringSubstr(upper,t1,1);
    else
      outstr = outstr + StringSubstr(str,i,1);
  }
  return(outstr);
} 

   
void DrawLabel(string name,int x,int y,string label,int size=9,string font="Arial",color clr=DimGray,string tooltip="")
  {
 
    
   long chart_ID = ChartID();
   
 
   if(ObjectFind(0,name) > 0 ) ObjectDelete(chart_ID,name);
   
   ObjectCreate(chart_ID,name,OBJ_LABEL,0,0,0);
   ObjectSetString(chart_ID,name,OBJPROP_TEXT,label); 
   ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,size); 
   ObjectSetString(chart_ID,name,OBJPROP_FONT,font); 
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); 
   ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,0); 
   ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x); 
   ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y); 
   ObjectSetString(0,name,OBJPROP_TOOLTIP,tooltip);
   
   
//--- justify text
//ObjectSet(name, OBJPROP_ANCHOR, 0);
//ObjectSetString(0, name, OBJPROP_TOOLTIP, tooltip);
//ObjectSet(name, OBJPROP_SELECTABLE, 0);
//---
  }
  

//+------------------------------------------------------------------+
//        Global Variables
//+------------------------------------------------------------------+

bool Get_GV_OnOffStatus()
{

    string gv = "";
    bool OnOffStatus = false;

   
    
   gv =  GV_Prefix_String + Symbol();
   if(GlobalVariableCheck(gv))
   OnOffStatus =  (bool) GlobalVariableGet(gv);
      
   
  return OnOffStatus;


}

void GV_StoreOnOffStatus()
  {

   string gv = "";

   bool OnOffStatus = false;

   
    
   gv =  GV_Prefix_String + Symbol();
   OnOffStatus = OnStatus;
  
   GlobalVariableSet(gv,OnOffStatus);


  }
  
void GV_DeleteOnOffStatus()
  {

//will have only 3 variable for any round

   string gv = "";

   
   gv =  GV_Prefix_String + Symbol();
   GlobalVariableDel(gv);

  



  }

