//+------------------------------------------------------------------+
//|                                           PanelInformacyjny.mq5  |
//|  Panel na wykresie: etykiety, przycisk i obsługa kliknięcia.     |
//|  Niczym nie handluje — pokazuje wyłącznie dane instrumentu.      |
//|  https://finanseodczarowane.pl/mql5/kurs/07-panel-na-wykresie/    |
//|  Licencja MIT                                                    |
//+------------------------------------------------------------------+
#property copyright "finanseodczarowane.pl/kod"
#property version   "1.00"

//--- wspólny przedrostek pozwala usunąć wszystkie obiekty jednym wywołaniem
#define PRZEDROSTEK "panel_"

input int OdstepX = 12;             // odległość od krawędzi w pikselach
input int OdstepY = 24;
input color KolorTekstu = clrWhite;

bool szczegoly = false;             // czy pokazujemy dodatkowe wiersze

//+------------------------------------------------------------------+
//| Tworzy etykietę tekstową w rogu wykresu.                         |
//+------------------------------------------------------------------+
bool UtworzEtykiete(const string nazwa, const int x, const int y,
                    const int rozmiar = 9)
  {
   string pelna = PRZEDROSTEK + nazwa;

   if(ObjectFind(0, pelna) < 0)
      if(!ObjectCreate(0, pelna, OBJ_LABEL, 0, 0, 0))
        {
         PrintFormat("Nie udało się utworzyć %s, błąd %d", pelna, GetLastError());
         return false;
        }

   ObjectSetInteger(0, pelna, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, pelna, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, pelna, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(0, pelna, OBJPROP_COLOR, KolorTekstu);
   ObjectSetInteger(0, pelna, OBJPROP_FONTSIZE, rozmiar);
   ObjectSetInteger(0, pelna, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, pelna, OBJPROP_HIDDEN, true);
   ObjectSetString(0, pelna, OBJPROP_FONT, "Consolas");
   return true;
  }

//+------------------------------------------------------------------+
bool UtworzPrzycisk(const string nazwa, const int x, const int y,
                    const int szerokosc, const int wysokosc, const string napis)
  {
   string pelna = PRZEDROSTEK + nazwa;

   if(ObjectFind(0, pelna) < 0)
      if(!ObjectCreate(0, pelna, OBJ_BUTTON, 0, 0, 0))
         return false;

   ObjectSetInteger(0, pelna, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, pelna, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, pelna, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(0, pelna, OBJPROP_XSIZE, szerokosc);
   ObjectSetInteger(0, pelna, OBJPROP_YSIZE, wysokosc);
   ObjectSetInteger(0, pelna, OBJPROP_BGCOLOR, clrDimGray);
   ObjectSetInteger(0, pelna, OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(0, pelna, OBJPROP_BORDER_COLOR, clrSilver);
   ObjectSetInteger(0, pelna, OBJPROP_STATE, false);
   ObjectSetString(0, pelna, OBJPROP_TEXT, napis);
   return true;
  }

//+------------------------------------------------------------------+
void UstawTekst(const string nazwa, const string tekst)
  {
   ObjectSetString(0, PRZEDROSTEK + nazwa, OBJPROP_TEXT, tekst);
  }

//+------------------------------------------------------------------+
void Odswiez(void)
  {
   MqlTick tick;
   if(!SymbolInfoTick(_Symbol, tick))
      return;

   double punkt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int spread = (punkt > 0.0) ? (int)MathRound((tick.ask - tick.bid) / punkt) : 0;

   UstawTekst("naglowek", StringFormat("%s  %s", _Symbol,
                                       EnumToString((ENUM_TIMEFRAMES)_Period)));
   UstawTekst("ceny", StringFormat("bid %.*f   ask %.*f",
                                   _Digits, tick.bid, _Digits, tick.ask));
   UstawTekst("spread", StringFormat("spread %d pkt", spread));

   if(szczegoly)
     {
      double dzienMax = iHigh(_Symbol, PERIOD_D1, 0);
      double dzienMin = iLow(_Symbol, PERIOD_D1, 0);
      int zakres = (punkt > 0.0) ? (int)MathRound((dzienMax - dzienMin) / punkt) : 0;

      UstawTekst("zakres", StringFormat("zakres dnia %d pkt", zakres));
      UstawTekst("wolumen", StringFormat("min lot %.2f   krok %.2f",
                            SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN),
                            SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP)));
     }
   else
     {
      UstawTekst("zakres", "");
      UstawTekst("wolumen", "");
     }

   ChartRedraw(0);                  // bez tego zmiany będą widoczne z opóźnieniem
  }

//+------------------------------------------------------------------+
int OnInit()
  {
   int y = OdstepY;

   UtworzEtykiete("naglowek", OdstepX, y, 11);   y += 20;
   UtworzEtykiete("ceny",     OdstepX, y);       y += 16;
   UtworzEtykiete("spread",   OdstepX, y);       y += 16;
   UtworzEtykiete("zakres",   OdstepX, y);       y += 16;
   UtworzEtykiete("wolumen",  OdstepX, y);       y += 22;

   UtworzPrzycisk("przelacz", OdstepX, y, 120, 22, "Szczegóły");

   Odswiez();
   EventSetTimer(1);                // odświeżanie także gdy rynek stoi
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
void OnDeinit(const int powod)
  {
   EventKillTimer();
   //--- sprzątamy po sobie: bez tego obiekty zostają na wykresie
   ObjectsDeleteAll(0, PRZEDROSTEK);
   ChartRedraw(0);
  }

//+------------------------------------------------------------------+
void OnTick()
  {
   Odswiez();
  }

//+------------------------------------------------------------------+
void OnTimer()
  {
   Odswiez();
  }

//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam,
                  const double &dparam, const string &sparam)
  {
   if(id != CHARTEVENT_OBJECT_CLICK)
      return;

   if(sparam != PRZEDROSTEK + "przelacz")
      return;

   szczegoly = !szczegoly;

   //--- przycisk zostaje wciśnięty, dopóki sami go nie zwolnimy
   ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
   ObjectSetString(0, sparam, OBJPROP_TEXT, szczegoly ? "Mniej" : "Szczegóły");

   Odswiez();
  }
