#property version   "1.01"
//+------------------------------------------------------------------+
//| Minimum width and height of a table cell and the margin          |
//+------------------------------------------------------------------+
#define Table_Cell_Width_Minimum 10
#define Table_Cell_Height_Minimum 10
#define Table_Inner_Margin 10
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| Structure for storing cell properties                            |
//+------------------------------------------------------------------+
struct STRUCT_CELL
  {
   int                   s_width;               //cell width
   int                   s_height;              //cell height
   color                 s_border_color;        //cell border color
   bool                  s_custom_border_color; //has custom border color
   color                 s_back_color;          //cell background color
   bool                  s_custom_back_color;   //has custom background color
   color                 s_text_color;          //cell text color
   bool                  s_custom_text_color;   //has custom text color
   bool                  s_read_only;           //cell read-only property
   ENUM_ALIGN_MODE       s_alignment;           //cell alignment property
   string                s_description;         //cell description

   //+------------------------------------------------------------------+
   //| Constructor of the STRUCT_CELL structure                         |
   //+------------------------------------------------------------------+
                     STRUCT_CELL()
     {
      s_width               = 0;
      s_height              = 0;
      s_border_color        = clrNONE;
      s_custom_border_color = false;
      s_back_color          = clrNONE;
      s_custom_back_color   = false;
      s_text_color          = clrNONE;
      s_custom_text_color   = false;
      s_read_only           = true;
      s_alignment           = ALIGN_CENTER;
      s_description         = "";
     }
  };
//+------------------------------------------------------------------+
//| CTable class for creating and managing a table                   |
//+------------------------------------------------------------------+
class CTable
  {
private:
   CChartObjectEdit      m_cell_object[];                                           //array of cell objects
   string                m_prefix;                                                  //prefix used for all table objects

   bool                  m_created;                                                 //table creation status

   bool                  m_has_horizontal_header;                                   //horizontal header status
   bool                  m_has_vertical_header;                                     //vertical header status

   color                 m_color_background_border;                                 //background border color
   color                 m_color_background_back;                                   //background color
   color                 m_color_cell_border;                                       //cell border color
   color                 m_color_cell_back;                                         //cell background color
   color                 m_color_cell_text;                                         //cell text color
   color                 m_color_header_border;                                     //header border color
   color                 m_color_header_back;                                       //header background color
   color                 m_color_header_text;                                       //header text color

   int                   m_x_coordinate;                                            //table x-coordinate
   int                   m_y_coordinate;                                            //table y-coordinate
   int                   m_width;                                                   //table width
   int                   m_height;                                                  //table height
   int                   m_rows;                                                    //number of table rows
   int                   m_columns;                                                 //number of table columns
   int                   m_gap;                                                     //gap between cells

   CChartObjectRectLabel m_labels[];                                                //array of background labels
   STRUCT_CELL           m_cells[];                                                 //array storing cell properties

   int               CellXFind(int cell_index);                                     //find the x-coordinate of a cell
   int               CellYFind(int cell_index);                                     //find the y-coordinate of a cell
   void              Refresh(void);                                                 //refresh all table objects
   void              CopyCellData(STRUCT_CELL &src_cell, STRUCT_CELL &dst_cell);    //copy cell properties from source to destination
   void              ApplyCellStyle(int index);                                     //apply the appropriate style to a cell
public:
                     CTable(void);                                                  //constructor
                    ~CTable(void);                                                  //destructor

   bool              Create(void);                                                  //create table objects on the chart
   bool              Destroy(bool Empty_Data);                                      //delete table objects

   void              PrefixSet(string prefix);                                      //set the prefix for table objects
   string            PrefixGet(void);                                               //get the prefix of table objects

   void              CoordinatesSet(int x, int y);                                  //set the table coordinates
   void              WidthHeightSet(int width, int height);                         //set the table width and height
   int               CoordinateXGet(void);                                          //get the table x-coordinate
   int               CoordinateYGet(void);                                          //get the table y-coordinate
   int               WidthGet(void);                                                //get the table width
   int               HeightGet(void);                                               //get the table height

   void              HeaderSet(bool horizontal, bool vertical);                        //set horizontal and vertical header status

   void              BackgroundColorSet(color back, color border);                     //set background colors
   void              HeadersColorSet(color back, color border, color text);            //set header colors
   void              CellsColorSet(color back, color border, color text);              //set cell colors

   void              CellsInitialize(int rows, int columns);                           //initialize the table cells
   int               RowsGet(void);                                                    //get the number of table rows
   int               ColumnsGet(void);                                                 //get the number of table columns

   int               IndexToColumn(int index);                                         //return the column index of a cell
   int               IndexToRow(int index);                                            //return the row index of a cell
   int               ColumnRowToIndex(int column, int row);                            //return the cell index from column and row

   void              AddRow(int after);                                                //add a row after the specified row
   void              AddColumn(int after);                                             //add a column after the specified column
   void              DeleteRow(int row);                                               //delete the specified row
   void              DeleteColumn(int column);                                         //delete the specified column

   void              CellSetBorderColor(int cell, color border, bool custom);          //change the border color of a cell
   void              CellSetBackColor(int cell, color back, bool custom);              //change the background color of a cell
   void              CellSetTextColor(int cell, color text, bool custom);              //change the text color of a cell
   void              CellSetReadOnly(int cell, bool read_only);                        //change the read-only property of a cell
   void              CellSetAlignment(int cell, ENUM_ALIGN_MODE align);                //change the alignment of a cell
   void              CellSetDescription(int column_index, int row_index, string text); //set the description using column and row
   void              CellSetDescription(int index, string text);                       //set the description using the cell index

   color             CellGetBorderColor(int cell);                                     //Getting the border color of a cell
   color             CellGetBackColor(int cell);                                       //Getting the background color of a cell
   color             CellGetTextColor(int cell);                                       //Getting the text color of a cell
   bool              CellGetReadOnly(int cell);                                        //Getting the read-only mode of a cell
   ENUM_ALIGN_MODE   CellGetAlignment(int cell);                                       //Getting the text alignment of a cell
   string            CellGetDescription(int cell);                                     //Getting the text of a cell

  };
//+------------------------------------------------------------------+
//| Constructor of the CTable class.                                 |
//+------------------------------------------------------------------+
CTable::CTable(void)
  {
   m_prefix                  = "Table";
   m_created                 = false;
   m_has_horizontal_header   = false;
   m_has_vertical_header     = false;
   m_color_background_border = clrWhite;
   m_color_background_back   = clrBlack;
   m_color_cell_border       = clrWhite;
   m_color_cell_back         = clrWhite;
   m_color_cell_text         = clrBlack;
   m_color_header_border     = clrWhite;
   m_color_header_back       = clrLightBlue;
   m_color_header_text       = clrBlack;
   m_x_coordinate            = 5;
   m_y_coordinate            = 25;
   m_width                   = 200;
   m_height                  = 200;
   m_rows                    = 0;
   m_columns                 = 0;
   m_gap                     = 2;
  }
//+------------------------------------------------------------------+
//| Destructor of the CTable class                                   |
//+------------------------------------------------------------------+
CTable::~CTable(void)
  {
//--- Delete all table objects and stored cell data.
   Destroy(true);
  }
//+------------------------------------------------------------------+
//| Create the table objects on the chart                            |
//+------------------------------------------------------------------+
bool CTable::Create(void)
  {
//--- Check that at least one row has been initialized
   if(m_rows<=0)
     {
      Print("Set number of rows before creation of table");
      return(false);
     }
//--- Check that at least one column has been initialized
   if(m_columns<=0)
     {
      Print("Set number of columns before creation of table");
      return(false);
     }
//--- Prevent creating the table when it has already been created
   if(m_created)
     {
      Print("Object is created already");
      return(false);
     }
//--- Initialize the creation status and allocate the background labels
   bool Created = true;
   ArrayResize(m_labels, 2);
//--- Create the two background labels.
   if(!m_labels[0].Create(ChartID(), m_prefix+"-background-1", 0, m_x_coordinate, m_y_coordinate, m_width, m_height))
     {
      Created = false;
     }
   else
     {
      m_labels[0].Color(m_color_background_border);
      m_labels[0].BackColor(m_color_background_border);
      m_labels[0].BorderType(BORDER_FLAT);
     }
   if(!m_labels[1].Create(ChartID(), m_prefix+"-background-2", 0,
                          m_x_coordinate+(Table_Inner_Margin/2), m_y_coordinate+(Table_Inner_Margin/2),
                          m_width-Table_Inner_Margin, m_height-Table_Inner_Margin))
     {
      Created = false;
     }
   else
     {
      m_labels[1].Color(m_color_background_back);
      m_labels[1].BackColor(m_color_background_back);
      m_labels[1].BorderType(BORDER_FLAT);
     }
//--- Calculate the total number of cells and allocate the required arrays
   int TotalCells = m_columns * m_rows;
   if(ArraySize(m_cells)<TotalCells)
     {
      ArrayResize(m_cells, TotalCells);
      ArrayResize(m_cell_object, TotalCells);
     }
//--- Create each cell object and apply its stored properties
   for(int a=0; a<TotalCells; a++)
     {
      //--- Calculate the cell position and retrieve its stored dimensions
      int X      = CellXFind(a);
      int Y      = CellYFind(a);
      int W      = m_cells[a].s_width;
      int H      = m_cells[a].s_height;
      //--- Create the cell object on the chart.
      if(!m_cell_object[a].Create(ChartID(), m_prefix+"-cell-"+IntegerToString(a), 0, X, Y, W, H))
        {
         Created = false;
         break;
        }
      else
        {
         //--- Apply the stored cell properties to the created object
         m_cell_object[a].BackColor(m_cells[a].s_back_color);
         m_cell_object[a].BorderColor(m_cells[a].s_border_color);
         m_cell_object[a].Color(m_cells[a].s_text_color);
         m_cell_object[a].ReadOnly(m_cells[a].s_read_only);
         m_cell_object[a].TextAlign(m_cells[a].s_alignment);
         m_cell_object[a].Description(m_cells[a].s_description);
        }
     }
//--- Mark the table as created when all objects were created successfully
   if(!Created)
     {
      //--- Remove all objects created before the failure
      m_created = true; //we set it to true so that Destroy deletes all objects from the chart
      Destroy(false);
      m_created = false;
      return(false);
     }
   else
     {
      m_created = true;
      return(true);
     }
  }
//+------------------------------------------------------------------+
//| Delete all table objects and optionally clear the stored data    |
//+------------------------------------------------------------------+
bool CTable::Destroy(bool Empty_Data)
  {
//--- If the table has not been created, clear the stored data when requested
   if(!m_created)
     {
      if(Empty_Data)
        {
         ArrayFree(m_labels);
         ArrayFree(m_cells);
         ArrayFree(m_cell_object);
        }
      return(true);
     }
//--- Track whether all table objects are deleted successfully
   bool Deleted = true;
//--- Delete all background objects one by one
   for(int a=0; a<ArraySize(m_labels); a++)
     {
      if(!m_labels[a].Delete())
         Deleted = false;
     }
   if(Deleted && Empty_Data)
     {
      ArrayFree(m_labels);
     }
//--- Delete all cell objects one by one
   for(int a=0; a<ArraySize(m_cells); a++)
     {
      if(!m_cell_object[a].Delete())
         Deleted = false;
     }
   if(Deleted && Empty_Data)
     {
      ArrayFree(m_cells);
      ArrayFree(m_cell_object);
     }
//--- Reset the creation status when all objects are deleted successfully
   if(Deleted)
     {
      m_created = false;
      return(true);
     }
   else
     {
      return(false);
     }
  }
//+------------------------------------------------------------------+
//| Set the prefix used for table objects                            |
//+------------------------------------------------------------------+
void CTable::PrefixSet(string prefix)
  {
//--- Use the default prefix when an empty string is provided
   if(prefix=="")
     {
      prefix = "Table";
     }
//--- checking for inconsistent character from - to _
   StringReplace(prefix,"-","_");
   m_prefix = prefix;
//--- Rename existing table objects when the table has already been created
   if(m_created)
     {
      //--- Update the names of the background objects
      for(int a=0; a<ArraySize(m_labels); a++)
        {
         string SplitedName[];
         StringSplit(m_labels[a].Name(), '-', SplitedName);
         //--- Rebuild the object name when it contains a prefix and suffix
         if(ArraySize(SplitedName)>1)
           {
            string Name = m_prefix;
            //--- Append the existing name components to the new prefix
            for(int b=1; b<ArraySize(SplitedName); b++)
              {
               Name = Name + "-" + SplitedName[b];
              }
            m_labels[a].Name(Name);
           }
        }
      //--- Update the names of the cell objects
      for(int a=0; a<ArraySize(m_cells); a++)
        {
         string SplitedName[];
         StringSplit(m_cell_object[a].Name(), '-', SplitedName);
         //--- Rebuild the object name when it contains a prefix and suffix
         if(ArraySize(SplitedName)>1)
           {
            string Name = m_prefix;
            //--- Append the existing name components to the new prefix
            for(int b=1; b<ArraySize(SplitedName); b++)
              {
               Name = Name + "-" + SplitedName[b];
              }
            m_cell_object[a].Name(Name);
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Get the prefix used for table objects                            |
//+------------------------------------------------------------------+
string CTable::PrefixGet(void)
  {
   return(m_prefix);
  }
//+------------------------------------------------------------------+
//| Set the table coordinates                                        |
//+------------------------------------------------------------------+
void CTable::CoordinatesSet(int x, int y)
  {
//--- Set the x-coordinate to zero when it is less than zero
   if(x<0)
     {
      x = 0;
     }
//--- Adjust the x-coordinate when the table exceeds the chart width
   else
      if(m_width!=0)
        {
         if(x+m_width>(int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS, 0))
           {
            x = MathMax((int)ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS, 0) - m_width, 0);
           }
        }
//--- Set the y-coordinate to zero when it is less than zero
   if(y<0)
     {
      y = 0;
     }
//--- Adjust the y-coordinate when the table exceeds the chart height
   else
      if(m_height!=0)
        {
         if(y+m_height>(int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS, 0))
           {
            y = MathMax((int)ChartGetInteger(ChartID(), CHART_HEIGHT_IN_PIXELS, 0) - m_height, 0);
           }
        }
//--- Store the previous table coordinates and calculate the differences
   int PreviousX  = m_x_coordinate;
   int PreviousY  = m_y_coordinate;
   m_x_coordinate = x;
   m_y_coordinate = y;
   int DiffX      = m_x_coordinate-PreviousX;
   int DiffY      = m_y_coordinate-PreviousY;
//--- Update the object positions when the table has already been created
   if(m_created)
     {
      //--- Move all background labels by the calculated coordinate differences
      for(int a=0; a<ArraySize(m_labels); a++)
        {
         m_labels[a].X_Distance(m_labels[a].X_Distance()+DiffX);
         m_labels[a].Y_Distance(m_labels[a].Y_Distance()+DiffY);
        }
      //--- Move all cell objects by the calculated coordinate differences
      for(int a=0; a<ArraySize(m_cells); a++)
        {
         m_cell_object[a].X_Distance(m_cell_object[a].X_Distance()+DiffX);
         m_cell_object[a].Y_Distance(m_cell_object[a].Y_Distance()+DiffY);
        }
     }
  }
//+------------------------------------------------------------------+
//| Set the table width and height                                   |
//+------------------------------------------------------------------+
void CTable::WidthHeightSet(int w, int h)
  {
//--- Calculate the minimum allowed width and height of the table
   int MinimumWidth = Table_Inner_Margin*2 + m_columns * (Table_Cell_Width_Minimum + m_gap);
   if(w<MinimumWidth)
      w = MinimumWidth;
   int MinimumHeight = Table_Inner_Margin*2 + m_rows * (Table_Cell_Height_Minimum + m_gap);
   if(h<MinimumHeight)
      h = MinimumHeight;
//--- Store the new table width and height
   m_width  = w;
   m_height = h;
//--- we need to check the boundaries again to keep the table within the chart boundaries
   int width = (int) ChartGetInteger(ChartID(),CHART_WIDTH_IN_PIXELS,0);
   int height = (int) ChartGetInteger(ChartID(),CHART_HEIGHT_IN_PIXELS,0);
//--- the table can only stay on the page if its width is smaller than the chart's width
   if(m_x_coordinate+m_width>(int)width && m_width<width)
      m_x_coordinate = width-m_width;
//--- the table can only stay on the page if its height is smaller than the chart's height
   if(m_y_coordinate+m_height>(int)height && m_height<height)
      m_y_coordinate = height-m_height;
//--- Update the cell sizes when the table has already been created
   if(m_created)
     {
      //---
      if(m_columns==0 || m_rows==0)
         return;
      //--- Calculate the width and height of each cell
      int CellWidth  = (m_width-Table_Inner_Margin*2) / m_columns;
      int CellHeight = (m_height-Table_Inner_Margin*2) / m_rows;
      //--- Update the width and height of all cells
      for(int a=0; a<ArraySize(m_cells); a++)
        {
         m_cells[a].s_width  = MathMax(CellWidth - m_gap, Table_Cell_Width_Minimum);
         m_cells[a].s_height = MathMax(CellHeight - m_gap, Table_Cell_Height_Minimum);
        }
      Refresh(); //Refresh all table objects
     }
  }
//+------------------------------------------------------------------+
//| Get the table x-coordinate                                       |
//+------------------------------------------------------------------+
int CTable::CoordinateXGet(void)
  {
   return(m_x_coordinate);
  }
//+------------------------------------------------------------------+
//| Get the table x-coordinate                                       |
//+------------------------------------------------------------------+
int CTable::CoordinateYGet(void)
  {
   return(m_y_coordinate);
  }
//+------------------------------------------------------------------+
//| Get the table width                                              |
//+------------------------------------------------------------------+
int CTable::WidthGet(void)
  {
   return(m_width);
  }
//+------------------------------------------------------------------+
//| Get the table height                                             |
//+------------------------------------------------------------------+
int CTable::HeightGet(void)
  {
   return(m_height);
  }
//+------------------------------------------------------------------+
//| Set the horizontal and vertical header status                    |
//+------------------------------------------------------------------+
void CTable::HeaderSet(bool horizontal, bool vertical)
  {
//--- Return if rows or columns are not initialized
   if(m_rows<=0 || m_columns<=0)
      return;
//--- Define variables
   bool PreviousRowHeader = m_has_horizontal_header; //Store the previous horizontal header status
   m_has_horizontal_header = horizontal;             //Set the new horizontal header status
//--- Update the first row when the table is already created
   if(m_created)
     {
      //--- Remove the horizontal header style when it is disabled
      if(PreviousRowHeader && !m_has_horizontal_header)
        {
         for(int a=0; a<=m_columns-1; a++)
            ApplyCellStyle(a);
        }
      //--- Apply the horizontal header style when it is enabled
      if(!PreviousRowHeader && m_has_horizontal_header)
        {
         //--- Apply the style to all cells in the first row
         for(int a=0; a<=m_columns-1; a++)
            ApplyCellStyle(a);
        }
     }
   else
     {
      //--- Apply the horizontal header style to the cell data
      if(m_has_horizontal_header)
        {
         //--- Apply the style to all cells in the first row
         for(int a=0; a<=m_columns-1; a++)
            ApplyCellStyle(a);
        }
     }
   bool PreviousColumnHeader = m_has_vertical_header; //Store the previous vertical header status
   m_has_vertical_header = vertical;                  //Set the new vertical header status
//--- Update the first column when the table is already created
   if(m_created)
     {
      //--- Remove the vertical header style when it is disabled
      if(PreviousColumnHeader && !m_has_vertical_header)
        {
         //--- Apply the regular cell style to all cells in the first column
         for(int a=0; a<=(m_columns*m_rows)-1; a+=m_columns)
            ApplyCellStyle(a);
        }
      //--- Apply the vertical header style when it is enabled
      if(!PreviousColumnHeader && m_has_vertical_header)
        {
         //--- Apply the style to all cells in the first column
         for(int a=0; a<=(m_columns*m_rows)-1; a+=m_columns)
            ApplyCellStyle(a);
        }
     }
   else
     {
      //--- Apply the vertical header style to the cell data
      if(m_has_vertical_header)
        {
         //--- Apply the style to all cells in the first column
         for(int a=0; a<=(m_columns*m_rows)-1; a+=m_columns)
            ApplyCellStyle(a);
        }
     }
  }
//+------------------------------------------------------------------+
//| Set the background and border colors                             |
//+------------------------------------------------------------------+
void CTable::BackgroundColorSet(color back, color border)
  {
//--- Replace invalid background and border colors with default colors
   if(back==clrNONE)
      back = clrBlack;
   if(border==clrNONE)
      border = clrWhite;
//--- Store the new background and border colors
   m_color_background_back   = back;
   m_color_background_border = border;
//--- Update the background objects when the table is already created
   if(m_created)
     {
      //--- Update the colors of the two background objects
      for(int a=0; a<ArraySize(m_labels); a++)
        {
         //--- Set the border color for the outer background
         if(a==0)
           {
            m_labels[a].Color(m_color_background_border);
            m_labels[a].BackColor(m_color_background_border);
           }
         //--- Set the background color for the inner background
         if(a==1)
           {
            m_labels[a].Color(m_color_background_back);
            m_labels[a].BackColor(m_color_background_back);
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Set the header colors                                            |
//+------------------------------------------------------------------+
void CTable::HeadersColorSet(color back, color border, color text)
  {
//--- Replace invalid colors with the default header colors
   if(back==clrNONE)
      back = clrLightBlue;
   if(border==clrNONE)
      border = clrLightBlue;
   if(text==clrNONE)
      text = clrBlack;
//--- Store the new header colors
   m_color_header_back   = back;
   m_color_header_border = border;
   m_color_header_text   = text;
//--- Update the header cells when the table is already created
   if(m_created)
     {
      if(m_has_horizontal_header)
        {
         //--- Apply the header style to all cells in the first row
         for(int a=0; a<=m_columns-1; a++)
            ApplyCellStyle(a);
        }
      if(m_has_vertical_header)
        {
         //--- Apply the header style to all cells in the first column
         for(int a=0; a<=(m_columns*m_rows)-1; a+=m_columns)
            ApplyCellStyle(a);
        }
     }
  }
//+------------------------------------------------------------------+
//| Set the cell colors while preserving the header colors           |
//+------------------------------------------------------------------+
void CTable::CellsColorSet(color back, color border, color text)
  {
//--- Replace invalid colors with the default cell colors
   if(back==clrNONE)
      back = clrWhite;
   if(border==clrNONE)
      border = clrWhite;
   if(text==clrNONE)
      text = clrBlack;
//--- Store the new cell colors
   m_color_cell_back   = back;
   m_color_cell_border = border;
   m_color_cell_text   = text;
//--- Update the cell colors when the table is already created
   if(m_created)
     {
      //--- Apply the new colors to all non-header cells
      for(int a=0; a<ArraySize(m_cells); a++)
        {
         //--- Skip cells that belong to the horizontal header
         if(m_has_horizontal_header && a<m_columns)
            continue;
         //--- Skip cells that belong to the vertical header
         if(m_has_vertical_header && a%m_columns==0)
            continue;
         //--- Apply the cell style to the current cell
         ApplyCellStyle(a);
        }
     }
  }
//+------------------------------------------------------------------+
//| Initialize the table cells and add new cells when required       |
//+------------------------------------------------------------------+
void CTable::CellsInitialize(int rows, int columns)
  {
//--- Prevent initialization when the table is already created
   if(m_created)
     {
      Print("Destroy the table before initializing cells");
      return;
     }
//--- Check whether the specified row and column counts are valid
   if(rows<1 || columns<1)
     {
      Print("You entered invalid row or column number");
      return;
     }
//--- Store the table dimensions and calculate the cell counts
   int TotalCells      = rows*columns;                 //Calculate the new number of cells
   m_rows    = rows;                                   //Update the number of rows
   m_columns = columns;                                //Update the number of columns
//--- Resize the cell arrays to accommodate the new cells
   ArrayResize(m_cells, TotalCells);
   ArrayResize(m_cell_object, TotalCells);
//--- Calculate the dimensions of the new cells
   int CellWidth  = (m_width-Table_Inner_Margin*2)/columns;
   int CellHeight = (m_height-Table_Inner_Margin*2)/rows;
//--- Initialize the newly added cells with the default properties
   for(int a=0; a<ArraySize(m_cells); a++)
     {
      m_cells[a].s_width               = MathMax(CellWidth - m_gap, Table_Cell_Width_Minimum);   //Set the cell width
      m_cells[a].s_height              = MathMax(CellHeight - m_gap, Table_Cell_Height_Minimum); //Set the cell height
      m_cells[a].s_border_color        = m_color_cell_border;                  //Set the border color
      m_cells[a].s_back_color          = m_color_cell_back;                    //Set the background color
      m_cells[a].s_text_color          = m_color_cell_text;                    //Set the text color
      m_cells[a].s_custom_border_color = false;                                //Set the custom border color mode
      m_cells[a].s_custom_back_color   = false;                                //Set the custom back color mode
      m_cells[a].s_custom_text_color   = false;                                //Set the custom text color mode
      m_cells[a].s_read_only           = true;                                 //Set the read-only mode
      m_cells[a].s_alignment           = ALIGN_CENTER;                         //Set the alignment mode
      m_cells[a].s_description         = "";                                   //Clear the description
     }
  }
//+------------------------------------------------------------------+
//| Get the number of table rows                                     |
//+------------------------------------------------------------------+
int CTable::RowsGet(void)
  {
   return(m_rows);
  }
//+------------------------------------------------------------------+
//| Get the number of table columns                                  |
//+------------------------------------------------------------------+
int CTable::ColumnsGet(void)
  {
   return(m_columns);
  }
//+------------------------------------------------------------------+
//| Returns the column index of a cell based on its array index      |
//+------------------------------------------------------------------+
int CTable::IndexToColumn(int index)
  {
//--- checking index, columns and rows for a positive number
   if(index < 0 || m_columns <= 0 || m_rows <= 0)
      return(-1);
//--- index should be between 0 and (m_rows*m_columns)-1
   if(index >= m_rows * m_columns)
      return(-1);
//--- return the column
   return(index % m_columns);
  }
//+------------------------------------------------------------------+
//| Return the row index of a cell based on its array index          |
//+------------------------------------------------------------------+
int CTable::IndexToRow(int index)
  {
   if(index < 0 || m_columns <= 0 || m_rows <= 0)
      return(-1);
   if(index >= m_rows * m_columns)
      return(-1);
   return(index / m_columns);
  }
//+------------------------------------------------------------------+
//| Return the cell index based on its column and row                |
//+------------------------------------------------------------------+
int CTable::ColumnRowToIndex(int column, int row)
  {
   if(column < 0 || row < 0)
      return(-1);
   if(column >= m_columns || row >= m_rows)
      return(-1);
   return(row * m_columns + column);
  }
//+------------------------------------------------------------------+
//| Add a row after the specified row                                |
//+------------------------------------------------------------------+
void CTable::AddRow(int after)
  {
//--- Check that the specified row index is not negative
   if(after<0)
     {
      Print("You should enter a non-negative row index for adding a row");
      return;
     }
//--- Check that the table contains at least one row
   if(m_rows<=0)
     {
      Print("There is no row to add after");
      return;
     }
//--- Limit the row index to the last available row
   if(after>m_rows-1)
      after = m_rows-1;
//--- Define variables for the new table dimensions
   int PreviousRows  = m_rows;
   int NewRow        = after+1;
   int TotalCells    = (m_rows+1)*m_columns;
//--- Create a temporary array for the new cell data
   STRUCT_CELL NewCells[];
   ArrayResize(NewCells, TotalCells);
   int SourceIndex = 0;
//--- Copy the existing cells and initialize the new row
   for(int a=0; a<TotalCells; a++)
     {
      int NewRowStart = NewRow*m_columns;
      int NewRowEnd   = NewRowStart+m_columns-1;
      //--- Initialize the cells that belong to the new row
      if(a>=NewRowStart && a<=NewRowEnd)
        {
         //--- Apply the vertical header style to the first cell of the new row
         if(a==NewRowStart && m_has_vertical_header)
           {
            NewCells[a].s_width               = 0;
            NewCells[a].s_height              = 0;
            NewCells[a].s_border_color        = m_color_header_border;
            NewCells[a].s_back_color          = m_color_header_back;
            NewCells[a].s_text_color          = m_color_header_text;
            NewCells[a].s_custom_back_color   = false;
            NewCells[a].s_custom_border_color = false;
            NewCells[a].s_custom_text_color   = false;
            NewCells[a].s_read_only           = true;
            NewCells[a].s_alignment           = ALIGN_CENTER;
            NewCells[a].s_description         = "";
           }
         else
           {
            NewCells[a].s_width        = 0;
            NewCells[a].s_height       = 0;
            NewCells[a].s_border_color = m_color_cell_border;
            NewCells[a].s_back_color   = m_color_cell_back;
            NewCells[a].s_text_color   = m_color_cell_text;
            NewCells[a].s_custom_back_color   = false;
            NewCells[a].s_custom_border_color = false;
            NewCells[a].s_custom_text_color   = false;
            NewCells[a].s_read_only    = true;
            NewCells[a].s_alignment    = ALIGN_CENTER;
            NewCells[a].s_description  = "";
           }
        }
      else
        {
         CopyCellData(m_cells[SourceIndex], NewCells[a]);
         SourceIndex++;
        }
     }
//--- Destroy the existing table objects before resizing the arrays
   if(!Destroy(false))
     {
      Print("Failed to destroy existing table objects");
      return;
     }
   ArrayResize(m_cells, TotalCells);
   ArrayResize(m_cell_object, TotalCells);
//--- Copy the cell data back to the main array
   for(int a=0; a<TotalCells; a++)
      CopyCellData(NewCells[a], m_cells[a]);
//--- Update the number of rows
   m_rows = PreviousRows+1;
//--- Calculate the new cell dimensions
   int CellWidth  = (m_width-Table_Inner_Margin*2)/m_columns;
   int CellHeight = (m_height-Table_Inner_Margin*2)/m_rows;
//--- Update the dimensions of all cells
   for(int a=0; a<TotalCells; a++)
     {
      m_cells[a].s_height = CellHeight-m_gap;
      m_cells[a].s_width  = CellWidth-m_gap;
     }
//--- Recreate the table with the updated cell data
   Create();
  }
//+------------------------------------------------------------------+
//| Add a column after the specified column                          |
//+------------------------------------------------------------------+
void CTable::AddColumn(int after)
  {
//--- Check that the specified column index is not negative
   if(after<0)
     {
      Print("You should enter a non-negative column index");
      return;
     }
//--- Check that the table contains at least one column
   if(m_columns<=0)
     {
      Print("There is no column to add after");
      return;
     }
//--- Limit the column index to the last available column
   if(after>m_columns-1)
      after = m_columns-1;
//--- Define variables for the new table dimensions
   int PreviousColumns = m_columns;
   int PreviousTotal   = m_rows*m_columns;
   int NewColumn       = after+1;
   int TotalCells      = m_rows*(m_columns+1);
//--- Create a temporary array for the new cell data
   STRUCT_CELL NewCells[];
   ArrayResize(NewCells, TotalCells);
//--- Initialize the indexes used to copy the existing cell data
   int skip    = after+1;
   int counter = 0;
//--- Copy the existing cells and leave space for the new column
   for(int a=0; a<ArraySize(NewCells); a++)
     {
      if(a==skip)
        {
         skip += m_columns+1;
         continue;
        }
      CopyCellData(m_cells[counter], NewCells[a]);
      counter++;
     }
//--- Destroy the existing table objects before resizing the arrays
   if(!Destroy(false))
     {
      Print("Failed to destroy existing table objects");
      return;
     }
   ArrayResize(m_cells, TotalCells);
   ArrayResize(m_cell_object, TotalCells);
//--- Initialize the index of the new column
   skip = after+1;
//--- Copy the existing cell data and initialize the new cells
   for(int a=0; a<TotalCells; a++)
     {
      if(a==skip)
        {
         skip += m_columns+1;
         m_cells[a].s_width               = 0;
         m_cells[a].s_height              = 0;
         m_cells[a].s_border_color        = m_color_cell_border;
         m_cells[a].s_back_color          = m_color_cell_back;
         m_cells[a].s_text_color          = m_color_cell_text;
         m_cells[a].s_custom_back_color   = false;
         m_cells[a].s_custom_border_color = false;
         m_cells[a].s_custom_text_color   = false;
         m_cells[a].s_read_only           = true;
         m_cells[a].s_alignment           = ALIGN_CENTER;
         m_cells[a].s_description         = "";
         continue;
        }
      CopyCellData(NewCells[a], m_cells[a]);
     }
//--- Update the number of columns
   m_columns = PreviousColumns+1;
//--- Calculate the new cell dimensions
   int CellWidth  = (m_width-Table_Inner_Margin*2)/m_columns;
   int CellHeight = (m_height-Table_Inner_Margin*2)/m_rows;
//--- New column status
   if(m_has_horizontal_header)
      ApplyCellStyle(NewColumn);
//--- Update the dimensions of all cells
   for(int a=0; a<TotalCells; a++)
     {
      m_cells[a].s_height = CellHeight-m_gap;
      m_cells[a].s_width  = CellWidth-m_gap;
     }
//--- Recreate the table with the updated cell data
   Create();
  }
//+------------------------------------------------------------------+
//| Delete the specified row                                         |
//+------------------------------------------------------------------+
void CTable::DeleteRow(int row)
  {
//--- Check that the specified row index is valid and is not a header row
   if(row<0 || (row==0 && m_has_horizontal_header))
     {
      Print("You should enter a positive row index");
      return;
     }
//--- Check that the table contains at least two rows
   if(m_rows<=1)
     {
      Print("There is no row to remove");
      return;
     }
//--- Limit the row index to the last available row
   if(row>m_rows-1)
      row = m_rows-1;
//--- Define variables for the new table dimensions
   int PreviousRows  = m_rows;
   int PreviousTotal = m_rows*m_columns;
   int TotalCells    = (m_rows-1)*m_columns;
//--- Create a temporary array for the remaining cell data
   STRUCT_CELL NewCells[];
   ArrayResize(NewCells, TotalCells);
   int counter = 0;
//--- Copy all cells except those in the specified row
   for(int a=0; a<PreviousTotal; a++)
     {
      //--- Skip the cells that belong to the specified row
      if(a>=row*m_columns && a<=(row+1)*m_columns-1)
         continue;
      //--- Copy the cell data to the temporary array
      CopyCellData(m_cells[a], NewCells[counter]);
      counter++;
     }
//--- Destroy the existing table objects before resizing the arrays
   if(!Destroy(false))
     {
      Print("Failed to destroy existing table objects");
      return;
     }
   ArrayResize(m_cells, TotalCells);
   ArrayResize(m_cell_object, TotalCells);
//--- Copy the remaining cell data back to the main array
//--- Restore the cell data after removing the specified row
   for(int a=0; a<TotalCells; a++)
      CopyCellData(NewCells[a], m_cells[a]);
//--- Calculate the new cell dimensions
   int CellWidth  = (m_width-Table_Inner_Margin*2)/m_columns;
   int CellHeight = (m_height-Table_Inner_Margin*2)/(m_rows-1);
//--- Update the dimensions of all cells
//--- Apply the new width and height to every cell
   for(int a=0; a<TotalCells; a++)
     {
      m_cells[a].s_height = CellHeight-m_gap;
      m_cells[a].s_width  = CellWidth-m_gap;
     }
//--- Update the number of rows and recreate the table
   m_rows = PreviousRows-1;
   Create();
  }
//+------------------------------------------------------------------+
//| Delete the specified column                                      |
//+------------------------------------------------------------------+
void CTable::DeleteColumn(int column)
  {
//--- Check that the table has at least two columns
   if(m_columns<=1)
     {
      Print("The table must have at least one column");
      return;
     }
//--- Check that the specified column index is not negative
   if(column<0)
     {
      Print("You should enter a non-negative column index");
      return;
     }
//--- Prevent deleting the vertical header column
   if(column==0 && m_has_vertical_header)
     {
      Print("The vertical header column cannot be deleted");
      return;
     }
//--- Limit the column index to the last available column
   if(column>m_columns-1)
      column = m_columns-1;
//--- Define variables for copying the existing cell data
   int PreviousColumns = m_columns;
   int PreviousTotal   = m_rows*m_columns;
   int TotalCells      = m_rows*(m_columns-1);
//--- Create a temporary array for the remaining cells
   STRUCT_CELL NewCells[];
   ArrayResize(NewCells, TotalCells);
//--- Copy all cells except those in the specified column
   int skip    = column;
   int counter = 0;
   for(int a=0; a<PreviousTotal; a++)
     {
      //--- Skip the cell that belongs to the specified column
      if(a==skip)
        {
         skip += m_columns;
         continue;
        }
      //--- Copy the cell data to the temporary array
      CopyCellData(m_cells[a], NewCells[counter]);
      counter++;
     }
//--- Destroy the existing table objects and resize the arrays
   if(!Destroy(false))
     {
      Print("Failed to destroy existing table objects");
      return;
     }
   ArrayResize(m_cells, TotalCells);
   ArrayResize(m_cell_object, TotalCells);
//--- Copy the remaining cell data back to the main array
   for(int a=0; a<TotalCells; a++)
      CopyCellData(NewCells[a], m_cells[a]);
//--- Calculate the new cell dimensions
   int CellWidth  = (m_width-Table_Inner_Margin*2)/(m_columns-1);
   int CellHeight = (m_height-Table_Inner_Margin*2)/m_rows;
//--- Update the dimensions of all cells
   for(int a=0; a<TotalCells; a++)
     {
      m_cells[a].s_height = CellHeight-m_gap;
      m_cells[a].s_width  = CellWidth-m_gap;
     }
//--- Update the number of columns and recreate the table
   m_columns = PreviousColumns-1;
   Create();
  }
//+------------------------------------------------------------------+
//| Set the border color of a cell                                   |
//+------------------------------------------------------------------+
void CTable::CellSetBorderColor(int cell, color border, bool custom)
  {
//--- Checking for invalid index
   if(cell<0 || cell>=ArraySize(m_cells))
      return;
//--- changing the data
   m_cells[cell].s_border_color        = border; //resetting the border color
   m_cells[cell].s_custom_border_color = custom; //resetting the custom border color mode
//--- change the border color property of the cell if the objects are created
   if(m_created)
     {
      m_cell_object[cell].BorderColor(m_cells[cell].s_border_color); //resetting the border color
     }
  }
//+------------------------------------------------------------------+
//| Set the background color of a cell                               |
//+------------------------------------------------------------------+
void CTable::CellSetBackColor(int cell, color back, bool custom)
  {
//--- Checking for invalid index
   if(cell<0 || cell>=ArraySize(m_cells))
      return;
//--- changing the data
   m_cells[cell].s_back_color        = back;   //resetting the back color
   m_cells[cell].s_custom_back_color = custom; //resetting the custom back color mode
//--- change the back color property of the cell if the objects are created
   if(m_created)
     {
      m_cell_object[cell].BackColor(m_cells[cell].s_back_color); //resetting the back color
     }
  }
//+------------------------------------------------------------------+
//| Set the background color of a cell                               |
//+------------------------------------------------------------------+
void CTable::CellSetTextColor(int cell, color text, bool custom)
  {
//--- Checking for invalid index
   if(cell<0 || cell>=ArraySize(m_cells))
      return;
//--- changing the data
   m_cells[cell].s_text_color        = text;   //resetting the text color
   m_cells[cell].s_custom_text_color = custom; //resetting the custom text color mode
//--- change the text color property of the cell if the objects are created
   if(m_created)
     {
      m_cell_object[cell].Color(m_cells[cell].s_text_color); //resetting the text color
     }
  }
//+------------------------------------------------------------------+
//| Set the read-only property of a cell                             |
//+------------------------------------------------------------------+
void CTable::CellSetReadOnly(int cell, bool read_only)
  {
//--- Check whether the cell index is valid
   if(cell<0 || cell>=ArraySize(m_cells))
      return;
//--- Store the read-only mode in the cell data
   m_cells[cell].s_read_only = read_only;
//--- Update the read-only mode of the cell object when the table is created
   if(m_created)
     {
      m_cell_object[cell].ReadOnly(m_cells[cell].s_read_only);
     }
  }
//+------------------------------------------------------------------+
//| Set the alignment of a cell                                      |
//+------------------------------------------------------------------+
void CTable::CellSetAlignment(int cell, ENUM_ALIGN_MODE align)
  {
//--- Check whether the cell index is valid
   if(cell<0 || cell>=ArraySize(m_cells))
      return;
//--- Store the alignment mode in the cell data
   m_cells[cell].s_alignment = align;
//--- Update the alignment of the cell object when the table is created
   if(m_created)
     {
      m_cell_object[cell].TextAlign(m_cells[cell].s_alignment);
     }
  }
//+------------------------------------------------------------------+
//| Find the X-coordinate of a cell                                  |
//+------------------------------------------------------------------+
int CTable::CellXFind(int cell_index)
  {
//--- Define the indentation variable
   int indentation = m_gap/2;
//--- Calculate the distance from the left side of the table
   for(int a=cell_index-1; a>=0; a--)
     {
      if(a%m_columns==m_columns-1)
        break;
      //--- adding to the indentation
      indentation += m_cells[a].s_width + m_gap;
     }
//--- Return the X-coordinate of the cell
   return(m_x_coordinate + Table_Inner_Margin + indentation);
  }
//+------------------------------------------------------------------+
//| Find the Y-coordinate of a cell                                  |
//+------------------------------------------------------------------+
int CTable::CellYFind(int cell_index)
  {
//--- Define the indentation variable
   int indentation = m_gap/2;
//--- Calculate the distance from the top of the table
   for(int column=IndexToColumn(cell_index); column<ArraySize(m_cells); column+=m_columns)
     {
      if(column>=cell_index)
        break;
      indentation += m_cells[column].s_height + m_gap;
     }
   return(m_y_coordinate + Table_Inner_Margin + indentation);
  }
//+------------------------------------------------------------------+
//| Set the description of a cell using its index                    |
//+------------------------------------------------------------------+
void CTable::CellSetDescription(int index, string text)
  {
//--- Check whether the cell index is valid
   if(index < 0 || index >= ArraySize(m_cells))
      return;
//--- Store the description in the cell data
   m_cells[index].s_description = text;
//--- Update the description of the cell object when the table is created
   if(m_created)
      m_cell_object[index].Description(text);
  }
//+------------------------------------------------------------------+
//| Set the cell description using its column and row                |
//+------------------------------------------------------------------+
void CTable::CellSetDescription(int column_index, int row_index, string text)
  {
//--- Convert the column and row to a cell index
   int index = ColumnRowToIndex(column_index, row_index);
//--- Check whether the cell index is valid
   if(index<0 || index>=ArraySize(m_cells))
      return;
//--- Store the description in the cell data
   m_cells[index].s_description = text;
//--- Update the description of the cell object when the table is created
   if(m_created)
      m_cell_object[index].Description(text);
  }
//+------------------------------------------------------------------+
//| Refresh all table objects                                        |
//+------------------------------------------------------------------+
void CTable::Refresh(void)
  {
//--- return if the object is not created
   if(!m_created)
      return;
//--- checking the background data array
   if(ArraySize(m_labels)<2)
      return;
//--- Check and update the background label coordinates
   if(m_labels[0].X_Distance()!=m_x_coordinate || m_labels[1].X_Distance()!=m_x_coordinate+Table_Inner_Margin/2)
     {
      m_labels[0].X_Distance(m_x_coordinate);
      m_labels[1].X_Distance(m_x_coordinate+Table_Inner_Margin/2);
     }
   if(m_labels[0].Y_Distance()!=m_y_coordinate || m_labels[1].Y_Distance()!=m_y_coordinate+Table_Inner_Margin/2)
     {
      m_labels[0].Y_Distance(m_y_coordinate);
      m_labels[1].Y_Distance(m_y_coordinate+Table_Inner_Margin/2);
     }
   if(m_labels[0].X_Size()!=m_width || m_labels[1].X_Size()!=m_width-Table_Inner_Margin)
     {
      m_labels[0].X_Size(m_width);
      m_labels[1].X_Size(m_width-Table_Inner_Margin);
     }
   if(m_labels[0].Y_Size()!=m_height || m_labels[1].Y_Size()!=m_height-Table_Inner_Margin)
     {
      m_labels[0].Y_Size(m_height);
      m_labels[1].Y_Size(m_height-Table_Inner_Margin);
     }
//--- Check and refresh all cell objects
   int total = MathMin(ArraySize(m_cells), ArraySize(m_cell_object));
   for(int a=0; a<total; a++)
     {
      //--- Check and update the cell alignment
      if(m_cells[a].s_alignment!=m_cell_object[a].TextAlign())
         m_cell_object[a].TextAlign(m_cells[a].s_alignment);
      //--- Check and update the cell background color
      if(m_cells[a].s_back_color!=m_cell_object[a].BackColor())
         m_cell_object[a].BackColor(m_cells[a].s_back_color);
      //--- Check and update the cell border color
      if(m_cells[a].s_border_color!=m_cell_object[a].BorderColor())
         m_cell_object[a].BorderColor(m_cells[a].s_border_color);
      //--- Check and update the cell description
      if(m_cells[a].s_description!=m_cell_object[a].Description())
         m_cell_object[a].Description(m_cells[a].s_description);
      //--- Check and update the cell height
      if(m_cells[a].s_height!=m_cell_object[a].Y_Size())
         m_cell_object[a].Y_Size(m_cells[a].s_height);
      //--- Check and update the cell read-only mode
      if(m_cells[a].s_read_only!=m_cell_object[a].ReadOnly())
         m_cell_object[a].ReadOnly(m_cells[a].s_read_only);
      //--- Check and update the cell text color
      if(m_cells[a].s_text_color!=m_cell_object[a].Color())
         m_cell_object[a].Color(m_cells[a].s_text_color);
      //--- Check and update the cell width
      if(m_cells[a].s_width!=m_cell_object[a].X_Size())
         m_cell_object[a].X_Size(m_cells[a].s_width);
      //--- Calculate the coordinates of the current cell
      int X      = CellXFind(a);
      int Y      = CellYFind(a);
      //--- Update the cell position when the coordinates have changed
      if(m_cell_object[a].X_Distance()!=X)
         m_cell_object[a].X_Distance(X);
      if(m_cell_object[a].Y_Distance()!=Y)
         m_cell_object[a].Y_Distance(Y);
     }
   ChartRedraw();
  }
//+------------------------------------------------------------------+
//| Copy the properties of a cell                                    |
//+------------------------------------------------------------------+
void CTable::CopyCellData(STRUCT_CELL &src, STRUCT_CELL &dst)
  {
   dst = src;
  }
//+------------------------------------------------------------------+
//| Apply the appropriate style to a cell                            |
//+------------------------------------------------------------------+
void CTable::ApplyCellStyle(int index)
  {
//--- check the validity of the index
   if(index<0 || index>=ArraySize(m_cells))
      return;
//--- Find the row and column of the cell and initialize the header status
   int  column    = IndexToColumn(index);
   int  row       = IndexToRow(index);
   bool is_header = false;
//--- Check whether the cell belongs to a header
   if(m_has_horizontal_header && row == 0)
      is_header = true;
   if(m_has_vertical_header && column == 0)
      is_header = true;
//--- Apply the header style when the cell belongs to a header and normal cell
   if(is_header)
     {
      if(!m_cells[index].s_custom_back_color)
         m_cells[index].s_back_color   = m_color_header_back;
      if(!m_cells[index].s_custom_border_color)
         m_cells[index].s_border_color = m_color_header_border;
      if(!m_cells[index].s_custom_text_color)
         m_cells[index].s_text_color   = m_color_header_text;
      if(m_created)
        {
         m_cell_object[index].BackColor(m_cells[index].s_back_color);
         m_cell_object[index].BorderColor(m_cells[index].s_border_color);
         m_cell_object[index].Color(m_cells[index].s_text_color);
         m_cell_object[index].ReadOnly(m_cells[index].s_read_only);
        }
     }
   else
     {
      if(!m_cells[index].s_custom_back_color)
         m_cells[index].s_back_color   = m_color_cell_back;
      if(!m_cells[index].s_custom_border_color)
         m_cells[index].s_border_color = m_color_cell_border;
      if(!m_cells[index].s_custom_text_color)
         m_cells[index].s_text_color   = m_color_cell_text;
      if(m_created)
        {
         m_cell_object[index].BackColor(m_cells[index].s_back_color);
         m_cell_object[index].BorderColor(m_cells[index].s_border_color);
         m_cell_object[index].Color(m_cells[index].s_text_color);
        }
     }
  }
//+------------------------------------------------------------------+
//| Getting the border color of a cell                               |
//+------------------------------------------------------------------+
color CTable::CellGetBorderColor(int cell)
  {
//---Checking if the size of cells array is greater than the index for valid number
   if(ArraySize(m_cells)>cell && cell>=0)
     {
      return(m_cells[cell].s_border_color);
     }
   else
     {
      return(clrNONE);
     }
  }
//+------------------------------------------------------------------+
//| Getting the background color of a cell                           |
//+------------------------------------------------------------------+
color CTable::CellGetBackColor(int cell)
  {
//---Checking if the size of cells array is greater than the index for valid number
   if(ArraySize(m_cells)>cell && cell>=0)
     {
      return(m_cells[cell].s_back_color);
     }
   else
     {
      return(clrNONE);
     }
  }
//+------------------------------------------------------------------+
//| Getting the text color of a cell                                 |
//+------------------------------------------------------------------+
color CTable::CellGetTextColor(int cell)
  {
//---Checking if the size of cells array is greater than the index for valid number
   if(ArraySize(m_cells)>cell && cell>=0)
     {
      return(m_cells[cell].s_text_color);
     }
   else
     {
      return(clrNONE);
     }
  }
//+------------------------------------------------------------------+
//| Getting the read-only mode of a cell                             |
//+------------------------------------------------------------------+
bool CTable::CellGetReadOnly(int cell)
  {
//---Checking if the size of cells array is greater than the index for valid number
   if(ArraySize(m_cells)>cell && cell>=0)
     {
      return(m_cells[cell].s_read_only);
     }
   else
     {
      return(false);
     }
  }
//+------------------------------------------------------------------+
//| Getting the alignment mode of a cell                             |
//+------------------------------------------------------------------+
ENUM_ALIGN_MODE CTable::CellGetAlignment(int cell)
  {
//---Checking if the size of cells array is greater than the index for valid number
   if(ArraySize(m_cells)>cell && cell>=0)
     {
      return(m_cells[cell].s_alignment);
     }
   else
     {
      return(ALIGN_CENTER);
     }
  }
//+------------------------------------------------------------------+
//| Getting the description mode of a cell                           |
//+------------------------------------------------------------------+
string CTable::CellGetDescription(int cell)
  {
//---Checking if the size of cells array is greater than the index for valid number
   if(ArraySize(m_cells)>cell && cell>=0)
     {
      return(m_cells[cell].s_description);
     }
   else
     {
      return("");
     }
  }
//+------------------------------------------------------------------+
