//+------------------------------------------------------------------+
//|                                                       TETRIS.mq4 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Evgeniy Serov"
#property link       "https://www.mql5.com/ru/users/vorese"
#property version   "1.00"
#property strict
#property indicator_chart_window
input string start_game="Q";//старт
input string pause="A";//пауза
input string left="M";//влево
input string right="L";//вправо
input string rotation="K";//вращение
input string downward="Z";//вниз
input int speed=20;//скорость
                   //=================================================
bool tr_start=false,
tr_stop=false,
tr_speedup=false,
tr_right=false,
tr_left=false,
tr_tick=false,
tr_pause=false,
tr_game=true,
tr_rotation=false;

int objects=0,//кол-во объектов в фигуре
figure=0,//номер фигуры
number_objects=0,// создано объектов 
speed_objects=0,//скорость
index=0,//последний индекс в предыдущей фигуре   
tet=0;//рекорд
int x1,x2,x3,x4,y1,y2,y3,y4;//коорд. объектов в фигуре
int ax1,ax2,ax3,ax4,ay1,ay2,ay3,ay4;//коорд.для проверки возможности вращения
int arr_index[];//индекс объекта
int arr_X[];//коорд.Х
int arr_Y[];//коорд.У

color clr_figure=clrNONE;//цвет фигуры

#define   pixels  2//скорость в пикселях
#define   speedup 10//ускорение 
//===================================================================
int OnInit()
  {
   ChartSetInteger(0,CHART_FOREGROUND,false);

   if(GlobalVariableCheck("tetris"))tet=(int)GlobalVariableGet("tetris");
   else
      GlobalVariableSet("tetris",0);

   RectLabelCreate(0,"tetris_0",0,220,26,220,414,clrRed,BORDER_FLAT,CORNER_RIGHT_UPPER,clrBlue,STYLE_SOLID,4);
   RectLabelCreate(0,"tetris_1",0,214,26,208,408,clrBlack,BORDER_FLAT,CORNER_RIGHT_UPPER,clrBlue,STYLE_SOLID,4);
   LabelCreate(0,"tetris_2",0,203,32,CORNER_RIGHT_UPPER,"high score","Arial",10,clrLawnGreen,0,ANCHOR_LEFT_UPPER);
   LabelCreate(0,"tetris_3",0,58,32,CORNER_RIGHT_UPPER,"score","Arial",10,clrLawnGreen,0,ANCHOR_LEFT_UPPER);
   LabelCreate(0,"tetris_4",0,58,50,CORNER_RIGHT_UPPER,"","Arial",10,clrWhite,0,ANCHOR_LEFT_UPPER);
   LabelCreate(0,"tetris_5",0,202,50,CORNER_RIGHT_UPPER,IntegerToString(tet),"Arial",10,clrWhite,0,ANCHOR_LEFT_UPPER);

   ArrayResize(arr_index,200);
   ArrayResize(arr_X,200);
   ArrayResize(arr_Y,200);
   f_Initial_array();

   ChartRedraw();
   EventSetMillisecondTimer(speed);
   return(INIT_SUCCEEDED);
  }
//===================================================================  
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0,"tetris");
   ObjectsDeleteAll(0,"figure");
//--- destroy timer
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| 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(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(!tr_pause)//пауза
     {
      if(tr_start && !tr_stop)
        {
         figure=f_GetRand(1,10);//номер фигуры 
         f_Initial_coordinates(figure,clr_figure);//начальные координаты
         objects=f_Figure(index,clr_figure);//создать фигуру
         number_objects+=objects;
         tr_start=false;
        }

      if(f_Restriction_down() && f_Stop_Y(index,objects) && objects>0 && !tr_stop)//ограничение вниз
        {
         if(!tr_rotation)
           {
            if(!tr_speedup)//ускоренное перемещение
              {
               speed_objects=pixels;
              }
            else
              {
               if(tr_tick)
                 {
                  tr_tick=false;
                  speed_objects=20-f_Correction();
                 }
               else
                  speed_objects=pixels*speedup;
              }

            f_Changing_coordinates_Y(speed_objects);//изменение координат по оси У
            if(tr_left && f_Stop_X(index,objects,-20))//смещение влево
              {
               f_Changing_coordinates_X(20);
               f_Restriction_left(x1,x2,x3,x4,y1,y2,y3,y4); //ограничение влево
              }
            if(tr_right && f_Stop_X(index,objects,20))//смещение вправо
              {
               f_Changing_coordinates_X(-20);
               f_Restriction_right(x1,x2,x3,x4,y1,y2,y3,y4);//ограничение вправо
              }
            f_Changing_XY(index,x1,x2,x3,x4,y1,y2,y3,y4);//изменение координат
           }

         if(tr_rotation && !tr_left && !tr_right)//вращение фигуры
           {
            f_Rotation_figure(figure);
            f_Restriction_left(ax1,ax2,ax3,ax4,ay1,ay2,ay3,ay4); //ограничение влево при вращении
            f_Restriction_right(ax1,ax2,ax3,ax4,ay1,ay2,ay3,ay4);//ограничение вправo при вращении
            int s=f_Stop_rotation();//запрет на вращение
            if(s>-100)
              {
               f_Changing_XY(index,ax1+s,ax2+s,ax3+s,ax4+s,ay1,ay2,ay3,ay4);
               x1=ax1+s;x2=ax2+s;x3=ax3+s;x4=ax4+s;
               y1=ay1;y2=ay2;y3=ay3;y4=ay4;
              }
            else
              {
               f_Changing_XY(index,x1,x2,x3,x4,y1,y2,y3,y4);
              }
           }
        }
      else
        {
         f_Entry_array(index,objects);//запись индекса объекта в массив
         index=number_objects;
         f_Filling(); //проверка заполнения ряда

         if(objects>0) tr_start=true;
         if(f_Game_stop())tr_stop=true;
         ObjectSetString(0,"tetris_4",OBJPROP_TEXT,IntegerToString(number_objects));
         tr_speedup=false;
        }
      tr_left=false;
      tr_right=false;
      tr_rotation=false;
      ChartRedraw();
     }
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(id==CHARTEVENT_KEYDOWN)
     {
      //------------------------------------начало игры
      if(lparam==StringGetChar(start_game,0) && !tr_pause && tr_game)
        {
         tr_start=true;
         tr_stop=false;
         tr_game=false;
        }
      //--------------------------------------влево  
      if(lparam==StringGetChar(left,0))
        {
         tr_left=true;
        }
      //--------------------------------------вправо  
      if(lparam==StringGetChar(right,0))
        {
         tr_right=true;
        }
      //--------------------------------------вращение   
      if(lparam==StringGetChar(rotation,0))
        {
         tr_rotation=true;
        }
      //--------------------------------------ускоренное перемещение вниз   
      if(lparam==StringGetChar(downward,0))
        {
         tr_speedup=true;
         tr_tick=true;
        }
      //--------------------------------------пауза
      if(lparam==StringGetChar(pause,0) && !tr_pause)
        {
         tr_pause=true;
         LabelCreate(0,"tetris_6",0,203,65,CORNER_RIGHT_UPPER,"PAUSE","Arial",42,clrGold,0,ANCHOR_LEFT_UPPER);
         ChartRedraw();
         return;
        }
      if(lparam==StringGetChar(pause,0) && tr_pause)
        {
         tr_pause=false;
         ObjectDelete(0,"tetris_6");
         ChartRedraw();
         return;
        }
     }
  }
//====================================================================
//==================================================================== вращение
void f_Rotation_figure(int num)
  {
   ax1=x1;ax2=x2;ax3=x3;ax4=x4;
   ay1=y1;ay2=y2;ay3=y3;ay4=y4;
   switch(num)
     {
      case 2: f_Rotation_2(); break;
      case 3: f_Rotation_3(); break;
      case 5: f_Rotation_5(); break;
      case 6: f_Rotation_6(); break;
      case 7: f_Rotation_7(); break;
      case 8: f_Rotation_8(); break;
      case 9: f_Rotation_9(); break;
      case 10: f_Rotation_10(); break;
     }
  }
//==================================================================== коррекция У-коорд. при ускоренном перемещении
int f_Correction()
  {
   return((int)MathMod(f_Y_coord(number_objects)-10,20));
  }
//==================================================================== удалить ряд
void f_Remove_number(int &arr_filling[])
  {
   for(int r=0;r<10;r++)
     {
      ObjectDelete(0,"figure"+IntegerToString(arr_filling[r]));
     }
  }
//==================================================================== смещение объектов вниз после удаления ряда
void f_Offset_Y(int line)
  {
   int arr_duplicate[];
   ArrayResize(arr_duplicate,200);
   ArrayCopy(arr_duplicate,arr_index,0,0,0);

   for(int t=(line+1)*10-1;t>=10;t--)
     {
      int ww=arr_duplicate[t-10];
      arr_index[t]=ww;
      if(ww>0) ObjectSetInteger(0,"figure"+(string)ww,OBJPROP_YDISTANCE,arr_Y[t]);
     }
  }
//==================================================================== проверка заполнения ряда
void f_Filling()
  {
   int k=0;
   int arr_filling[];
   ArrayResize(arr_filling,10);

   for(int v=0;v<20;v++)
     {
      int line_number=0;
      ArrayInitialize(arr_filling,0);
      for(int b=0;b<10;b++)
        {
         arr_filling[b]=arr_index[k];
         k++;
        }
      line_number=arr_filling[ArrayMinimum(arr_filling,WHOLE_ARRAY,0)];
      if(line_number>0)
        {
         f_Remove_number(arr_filling);
         f_Offset_Y(v);
        }
     }
  }
//==================================================================== ограничение вниз
bool f_Stop_Y(int number,int obj_num)
  {
   for(int h=0;h<200;h++)
     {
      if(arr_index[h]>0)
        {
         if(f_Y_coord(number+1)==arr_Y[h]-20 && f_X_coord(number+1)==arr_X[h]) return(false);
         else
            if(obj_num>1 && f_Y_coord(number+2)==arr_Y[h]-20 && f_X_coord(number+2)==arr_X[h]) return(false);
         else
            if(obj_num>2 && f_Y_coord(number+3)==arr_Y[h]-20 && f_X_coord(number+3)==arr_X[h]) return(false);
         else
            if(obj_num>3 && f_Y_coord(number+4)==arr_Y[h]-20 && f_X_coord(number+4)==arr_X[h]) return(false);
        }
     }
   return(true);
  }
//====================================================================ограничение вправо/влево
bool f_Stop_X(int number,int obj_num,int offset_x)
  {
   for(int h=0;h<200;h++)
     {
      if(arr_index[h]>0)
        {
         if(arr_Y[h]-20<=f_Y_coord(number+1) && arr_Y[h]>=f_Y_coord(number+1) && f_X_coord(number+1)==arr_X[h]+offset_x) return(false);
         else
            if(obj_num>1 && arr_Y[h]-20<=f_Y_coord(number+2) && arr_Y[h]>=f_Y_coord(number+2) && f_X_coord(number+2)==arr_X[h]+offset_x) return(false);
         else
            if(obj_num>2 && arr_Y[h]-20<=f_Y_coord(number+3) && arr_Y[h]>=f_Y_coord(number+3) && f_X_coord(number+3)==arr_X[h]+offset_x) return(false);
         else
            if(obj_num>3 && arr_Y[h]-20<=f_Y_coord(number+4) && arr_Y[h]>=f_Y_coord(number+4) && f_X_coord(number+4)==arr_X[h]+offset_x) return(false);
        }
     }
   return(true);
  }
//====================================================================запрет на вращение, проверка возможности смещения
bool f_Stop_rotation_offset(int offset)
  {
   for(int h=0;h<200;h++)
     {
      if(arr_index[h]>0)
        {
         if((arr_Y[h]-20<=ay1 && arr_Y[h]+20>=ay1 && ax1+offset==arr_X[h]) || ax1+offset>210 || ax1+offset<30)return(false);
         else
            if((objects>1 && arr_Y[h]-20<=ay2 && arr_Y[h]+20>=ay2 && ax2+offset==arr_X[h]) || ax2+offset>210 ||(objects>1 && ax2+offset<30))return(false);
         else
            if((objects>2 && arr_Y[h]-20<=ay3 && arr_Y[h]+20>=ay3 && ax3+offset==arr_X[h]) || ax3+offset>210 || (objects>2 && ax3+offset<30))return(false);
         else
            if((objects>3 && arr_Y[h]-20<=ay4 && arr_Y[h]+20>=ay4 && ax4+offset==arr_X[h]) || ax4+offset>210 || (objects>3 && ax4+offset<30))return(false);
        }
     }
   return(true);
  }
//===================================================================== смещение при вращении
int f_Stop_rotation()
  {
   if(f_Stop_rotation_offset(0)) return(0);
   else
      if(f_Stop_rotation_offset(-20)) return(-20);
   else
      if(f_Stop_rotation_offset(20)) return(20);
   else
      return(-100);
  }
//==================================================================== инициализация массивов
void f_Initial_array()
  {
   int k=0;
   for(int v=0;v<20;v++)//Y
     {
      for(int b=0;b<10;b++)//X
        {
         arr_index[k]=0;  //индекс объекта
         arr_Y[k]=30+20*v;//коорд.У
         arr_X[k]=30+20*b;//коорд.Х
         k++;
        }
     }
  }
//==================================================================== запись индекса объекта в массив
void f_Entry_array(int ind,int obj_num)
  {
   int a=0;
   int u=0;
   int k=0;
   for(int v=0;v<20;v++)//Y
     {
      a=30+20*v;
      for(int b=0;b<10;b++)//X
        {
         u=30+20*b;
         if(f_X_coord(ind+1)==u && f_Y_coord(ind+1)==a)
            arr_index[k]=ind+1;

         if(obj_num>1 && f_X_coord(ind+2)==u && f_Y_coord(ind+2)==a)
            arr_index[k]=ind+2;

         if(obj_num>2 && f_X_coord(ind+3)==u && f_Y_coord(ind+3)==a)
            arr_index[k]=ind+3;

         if(obj_num>3 && f_X_coord(ind+4)==u && f_Y_coord(ind+4)==a)
            arr_index[k]=ind+4;
         k++;
        }
     }
  }
//==================================================================== возвращает коорд Х объекта
int f_X_coord(int number)
  {
   return((int) ObjectGetInteger(0,"figure"+(string)(number),OBJPROP_XDISTANCE));
  }
//==================================================================== возвращает коорд У объекта
int f_Y_coord(int number)
  {
   return((int)ObjectGetInteger(0,"figure"+(string)(number),OBJPROP_YDISTANCE));
  }
//==================================================================== ограничение влево в крайнем положении
void f_Restriction_left(int &lx1,int &lx2,int &lx3,int &lx4,int &ly1,int &ly2,int &ly3,int &ly4)
  {
   if(lx1>210 || lx2>210 || lx3>210 || lx4>210)
     {
      if(lx1>0) lx1-=20;
      if(lx2>0) lx2-=20;
      if(lx3>0) lx3-=20;
      if(lx4>0) lx4-=20;
     }
  }
//====================================================================ограничение вправо в крайнем положении
void f_Restriction_right(int &rx1,int &rx2,int &rx3,int &rx4,int &ry1,int &ry2,int &ry3,int &ry4)
  {
   if((rx1!=0 && rx1<30) || (rx2!=0 && rx2<30) || (rx3!=0 && rx3<30) || (rx4!=0 && rx4<30))
     {
      if(rx1>0) rx1+=20;
      if(rx2>0) rx2+=20;
      if(rx3>0) rx3+=20;
      if(rx4>0) rx4+=20;
     }
  }
//==================================================================== ограничение вниз в крайнем положении
bool f_Restriction_down()
  {
   if(y1<410 && y2<410 && y3<410 && y4<410)return(true);
   else
      return(false);
  }
//==================================================================== игра окончена
bool f_Game_stop()
  {
   if(y1==50 || y2==50 || y3==50 || y4==50)
     {
      if(tet<number_objects)GlobalVariableSet("tetris",number_objects);//рекорд
      return(true);
     }
   else
      return(false);
  }
//==================================================================== начальные координаты 
void f_Initial_coordinates(int fig,color &CLR)
  {
   switch(fig)
     {
      case 1: x1=130;x2=0;x3=0;x4=0;y1=30;y2=0;y3=0;y4=0;CLR=clrRed; break;
      case 2: x1=130;x2=130;x3=0;x4=0;y1=30;y2=50;y3=0;y4=0;CLR=clrMediumBlue; break;
      case 3: x1=130;x2=130;x3=110;x4=0;y1=30;y2=50;y3=30;y4=0;CLR=clrDeepPink; break;
      case 4: x1=130;x2=110;x3=130;x4=110;y1=30;y2=30;y3=50;y4=50;CLR=clrOrangeRed; break;
      case 5: x1=130;x2=130;x3=130;x4=130;y1=30;y2=50;y3=70;y4=90;CLR=clrDarkOrange;break;
      case 6: x1=130;x2=110;x3=90;x4=110;y1=30;y2=30;y3=30;y4=50;CLR=clrGreen;break;
      case 7: x1=130;x2=130;x3=110;x4=150;y1=30;y2=50;y3=30;y4=50;CLR=clrDeepSkyBlue;break;
      case 8: x1=130;x2=130;x3=110;x4=150;y1=30;y2=50;y3=50;y4=30;CLR=clrBlueViolet;break;
      case 9: x1=150;x2=130;x3=110;x4=110;y1=30;y2=30;y3=30;y4=50;CLR=clrRoyalBlue;break;
      case 10: x1=150;x2=130;x3=110;x4=150;y1=30;y2=30;y3=30;y4=50;CLR=clrLimeGreen;break;
     }
  }
//==================================================================== вращение F-10
void f_Rotation_10()
  {
   if(y1==y2 && y3<y4) { ax1-=20;ay1+=20;ax3+=20;ay3-=20;ax4-=40; }
   else
   if(x1==x2 && y3<y4) { ax1+=20;ay1-=20;ax3-=20;ay3+=20;ay4-=40; }
   else
   if(y1==y2 && y3>y4) {ax1-=20;ay1+=20; ax3+=20;ay3-=20;ax4+=40; }
   else
   if(x1==x2 && y3==y4) {ax1+=20;ay1-=20;ax3-=20;ay3+=20;ay4+=40; }
  }
//==================================================================== вращение F-9
void f_Rotation_9()
  {
   if(y2==y3 && y3<y4) { ax1-=20;ay1+=20;ax3+=20;ay3-=20;ay4-=40; }
   else
   if(x2==x3 && x3>x4) { ay1-=20;ax1-=20;ax3+=20;ay3+=20;ax4+=40; }
   else
   if(y2==y3 && y3>y4) { ax1+=20;ay1-=20;ax3-=20;ay3+=20;ay4+=40; }
   else
   if(x2==x3 && x3<x4) { ax1+=20;ay1+=20;ax3-=20;ay3-=20;ax4-=40; }
  }
//==================================================================== вращение F-8
void f_Rotation_8()
  {
   if(x3!=x4) { ay3-=20;ax4-=40;ay4-=20; }
   else
     { ay3+=20;ax4+=40;ay4+=20;}
  }
//==================================================================== вращение F-7  
void f_Rotation_7()
  {
   if(x3!=x4) { ax3+=40;ay4-=40; }
   else
     { ax3-=40;ay4+=40; }
  }
//==================================================================== вращение F-6
void f_Rotation_6()
  {
   if(y1==y2 && y2==y3) { ax1-=20;ay1-=20; }
   else
   if(x1==x2 && x2==x4) { ax4+=20;ay4-=20; }
   else
   if(y2==y3 && y3==y4) { ay3+=20;ax3+=20; }
   else
   if(x1==x2 && x2==x3) { ax1+=20;ay1+=20;ax3-=20;ay3-=20;ax4-=20;ay4+=20; }
  }
//==================================================================== вращение F-5 
void f_Rotation_5()
  {
   if(x1!=x2) { ax1=ax3;ax2=ax3;ax4=ax3;ay1-=40;ay2-=20;ay4+=20; }
   else
   if(x1==x2 && x1<210) { ay1=ay3;ay2=ay3;ay4=ay3;ax1+=40;ax2+=20;ax4-=20; }
   else
   if(x1==x2 && x1==210) { ay1=ay3;ay2=ay3;ay4=ay3;ax1+=20;ax3-=20;ax4-=40; }
  }
//==================================================================== вращение F-3
void f_Rotation_3()
  {
   if(y3==y1 && x1>x3) { ay3=ay2; }
   else
   if(y3==y2 && x2>x3) { ax3=ax2+20; }
   else
   if(y3==y2 && x2<x3) { ay3=ay1; }
   else
   if(y3==y1 && x1<x3) { ax3=ax1-20; }
  }
//==================================================================== вращение F-2
void f_Rotation_2()
  {
   if(x1==x2) { ax1+=20; ay1+=20; }
   else
     { ax1-=20; ay1-=20; }
  }
//==================================================================== координаты
void f_Changing_XY(int number,int xx1,int xx2,int xx3,int xx4,int yy1,int yy2,int yy3,int yy4)
  {
   ObjectSetInteger(0,"figure"+(string)(number+1),OBJPROP_XDISTANCE,xx1);
   if(xx2>0) ObjectSetInteger(0,"figure"+(string)(number+2),OBJPROP_XDISTANCE,xx2);
   if(xx3>0) ObjectSetInteger(0,"figure"+(string)(number+3),OBJPROP_XDISTANCE,xx3);
   if(xx4>0)ObjectSetInteger(0,"figure"+(string)(number+4),OBJPROP_XDISTANCE,xx4);

   ObjectSetInteger(0,"figure"+(string)(number+1),OBJPROP_YDISTANCE,yy1);
   if(yy2>0) ObjectSetInteger(0,"figure"+(string)(number+2),OBJPROP_YDISTANCE,yy2);
   if(yy3>0) ObjectSetInteger(0,"figure"+(string)(number+3),OBJPROP_YDISTANCE,yy3);
   if(yy4>0)ObjectSetInteger(0,"figure"+(string)(number+4),OBJPROP_YDISTANCE,yy4);
  }
//==================================================================== создать фигуру
int f_Figure(int number,color CLR)
  {
   int numb=1;
   RectLabelCreate(0,"figure"+(string)(number+1),0,x1,y1,20,20,CLR,BORDER_RAISED,CORNER_RIGHT_UPPER,CLR,STYLE_SOLID,2);
   if(x2>0)
     {
      RectLabelCreate(0,"figure"+(string)(number+2),0,x2,y2,20,20,CLR,BORDER_RAISED,CORNER_RIGHT_UPPER,CLR,STYLE_SOLID,2);
      numb++;
     }
   if(x3>0)
     {
      RectLabelCreate(0,"figure"+(string)(number+3),0,x3,y3,20,20,CLR,BORDER_RAISED,CORNER_RIGHT_UPPER,CLR,STYLE_SOLID,2);
      numb++;
     }
   if(x4>0)
     {
      RectLabelCreate(0,"figure"+(string)(number+4),0,x4,y4,20,20,CLR,BORDER_RAISED,CORNER_RIGHT_UPPER,CLR,STYLE_SOLID,2);
      numb++;
     }
   return(numb);//кол-во объектов в фигуре
  }
//==================================================================== изменение координат по оси У
void f_Changing_coordinates_Y(int ydist)
  {
   y1+=ydist;
   if(y2>0) y2+=ydist;
   if(y3>0) y3+=ydist;
   if(y4>0) y4+=ydist;
  }
//==================================================================== изменение координат по оси Х
void f_Changing_coordinates_X(int xdist)
  {
   x1+=xdist;
   if(x2>0) x2+=xdist;
   if(x3>0) x3+=xdist;
   if(x4>0)x4+=xdist;
  }
//+-------------------------------------------------------------------+ 
//|Генератор случайных чисел.                                         |            
//+-------------------------------------------------------------------+
int f_GetRand(int min,int max)
  {
   int v=0;
   MathSrand(GetTickCount());
   while(true)
     {
      v=MathRand();
      if(v>=min && v<=max)
         break;
     }
   return(v);
  }
//+------------------------------------------------------------------+
//| Создает прямоугольную метку                                      |
//+------------------------------------------------------------------+
bool RectLabelCreate(const long             chart_ID=0,               // ID графика
                     const string           name="RectLabel",         // имя метки
                     const int              sub_window=0,             // номер подокна
                     const int              x=0,                      // координата по оси X
                     const int              y=0,                      // координата по оси Y
                     const int              width=50,                 // ширина
                     const int              height=18,                // высота
                     const color            back_clr=C'236,233,216',  // цвет фона
                     const ENUM_BORDER_TYPE border=BORDER_SUNKEN,     // тип границы
                     const ENUM_BASE_CORNER corner=CORNER_LEFT_UPPER, // угол графика для привязки
                     const color            clr=clrRed,               // цвет плоской границы (Flat)
                     const ENUM_LINE_STYLE  style=STYLE_SOLID,        // стиль плоской границы
                     const int              line_width=1,             // толщина плоской границы
                     const bool             back=false,               // на заднем плане
                     const bool             selection=false,          // выделить для перемещений
                     const bool             hidden=true,              // скрыт в списке объектов
                     const long             z_order=0)                // приоритет на нажатие мышью
  {
//--- сбросим значение ошибки
   ResetLastError();
//--- создадим прямоугольную метку
   if(!ObjectCreate(chart_ID,name,OBJ_RECTANGLE_LABEL,sub_window,0,0))
     {
      Print(__FUNCTION__,
            ": не удалось создать прямоугольную метку! Код ошибки = ",GetLastError());
      return(false);
     }
//--- установим координаты метки
   ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);
//--- установим размеры метки
   ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width);
   ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height);
//--- установим цвет фона
   ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr);
//--- установим тип границы
   ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_TYPE,border);
//--- установим угол графика, относительно которого будут определяться координаты точки
   ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner);
//--- установим цвет плоской рамки (в режиме Flat)
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- установим стиль линии плоской рамки
   ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- установим толщину плоской границы
   ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,line_width);
//--- отобразим на переднем (false) или заднем (true) плане
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- включим (true) или отключим (false) режим перемещения метки мышью
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- скроем (true) или отобразим (false) имя графического объекта в списке объектов
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- установим приоритет на получение события нажатия мыши на графике
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- успешное выполнение
   return(true);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+ 
//| Create a text label                                              | 
//+------------------------------------------------------------------+ 
bool LabelCreate(const long              chart_ID=0,               // chart's ID 
                 const string            name="Label",             // label name 
                 const int               sub_window=0,             // subwindow index 
                 const int               x=0,                      // X coordinate 
                 const int               y=0,                      // Y coordinate 
                 const ENUM_BASE_CORNER  corner=CORNER_LEFT_UPPER, // chart corner for anchoring 
                 const string            text="Label",             // text 
                 const string            font="Arial",             // font 
                 const int               font_size=10,             // font size 
                 const color             clr=clrRed,               // color 
                 const double            angle=0.0,                // text slope 
                 const ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER, // anchor type 
                 const bool              back=false,               // in the background 
                 const bool              selection=false,          // highlight to move 
                 const bool              hidden=true,              // hidden in the object list 
                 const long              z_order=0)                // priority for mouse click 
  {
//--- reset the error value 
   ResetLastError();
//--- create a text label 
   if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0))
     {
      Print(__FUNCTION__,
            ": failed to create text label! Error code = ",GetLastError());
      return(false);
     }
//--- set label coordinates 
   ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);
//--- set the chart's corner, relative to which point coordinates are defined 
   ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner);
//--- set the text 
   ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);
//--- set text font 
   ObjectSetString(chart_ID,name,OBJPROP_FONT,font);
//--- set font size 
   ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size);
//--- set the slope angle of the text 
   ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle);
//--- set anchor type 
   ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor);
//--- set color 
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- display in the foreground (false) or background (true) 
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the label by mouse 
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- hide (true) or display (false) graphical object name in the object list 
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart 
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution 
   return(true);
  }
//+------------------------------------------------------------------+
