//+---------------------------------------------------------------------------+
//|                                                  SimpleChartNavigator.mq4 |
//|                                                   Kilian19 @ ForexFactory |
//|                                                                           |
//| Copyright (c) 2015                                                        |
//|                                                                           |
//| Permission to use, copy, modify, and/or distribute this software for any  |
//| purpose with or without fee is hereby granted, provided that the above    |
//| copyright notice and this permission notice appear in all copies.         |
//|                                                                           |
//| THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES  |
//| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF          |
//| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR   |
//| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    |
//| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN     |
//| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF   |
//| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.            |
//|                                                                           |
//+---------------------------------------------------------------------------+

/*
   Time zone calculation could be implemented as well to easily navigate to a time stated in annother time zone. Usefull for news trading?. 
   I could have used more functions to organize the code a bit more but I think it's okay the way it is.
*/

#property copyright "Kilian19 @ ForexFactory"
#property link      "kilian19f@gmail.com"
#property version   "1.00"
#property strict
#property description "Легкий виджет,чтобы быстро прыгнуть к определенной дате. * Русифицировал поручик 25.05.15 *."

#property indicator_chart_window

#include <Controls/Dialog.mqh>
#include <Controls/DatePicker.mqh>
#include <Controls/Button.mqh>
#include <Controls/Edit.mqh>
#include <Controls/ComboBox.mqh>

//--- input parameters 
input bool autoDisableAutoScrolling = true;  //Disable Autoscrolling After Jump
input bool markJumpWithTrendline = true;     // Draw Trendline At Destination
input color trendlineColor = Red;            //Trendline Color
input int   tWidth = 1;                      //Trendline Width


// Alignment
/*
   You should be pretty safe to play around with these values just be aware to increase the panel width and height accordingly. 
   If the alignement breaks take a look at the onCreate function of the class.
*/
#define MARGIN_LEFT        (11)
#define MARGIN_TOP         (11)
#define SPACING            (10) 
   
#define BUTTON_WIDTH       (100)    
#define BUTTON_HEIGHT      (20)     
#define DATE_HEIGHT        (20)      
#define DATE_WIDTH         (150)     

#define PANEL_WIDTH        (180)
#define PANEL_HEIGHT       (170)

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {

   //Spawn the pannel in the upper right corner.  
   int chartWidth = (int)ChartGetInteger(ChartID(),CHART_WIDTH_IN_PIXELS,0);
   int x = chartWidth - PANEL_WIDTH;
   
   pan.Create(ChartID(),"Навигатор графиков",0,x,0,x+PANEL_WIDTH,PANEL_HEIGHT);
   pan.Caption("Навигатор графиков");
   pan.Run();
   
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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 value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
      //Not many functions are used but for the sake of it we keep it like this with event mapping.
      pan.ChartEvent(id,lparam,dparam,sparam);
   
  }
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   //Don't delete our jump mark if we change the tf or symbol
   if(reason != 3)
   {
      string objName = "jumpMark";
      if(ObjectFind(ChartID(),objName) >= 0)
      {
         ObjectDelete(ChartID(),objName);
      }
   }
   pan.Destroy(reason);        
}


class Panel : public CAppDialog
  {
private:
   //controls  
   CComboBox           mSymbol;
   CComboBox           mPeriod;
   CEdit               mTimeMin;
   CEdit               mTimeHour;
   CButton             mButton;
   CDatePicker         mDate;      

   /* Gets called after panel sucessfully initalised.
    * If we changed timeframe or symbol through this indicator we cand not perform the chart shift before deinitialization. */
   void postCreation(){  
      
      string vName = "Прыжок_"+Symbol()+"_"+Period();
      
      if(GlobalVariableCheck(vName))
      {
         datetime destination = GlobalVariableGet(vName);
         navigate(destination);
         //Delete the variable
         GlobalVariableDel(vName);        
         //We should set the hour and minute values to the last jump time
         setControls(destination);
      }
   }
   
   //Set the hours and numbers edit box to the specified datetime
   void setControls(datetime d){
      MqlDateTime time;
      TimeToStruct(d,time);
      mTimeMin.Text(time.min);
      mTimeHour.Text(time.hour);
      mDate.Value(d);
   }
   
   //Navigate to the specified datetime on the chart
   void navigate(datetime to)
   {
      int barsShift = iBarShift(NULL,0,to);
      //Naviagate to the predefined place.
      
      int barsInWindow = (int)ChartGetInteger(ChartID(),CHART_WIDTH_IN_BARS);
      int finalShift = (barsShift-barsInWindow/2);
      ChartNavigate(ChartID(),CHART_END,-finalShift);
   }
   
   
   
public:
                     Panel(void){};
                    ~Panel(void){};
            
   //Event handling
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //Just for the event mapping macro
   
   //Gets called when jump is pressed
   void  OnClickButton(void){
           
      //compose the date time of the 2 edit boxes and the date picker
      CDateTime dateTime;
      dateTime.Date(mDate.Value()); //date easy step000
              
      //Parse the tex box
      string minutes = StringTrimLeft(StringTrimRight(mTimeMin.Text()));
      string hours = StringTrimLeft(StringTrimRight(mTimeHour.Text()));
      dateTime.Min((int)StringToInteger(minutes)); //Will be 0 if parse error happens which will guarantee it to work even by wrong input
      dateTime.Hour((int)StringToInteger(hours));
    
      //It makes no sense to navigate if autoscroll is enabled
      ChartSetInteger(ChartID(),CHART_AUTOSCROLL,!autoDisableAutoScrolling);
      
      //Create a trendline which marks the spot we want to jump to.
      createJumpMark(dateTime.DateTime());
                
      //Get the desired chart and period
      string symbol = mSymbol.Select();
      int tf = (int)(mPeriod.Value());
       
      //If symbol or tf is changed EA will be initialized again.
      if(Symbol() != symbol || tf != Period())
      {
         //Prepare deinitialisation.
         string vName = "Прыжок_"+symbol+"_"+tf;
         GlobalVariableTemp(vName);
         GlobalVariableSet(vName,dateTime.DateTime());
         
         ChartSetSymbolPeriod(ChartID(),symbol,tf);
      }  
      
      //If we don't change tf or symbol we can simply navigate to the specified time.
      navigate(dateTime.DateTime());         
   };

   
   //Creation nothign special here. Just really ugly
   virtual bool   Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
   {
      //create parent
      if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
         return false;
         
      //Create controls
      
      //Sym picker
      int x = MARGIN_LEFT;
      int y = MARGIN_TOP;
      int toX =(int) (x + DATE_WIDTH/1.7);
      int toY = y +DATE_HEIGHT;
      
      //needs to be implemented the last so it's drawn on top of everyhing
            
      //Period picker
      if(!mPeriod.Create(chart,"PeriodPicker",subwin,toX + 5,y,(int)(toX+ + DATE_WIDTH/2.3),toY))
         return false;
         
      //no library functions for public release
      mPeriod.AddItem("M1",1);
      mPeriod.AddItem("M5",5);
      mPeriod.AddItem("M15",15);
      mPeriod.AddItem("M30",30);
      mPeriod.AddItem("H1",60);
      mPeriod.AddItem("H4",240);
      mPeriod.AddItem("D1",1440);
      mPeriod.AddItem("W1",10080);      
      mPeriod.AddItem("MN",43200);

      mPeriod.SelectByValue(Period());

      if(!Add(mPeriod))
         return false;  
         
      //Date picker
      
      //cache values for correct implementation order
      y  = toY + SPACING;
      toX = x + DATE_WIDTH;
      toY = y + DATE_HEIGHT;
      
      int xDate = x;
      int yDate = y;
      int x1Date = toX;
      int y1Date = toY;
      
       //Time picker
      y  = toY + SPACING;
      toX = x + DATE_WIDTH/2;
      toY = y + DATE_HEIGHT;
      
      if(!mTimeHour.Create(chart,"TimeHour",subwin,x,y,toX,toY))
         return false;
         
       if(!Add(mTimeHour))
         return false;
                
      mTimeHour.TextAlign(ALIGN_CENTER);
      mTimeHour.Text("HH");
      

      if(!mTimeMin.Create(chart,"TimeMin",subwin,toX + 5 ,y,toX + DATE_WIDTH/2 ,toY))
         return false;
         
       if(!Add(mTimeMin))
         return false;
                
      mTimeMin.TextAlign(ALIGN_CENTER);
      mTimeMin.Text("MM");
         
       //Button 
      x = (int)(x*4);
      y  = toY+ SPACING; 
      toX = x + BUTTON_WIDTH;
      toY = y + BUTTON_HEIGHT;
      
      if(!mButton.Create(chart,"Button",subwin,x,y,toX,toY))
         return false;
         
       if(!Add(mButton))
         return false;
       mButton.Text("Прыжок");
       
      //Finally create the datepicker 
       
      if(!mDate.Create(chart,"DatePicker",subwin,xDate,yDate,x1Date,y1Date))
         return false;
         
      if(!Add(mDate))
         return false;  

      mDate.Value(TimeCurrent());
       
      if(!mSymbol.Create(chart,"SymbolPicker",subwin,MARGIN_LEFT,MARGIN_TOP,(int) (MARGIN_LEFT + DATE_WIDTH/1.7),MARGIN_TOP + DATE_HEIGHT))
         return false;
         
      if(!Add(mSymbol))
         return false;  
      
      //Populate symbol list
      int numSymbols = SymbolsTotal(true);
      for(int i= 0; i < numSymbols; i++)
         mSymbol.AddItem(SymbolName(i,true),i);
       
       //Select the current symbol in the list so that if we want to only use the time jump feature we do not have to worry about selecting the correct window.
       mSymbol.SelectByText(Symbol());
       
       postCreation();
       return true;
   }
};

//Mapping macro
   EVENT_MAP_BEGIN(Panel)
      ON_EVENT(ON_CLICK,mButton,OnClickButton)
   EVENT_MAP_END(CAppDialog)

Panel pan;
   
void createJumpMark(datetime d){

   if(markJumpWithTrendline){

      string objName = "jumpMark";
      
      if(ObjectFind(ChartID(),objName) < 0){
         ObjectCreate(ChartID(),objName,OBJ_VLINE,0,d,0);
         ObjectSet(objName,OBJPROP_COLOR,trendlineColor);
         ObjectSet(objName,OBJPROP_WIDTH,tWidth);
      }   
      else
         ObjectSetInteger(ChartID(),objName,OBJPROP_TIME1,d);
   }   
}